From 452bbe41cfb3139ea62580e9930525d9ea664ac9 Mon Sep 17 00:00:00 2001 From: YamaArashi Date: Wed, 2 Nov 2016 14:06:41 -0700 Subject: port siirtc from pokeruby --- src/siirtc.c | 432 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 432 insertions(+) create mode 100644 src/siirtc.c (limited to 'src') diff --git a/src/siirtc.c b/src/siirtc.c new file mode 100644 index 000000000..965a068f1 --- /dev/null +++ b/src/siirtc.c @@ -0,0 +1,432 @@ +// Ruby/Sapphire/Emerald cartridges contain a Seiko Instruments Inc. (SII) +// S-3511A real-time clock (RTC). This library ("SIIRTC_V001") is for +// communicating with the RTC. + +#include "gba/gba.h" +#include "siirtc.h" + +#define STATUS_INTFE 0x02 // frequency interrupt enable +#define STATUS_INTME 0x08 // per-minute interrupt enable +#define STATUS_INTAE 0x20 // alarm interrupt enable +#define STATUS_24HOUR 0x40 // 0: 12-hour mode, 1: 24-hour mode +#define STATUS_POWER 0x80 // power on or power failure occurred + +#define TEST_MODE 0x80 // flag in the "second" byte + +#define ALARM_AM 0x00 +#define ALARM_PM 0x80 + +#define OFFSET_YEAR offsetof(struct SiiRtcInfo, year) +#define OFFSET_MONTH offsetof(struct SiiRtcInfo, month) +#define OFFSET_DAY offsetof(struct SiiRtcInfo, day) +#define OFFSET_DAY_OF_WEEK offsetof(struct SiiRtcInfo, dayOfWeek) +#define OFFSET_HOUR offsetof(struct SiiRtcInfo, hour) +#define OFFSET_MINUTE offsetof(struct SiiRtcInfo, minute) +#define OFFSET_SECOND offsetof(struct SiiRtcInfo, second) +#define OFFSET_STATUS offsetof(struct SiiRtcInfo, status) +#define OFFSET_ALARM_HOUR offsetof(struct SiiRtcInfo, alarmHour) +#define OFFSET_ALARM_MINUTE offsetof(struct SiiRtcInfo, alarmMinute) + +#define INFO_BUF(info, index) (*((u8 *)(info) + (index))) + +#define DATETIME_BUF(info, index) INFO_BUF(info, OFFSET_YEAR + index) +#define DATETIME_BUF_LEN (OFFSET_SECOND - OFFSET_YEAR + 1) + +#define TIME_BUF(info, index) INFO_BUF(info, OFFSET_HOUR + index) +#define TIME_BUF_LEN (OFFSET_SECOND - OFFSET_HOUR + 1) + +#define WR 0 // command for writing data +#define RD 1 // command for reading data + +#define CMD(n) (0x60 | (n << 1)) + +#define CMD_RESET CMD(0) +#define CMD_STATUS CMD(1) +#define CMD_DATETIME CMD(2) +#define CMD_TIME CMD(3) +#define CMD_ALARM CMD(4) + +#define GPIO_PORT_DATA (*(vu16 *)0x80000C4) +#define GPIO_PORT_DIRECTION (*(vu16 *)0x80000C6) +#define GPIO_PORT_READ_ENABLE (*(vu16 *)0x80000C8) + +extern vu16 GPIOPortDirection; + +static u16 sDummy; // unused variable +static bool8 sLocked; + +static int WriteCommand(u8 value); +static int WriteData(u8 value); +static u8 ReadData(); +static void EnableGpioPortRead(); +static void DisableGpioPortRead(); + +static const char AgbLibRtcVersion[] = "SIIRTC_V001"; + +void SiiRtcUnprotect() +{ + EnableGpioPortRead(); + sLocked = FALSE; +} + +void SiiRtcProtect() +{ + DisableGpioPortRead(); + sLocked = TRUE; +} + +u8 SiiRtcProbe() +{ + u8 errorCode; + struct SiiRtcInfo rtc; + + if (!SiiRtcGetStatus(&rtc)) + return 0; + + errorCode = 0; + + if ((rtc.status & (SIIRTCINFO_POWER | SIIRTCINFO_24HOUR)) == SIIRTCINFO_POWER + || (rtc.status & (SIIRTCINFO_POWER | SIIRTCINFO_24HOUR)) == 0) + { + // The RTC is in 12-hour mode. Reset it and switch to 24-hour mode. + + // Note that the conditions are redundant and equivalent to simply + // "(rtc.status & SIIRTCINFO_24HOUR) == 0". It's possible that this + // was also intended to handle resetting the clock after power failure + // but a mistake was made. + + if (!SiiRtcReset()) + return 0; + + errorCode++; + } + + SiiRtcGetTime(&rtc); + + if (rtc.second & TEST_MODE) + { + // The RTC is in test mode. Reset it to leave test mode. + + if (!SiiRtcReset()) + return (errorCode << 4) & 0xF0; + + errorCode++; + } + + return (errorCode << 4) | 1; +} + +bool8 SiiRtcReset() +{ + u8 result; + struct SiiRtcInfo rtc; + + if (sLocked == TRUE) + return FALSE; + + sLocked = TRUE; + + GPIO_PORT_DATA = 1; + GPIO_PORT_DATA = 5; + + GPIO_PORT_DIRECTION = 7; + + WriteCommand(CMD_RESET | WR); + + GPIO_PORT_DATA = 1; + GPIO_PORT_DATA = 1; + + sLocked = FALSE; + + rtc.status = SIIRTCINFO_24HOUR; + + result = SiiRtcSetStatus(&rtc); + + return result; +} + +bool8 SiiRtcGetStatus(struct SiiRtcInfo *rtc) +{ + u8 statusData; + + if (sLocked == TRUE) + return FALSE; + + sLocked = TRUE; + + GPIO_PORT_DATA = 1; + GPIO_PORT_DATA = 5; + + GPIO_PORT_DIRECTION = 7; + + WriteCommand(CMD_STATUS | RD); + + GPIO_PORT_DIRECTION = 5; + + statusData = ReadData(); + + rtc->status = (statusData & (STATUS_POWER | STATUS_24HOUR)) + | ((statusData & STATUS_INTAE) >> 3) + | ((statusData & STATUS_INTME) >> 2) + | ((statusData & STATUS_INTFE) >> 1); + + GPIO_PORT_DATA = 1; + GPIO_PORT_DATA = 1; + + sLocked = FALSE; + + return TRUE; +} + +bool8 SiiRtcSetStatus(struct SiiRtcInfo *rtc) +{ + u8 statusData; + + if (sLocked == TRUE) + return FALSE; + + sLocked = TRUE; + + GPIO_PORT_DATA = 1; + GPIO_PORT_DATA = 5; + + statusData = STATUS_24HOUR + | ((rtc->status & SIIRTCINFO_INTAE) << 3) + | ((rtc->status & SIIRTCINFO_INTME) << 2) + | ((rtc->status & SIIRTCINFO_INTFE) << 1); + + GPIO_PORT_DIRECTION = 7; + + WriteCommand(CMD_STATUS | WR); + + WriteData(statusData); + + GPIO_PORT_DATA = 1; + GPIO_PORT_DATA = 1; + + sLocked = FALSE; + + return TRUE; +} + +bool8 SiiRtcGetDateTime(struct SiiRtcInfo *rtc) +{ + u8 i; + + if (sLocked == TRUE) + return FALSE; + + sLocked = TRUE; + + GPIO_PORT_DATA = 1; + GPIO_PORT_DATA = 5; + + GPIO_PORT_DIRECTION = 7; + + WriteCommand(CMD_DATETIME | RD); + + GPIO_PORT_DIRECTION = 5; + + for (i = 0; i < DATETIME_BUF_LEN; i++) + DATETIME_BUF(rtc, i) = ReadData(); + + INFO_BUF(rtc, OFFSET_HOUR) &= 0x7F; + + GPIO_PORT_DATA = 1; + GPIO_PORT_DATA = 1; + + sLocked = FALSE; + + return TRUE; +} + +bool8 SiiRtcSetDateTime(struct SiiRtcInfo *rtc) +{ + u8 i; + + if (sLocked == TRUE) + return FALSE; + + sLocked = TRUE; + + GPIO_PORT_DATA = 1; + GPIO_PORT_DATA = 5; + + GPIO_PORT_DIRECTION = 7; + + WriteCommand(CMD_DATETIME | WR); + + for (i = 0; i < DATETIME_BUF_LEN; i++) + WriteData(DATETIME_BUF(rtc, i)); + + GPIO_PORT_DATA = 1; + GPIO_PORT_DATA = 1; + + sLocked = FALSE; + + return TRUE; +} + +bool8 SiiRtcGetTime(struct SiiRtcInfo *rtc) +{ + u8 i; + + if (sLocked == TRUE) + return FALSE; + + sLocked = TRUE; + + GPIO_PORT_DATA = 1; + GPIO_PORT_DATA = 5; + + GPIO_PORT_DIRECTION = 7; + + WriteCommand(CMD_TIME | RD); + + GPIO_PORT_DIRECTION = 5; + + for (i = 0; i < TIME_BUF_LEN; i++) + TIME_BUF(rtc, i) = ReadData(); + + INFO_BUF(rtc, OFFSET_HOUR) &= 0x7F; + + GPIO_PORT_DATA = 1; + GPIO_PORT_DATA = 1; + + sLocked = FALSE; + + return TRUE; +} + +bool8 SiiRtcSetTime(struct SiiRtcInfo *rtc) +{ + u8 i; + + if (sLocked == TRUE) + return FALSE; + + sLocked = TRUE; + + GPIO_PORT_DATA = 1; + GPIO_PORT_DATA = 5; + + GPIO_PORT_DIRECTION = 7; + + WriteCommand(CMD_TIME | WR); + + for (i = 0; i < TIME_BUF_LEN; i++) + WriteData(TIME_BUF(rtc, i)); + + GPIO_PORT_DATA = 1; + GPIO_PORT_DATA = 1; + + sLocked = FALSE; + + return TRUE; +} + +bool8 SiiRtcSetAlarm(struct SiiRtcInfo *rtc) +{ + u8 i; + u8 alarmData[2]; + + if (sLocked == TRUE) + return FALSE; + + sLocked = TRUE; + + // Decode BCD. + alarmData[0] = (rtc->alarmHour & 0xF) + 10 * ((rtc->alarmHour >> 4) & 0xF); + + // The AM/PM flag must be set correctly even in 24-hour mode. + + if (alarmData[0] < 12) + alarmData[0] = rtc->alarmHour | ALARM_AM; + else + alarmData[0] = rtc->alarmHour | ALARM_PM; + + alarmData[1] = rtc->alarmMinute; + + GPIO_PORT_DATA = 1; + GPIO_PORT_DATA = 5; + + GPIOPortDirection = 7; // Why is this the only instance that uses a symbol? + + WriteCommand(CMD_ALARM | WR); + + for (i = 0; i < 2; i++) + WriteData(alarmData[i]); + + GPIO_PORT_DATA = 1; + GPIO_PORT_DATA = 1; + + sLocked = FALSE; + + return TRUE; +} + +static int WriteCommand(u8 value) +{ + u8 i; + u8 temp; + + for (i = 0; i < 8; i++) + { + temp = ((value >> (7 - i)) & 1); + GPIO_PORT_DATA = (temp << 1) | 4; + GPIO_PORT_DATA = (temp << 1) | 4; + GPIO_PORT_DATA = (temp << 1) | 4; + GPIO_PORT_DATA = (temp << 1) | 5; + } + + // control reaches end of non-void function +} + +static int WriteData(u8 value) +{ + u8 i; + u8 temp; + + for (i = 0; i < 8; i++) + { + temp = ((value >> i) & 1); + GPIO_PORT_DATA = (temp << 1) | 4; + GPIO_PORT_DATA = (temp << 1) | 4; + GPIO_PORT_DATA = (temp << 1) | 4; + GPIO_PORT_DATA = (temp << 1) | 5; + } + + // control reaches end of non-void function +} + +static u8 ReadData() +{ + u8 i; + u8 temp; + u8 value; + + for (i = 0; i < 8; i++) + { + GPIO_PORT_DATA = 4; + GPIO_PORT_DATA = 4; + GPIO_PORT_DATA = 4; + GPIO_PORT_DATA = 4; + GPIO_PORT_DATA = 4; + GPIO_PORT_DATA = 5; + + temp = ((GPIO_PORT_DATA & 2) >> 1); + value = (value >> 1) | (temp << 7); // UB: accessing uninitialized var + } + + return value; +} + +static void EnableGpioPortRead() +{ + GPIO_PORT_READ_ENABLE = 1; +} + +static void DisableGpioPortRead() +{ + GPIO_PORT_READ_ENABLE = 0; +} -- cgit v1.2.3 From ebf4c5ca76fc2c05443361a7ca633a897a4a76d7 Mon Sep 17 00:00:00 2001 From: YamaArashi Date: Fri, 13 Jan 2017 17:40:03 -0800 Subject: decompile multiboot --- src/multiboot.c | 470 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 470 insertions(+) create mode 100644 src/multiboot.c (limited to 'src') diff --git a/src/multiboot.c b/src/multiboot.c new file mode 100644 index 000000000..80291ff46 --- /dev/null +++ b/src/multiboot.c @@ -0,0 +1,470 @@ +#include "gba/gba.h" +#include "multiboot.h" + +static u16 MultiBoot_required_data[MULTIBOOT_NCHILD]; + +static int MultiBootSend(struct MultiBootParam *mp, u16 data); +static int MultiBootHandShake(struct MultiBootParam *mp); +static void MultiBootWaitCycles(u32 cycles); +static void MultiBootWaitSendDone(void); + +void MultiBootInit(struct MultiBootParam *mp) +{ + mp->client_bit = 0; + mp->probe_count = 0; + mp->response_bit = 0; + + mp->check_wait = MULTIBOOT_CONNECTION_CHECK_WAIT; + mp->sendflag = 0; + + mp->handshake_timeout = 0; + + REG_RCNT = 0; + REG_SIOCNT = SIO_MULTI_MODE | SIO_115200_BPS; + REG_SIODATA8 = 0; +} + +int MultiBootMain(struct MultiBootParam *mp) +{ + int i; + int j; + int k; + + if (MultiBootCheckComplete(mp)) + { + return 0; + } + + if (mp->check_wait > MULTIBOOT_CONNECTION_CHECK_WAIT) + { + mp->check_wait--; + return 0; + } + +output_burst: + if (mp->sendflag) + { + mp->sendflag = 0; + + i = REG_SIOCNT & (SIO_MULTI_BUSY | SIO_ERROR | SIO_ID | SIO_MULTI_SD | SIO_MULTI_SI); + if (i != SIO_MULTI_SD) + { + MultiBootInit(mp); + return i ^ SIO_MULTI_SD; + } + } + + if (mp->probe_count >= 0xe0) + { + i = MultiBootHandShake(mp); + if (i) + { + return i; + } + + if (mp->server_type == MULTIBOOT_SERVER_TYPE_QUICK + && mp->probe_count > 0xe1 + && MultiBootCheckComplete(mp) == 0) + { + MultiBootWaitSendDone(); + goto output_burst; + } + + if (MultiBootCheckComplete(mp) == 0) + { + if (mp->handshake_timeout == 0) + { + MultiBootInit(mp); + return MULTIBOOT_ERROR_HANDSHAKE_FAILURE; + } + mp->handshake_timeout--; + } + + return 0; + } + + switch (mp->probe_count) + { + case 0: + k = 0x0e; + for (i = MULTIBOOT_NCHILD; i != 0; i--) + { + if (*(vu16 *)(REG_ADDR_SIOMULTI0 + i * 2) != 0xffff) + { + break; + } + k >>= 1; + } + + k &= 0x0e; + mp->response_bit = k; + + for (i = MULTIBOOT_NCHILD; i != 0; i--) + { + j = *(vu16 *)(REG_ADDR_SIOMULTI0 + i * 2); + if (mp->client_bit & (1 << i)) + { + if (j != ((MULTIBOOT_CLIENT_INFO << 8) | (1 << i))) + { + k = 0; + break; + } + } + } + + mp->client_bit &= k; + + if (k == 0) + { + mp->check_wait = MULTIBOOT_CONNECTION_CHECK_WAIT; + } + + if (mp->check_wait) + { + mp->check_wait--; + } + else + { + if (mp->response_bit != mp->client_bit) + { + MultiBootStartProbe(mp); + goto case_1; + } + } + + output_master_info: + return MultiBootSend(mp, (MULTIBOOT_MASTER_INFO << 8) | mp->client_bit); + + case_1: + case 1: + mp->probe_target_bit = 0; + for (i = MULTIBOOT_NCHILD; i != 0; i--) + { + j = *(vu16 *)(REG_ADDR_SIOMULTI0 + i * 2); + if ((j >> 8) == MULTIBOOT_CLIENT_INFO) + { + MultiBoot_required_data[i - 1] = j; + j &= 0xff; + if (j == (1 << i)) + { + mp->probe_target_bit |= j; + } + } + } + + if (mp->response_bit != mp->probe_target_bit) + { + goto output_master_info; + } + + mp->probe_count = 2; + return MultiBootSend(mp, (MULTIBOOT_MASTER_START_PROBE << 8) | mp->probe_target_bit); + + case 2: + for (i = MULTIBOOT_NCHILD; i != 0; i--) + { + if (mp->probe_target_bit & (1 << i)) + { + j = *(vu16 *)(REG_ADDR_SIOMULTI0 + i * 2); + if (j != MultiBoot_required_data[i - 1]) + { + mp->probe_target_bit ^= 1 << i; + } + } + } + goto output_header; + + case 0xd0: + k = 1; + for (i = MULTIBOOT_NCHILD; i != 0; i--) + { + j = *(vu16 *)(REG_ADDR_SIOMULTI0 + i * 2); + mp->client_data[i - 1] = j; + if (mp->probe_target_bit & (1 << i)) + { + if ((j >> 8) != MULTIBOOT_CLIENT_INFO + && (j >> 8) != MULTIBOOT_CLIENT_DLREADY) + { + MultiBootInit(mp); + return MULTIBOOT_ERROR_NO_DLREADY; + } + if (j == MultiBoot_required_data[i - 1]) + { + k = 0; + } + } + } + + if (k == 0) + { + return MultiBootSend(mp, (MULTIBOOT_MASTER_REQUEST_DLREADY << 8) | mp->palette_data); + } + + mp->probe_count = 0xd1; + + k = 0x11; + for (i = MULTIBOOT_NCHILD; i != 0; i--) + { + k += mp->client_data[i - 1]; + } + mp->handshake_data = k; + return MultiBootSend(mp, (MULTIBOOT_MASTER_START_DL << 8) | (k & 0xff)); + + case 0xd1: + for (i = MULTIBOOT_NCHILD; i != 0; i--) + { + j = *(vu16 *)(REG_ADDR_SIOMULTI0 + i * 2); + if (mp->probe_target_bit & (1 << i)) + { + if ((j >> 8) != MULTIBOOT_CLIENT_DLREADY) + { + MultiBootInit(mp); + return MULTIBOOT_ERROR_NO_DLREADY; + } + } + } + + i = MultiBoot(mp); + + if (i == 0) + { + mp->probe_count = 0xe0; + mp->handshake_timeout = MULTIBOOT_HANDSHAKE_TIMEOUT; + return 0; + } + MultiBootInit(mp); + mp->check_wait = MULTIBOOT_CONNECTION_CHECK_WAIT * 2; + return MULTIBOOT_ERROR_BOOT_FAILURE; + + default: + for (i = MULTIBOOT_NCHILD; i != 0; i--) + { + if (mp->probe_target_bit & (1 << i)) + { + j = *(vu16 *)(REG_ADDR_SIOMULTI0 + i * 2); + if ((j >> 8) != (MULTIBOOT_MASTER_START_PROBE + 1 - (mp->probe_count >> 1)) + || ((j & 0xff) != (1 << i))) + { + mp->probe_target_bit ^= 1 << i; + } + } + } + + if (mp->probe_count == 0xc4) + { + mp->client_bit = mp->probe_target_bit & 0x0e; + mp->probe_count = 0; + goto output_master_info; + } + + output_header: + if (mp->probe_target_bit == 0) + { + MultiBootInit(mp); + return MULTIBOOT_ERROR_NO_PROBE_TARGET; + } + + mp->probe_count += 2; + if (mp->probe_count == 0xc4) + { + goto output_master_info; + } + i = MultiBootSend(mp, + (mp->masterp[mp->probe_count - 4 + 1] << 8) + | mp->masterp[mp->probe_count - 4]); + + if (i) + { + return i; + } + if (mp->server_type == MULTIBOOT_SERVER_TYPE_QUICK) + { + MultiBootWaitSendDone(); + goto output_burst; + } + return 0; + } +} + +static int MultiBootSend(struct MultiBootParam *mp, u16 data) +{ + int i; + + i = REG_SIOCNT & (SIO_MULTI_BUSY | SIO_MULTI_SD | SIO_MULTI_SI); + if (i != SIO_MULTI_SD) + { + MultiBootInit(mp); + return i ^ SIO_MULTI_SD; + } + + REG_SIODATA8 = data; + REG_SIOCNT = SIO_MULTI_MODE | SIO_START | SIO_115200_BPS; + + mp->sendflag = 1; + return 0; +} + +void MultiBootStartProbe(struct MultiBootParam *mp) +{ + if (mp->probe_count != 0) + { + MultiBootInit(mp); + return; + } + mp->check_wait = 0; + mp->client_bit = 0; + mp->probe_count = 1; +} + +void MultiBootStartMaster(struct MultiBootParam *mp, u8 *srcp, int length, u8 palette_color, s8 palette_speed) +{ + int i = 0; + + if (mp->probe_count != 0 + || mp->client_bit == 0 + || mp->check_wait != 0) + { + MultiBootInit(mp); + return; + } + + mp->boot_srcp = srcp; + length = (length + 15) & ~15; + if (length < MULTIBOOT_SEND_SIZE_MIN || length > MULTIBOOT_SEND_SIZE_MAX) + { + MultiBootInit(mp); + return; + } + + mp->boot_endp = srcp + length; + + switch (palette_speed) + { + case -4: + case -3: + case -2: + case -1: + i = (palette_color << 3) | (3 - palette_speed); + break; + case 0: + i = 0x38 | palette_color; + break; + case 1: + case 2: + case 3: + case 4: + i = (palette_color << 3) | (palette_speed - 1); + break; + } + + mp->palette_data = ((i & 0x3f) << 1) | 0x81; + mp->probe_count = 0xd0; +} + +int MultiBootCheckComplete(struct MultiBootParam *mp) +{ + if (mp->probe_count == 0xe9) + { + return 1; + } + + return 0; +} + +static int MultiBootHandShake(struct MultiBootParam *mp) +{ + int i, j; + +#define send_data (mp->system_work[0]) +#define must_data (mp->system_work[1]) + + switch (mp->probe_count) + { + case_0xe0: + case 0xe0: + mp->probe_count = 0xe1; + must_data = 0x0000; + send_data = 0x100000; + return MultiBootSend(mp, 0x0000); + + default: + for (i = MULTIBOOT_NCHILD; i != 0; i--) + { + j = *(vu16 *)(REG_ADDR_SIOMULTI0 + i * 2); + if ((mp->client_bit & (1 << i)) + && j != must_data) + { + goto case_0xe0; + } + } + mp->probe_count++; + must_data = send_data & 0xffff; + if (send_data == 0x0000) + { + must_data = mp->masterp[0xac] | (mp->masterp[0xad] << 8); + send_data = must_data << 5; + } + send_data >>= 5; + output_common: + return MultiBootSend(mp, send_data); + + case 0xe7: + case 0xe8: + for (i = MULTIBOOT_NCHILD; i != 0; i--) + { + j = *(vu16 *)(REG_ADDR_SIOMULTI0 + i * 2); + if ((mp->client_bit & (1 << i)) && j != must_data) + { + MultiBootInit(mp); + return MULTIBOOT_ERROR_HANDSHAKE_FAILURE; + } + } + + mp->probe_count++; + if (mp->probe_count == 0xe9) + { + return 0; + } + + send_data = mp->masterp[0xae] | (mp->masterp[0xaf] << 8); + must_data = send_data; + goto output_common; + } + +#undef send_data +#undef must_data +} + +static void MultiBootWaitCycles(u32 cycles) +{ + asm("mov r2, pc"); + asm("lsr r2, #24"); + asm("mov r1, #12"); + asm("cmp r2, #0x02"); + asm("beq MultiBootWaitCyclesLoop"); + + asm("mov r1, #13"); + asm("cmp r2, #0x08"); + asm("beq MultiBootWaitCyclesLoop"); + + asm("mov r1, #4"); + + asm("MultiBootWaitCyclesLoop:"); + asm("sub r0, r1"); + asm("bgt MultiBootWaitCyclesLoop"); +} + +static void MultiBootWaitSendDone(void) +{ + int i; + + for (i = 0; i < 31069; i++) + { + if ((REG_SIOCNT & SIO_START) == 0) + { + break; + } + } + + MultiBootWaitCycles(600); +} -- cgit v1.2.3 From 12681346688870e71b1a33dae7e52f9e1302080f Mon Sep 17 00:00:00 2001 From: YamaArashi Date: Sat, 14 Jan 2017 11:53:20 -0800 Subject: decompile string_util --- src/string_util.c | 544 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 544 insertions(+) create mode 100644 src/string_util.c (limited to 'src') diff --git a/src/string_util.c b/src/string_util.c new file mode 100644 index 000000000..35b48ceae --- /dev/null +++ b/src/string_util.c @@ -0,0 +1,544 @@ +#include "global.h" +#include "string_util.h" +#include "text.h" + +#define MAX_PLACEHOLDER_ID 0xD + +extern const u8 sDigits[]; +extern const s32 sPowersOfTen[]; +extern const u8 sSetBrailleFont[]; +extern const u8 sGotoLine2[]; + +typedef u8 *(*ExpandPlaceholderFunc)(void); + +extern const ExpandPlaceholderFunc sExpandPlaceholderFuncs[]; + +extern u8 gUnknownStringVar[]; +extern u8 gStringVar1[]; +extern u8 gStringVar2[]; +extern u8 gStringVar3[]; +extern u8 gStringVar4[]; + +extern u8 gExpandedPlaceholder_Empty[]; +extern u8 gExpandedPlaceholder_Kun[]; +extern u8 gExpandedPlaceholder_Chan[]; +extern u8 gExpandedPlaceholder_Sapphire[]; +extern u8 gExpandedPlaceholder_Ruby[]; +extern u8 gExpandedPlaceholder_Emerald[]; +extern u8 gExpandedPlaceholder_Aqua[]; +extern u8 gExpandedPlaceholder_Magma[]; +extern u8 gExpandedPlaceholder_Archie[]; +extern u8 gExpandedPlaceholder_Maxie[]; +extern u8 gExpandedPlaceholder_Kyogre[]; +extern u8 gExpandedPlaceholder_Groudon[]; +extern u8 gExpandedPlaceholder_Brendan[]; +extern u8 gExpandedPlaceholder_May[]; + +u8 *StringCopy10(u8 *dest, const u8 *src) +{ + u8 i; + u32 limit = 10; + + for (i = 0; i < limit; i++) + { + dest[i] = src[i]; + + if (dest[i] == EOS) + return &dest[i]; + } + + dest[i] = EOS; + return &dest[i]; +} + +u8 *StringGetEnd10(u8 *str) +{ + u8 i; + u32 limit = 10; + + for (i = 0; i < limit; i++) + if (str[i] == EOS) + return &str[i]; + + str[i] = EOS; + return &str[i]; +} + +u8 *StringCopy7(u8 *dest, const u8 *src) +{ + s32 i; + s32 limit = 7; + + for (i = 0; i < limit; i++) + { + dest[i] = src[i]; + + if (dest[i] == EOS) + return &dest[i]; + } + + dest[i] = EOS; + return &dest[i]; +} + +u8 *StringCopy(u8 *dest, const u8 *src) +{ + while (*src != EOS) + { + *dest = *src; + dest++; + src++; + } + + *dest = EOS; + return dest; +} + +u8 *StringAppend(u8 *dest, const u8 *src) +{ + while (*dest != EOS) + dest++; + + return StringCopy(dest, src); +} + +u8 *StringCopyN(u8 *dest, const u8 *src, u8 n) +{ + u16 i; + + for (i = 0; i < n; i++) + dest[i] = src[i]; + + return &dest[n]; +} + +u8 *StringAppendN(u8 *dest, const u8 *src, u8 n) +{ + while (*dest != EOS) + dest++; + + return StringCopyN(dest, src, n); +} + +u16 StringLength(const u8 *str) +{ + u16 length = 0; + + while (str[length] != EOS) + length++; + + return length; +} + +s32 StringCompare(const u8 *str1, const u8 *str2) +{ + while (*str1 == *str2) + { + if (*str1 == EOS) + return 0; + str1++; + str2++; + } + + return *str1 - *str2; +} + +s32 StringCompareN(const u8 *str1, const u8 *str2, u32 n) +{ + while (*str1 == *str2) + { + if (*str1 == EOS) + return 0; + str1++; + str2++; + if (--n == 0) + return 0; + } + + return *str1 - *str2; +} + +bool8 IsStringLengthAtLeast(const u8 *str, s32 n) +{ + u8 i; + + for (i = 0; i < n; i++) + if (str[i] && str[i] != EOS) + return TRUE; + + return FALSE; +} + +u8 *ConvertIntToDecimalStringN(u8 *dest, s32 value, enum StringConvertMode mode, u8 n) +{ + enum { WAITING_FOR_NONZERO_DIGIT, WRITING_DIGITS, WRITING_SPACES } state; + s32 powerOfTen; + s32 largestPowerOfTen = sPowersOfTen[n - 1]; + + state = WAITING_FOR_NONZERO_DIGIT; + + if (mode == STR_CONV_MODE_RIGHT_ALIGN) + state = WRITING_SPACES; + + if (mode == STR_CONV_MODE_LEADING_ZEROS) + state = WRITING_DIGITS; + + for (powerOfTen = largestPowerOfTen; powerOfTen > 0; powerOfTen /= 10) + { + u8 c; + u16 digit = value / powerOfTen; + s32 temp = value - (powerOfTen * digit); + + if (state == WRITING_DIGITS) + { + u8 *out = dest++; + + if (digit <= 9) + c = sDigits[digit]; + else + c = CHAR_QUESTION_MARK; + + *out = c; + } + else if (digit != 0 || powerOfTen == 1) + { + u8 *out; + state = WRITING_DIGITS; + out = dest++; + + if (digit <= 9) + c = sDigits[digit]; + else + c = CHAR_QUESTION_MARK; + + *out = c; + } + else if (state == WRITING_SPACES) + { + *dest++ = 0x77; + } + + value = temp; + } + + *dest = EOS; + return dest; +} + +u8 *ConvertUIntToDecimalStringN(u8 *dest, u32 value, enum StringConvertMode mode, u8 n) +{ + enum { WAITING_FOR_NONZERO_DIGIT, WRITING_DIGITS, WRITING_SPACES } state; + s32 powerOfTen; + s32 largestPowerOfTen = sPowersOfTen[n - 1]; + + state = WAITING_FOR_NONZERO_DIGIT; + + if (mode == STR_CONV_MODE_RIGHT_ALIGN) + state = WRITING_SPACES; + + if (mode == STR_CONV_MODE_LEADING_ZEROS) + state = WRITING_DIGITS; + + for (powerOfTen = largestPowerOfTen; powerOfTen > 0; powerOfTen /= 10) + { + u8 c; + u16 digit = value / powerOfTen; + u32 temp = value - (powerOfTen * digit); + + if (state == WRITING_DIGITS) + { + u8 *out = dest++; + + if (digit <= 9) + c = sDigits[digit]; + else + c = CHAR_QUESTION_MARK; + + *out = c; + } + else if (digit != 0 || powerOfTen == 1) + { + u8 *out; + state = WRITING_DIGITS; + out = dest++; + + if (digit <= 9) + c = sDigits[digit]; + else + c = CHAR_QUESTION_MARK; + + *out = c; + } + else if (state == WRITING_SPACES) + { + *dest++ = 0x77; + } + + value = temp; + } + + *dest = EOS; + return dest; +} + +u8 *ConvertIntToHexStringN(u8 *dest, s32 value, enum StringConvertMode mode, u8 n) +{ + enum { WAITING_FOR_NONZERO_DIGIT, WRITING_DIGITS, WRITING_SPACES } state; + u8 i; + s32 powerOfSixteen; + s32 largestPowerOfSixteen = 1; + + for (i = 1; i < n; i++) + largestPowerOfSixteen *= 16; + + state = WAITING_FOR_NONZERO_DIGIT; + + if (mode == STR_CONV_MODE_RIGHT_ALIGN) + state = WRITING_SPACES; + + if (mode == STR_CONV_MODE_LEADING_ZEROS) + state = WRITING_DIGITS; + + for (powerOfSixteen = largestPowerOfSixteen; powerOfSixteen > 0; powerOfSixteen /= 16) + { + u8 c; + u32 digit = value / powerOfSixteen; + s32 temp = value % powerOfSixteen; + + if (state == WRITING_DIGITS) + { + char *out = dest++; + + if (digit <= 0xF) + c = sDigits[digit]; + else + c = CHAR_QUESTION_MARK; + + *out = c; + } + else if (digit != 0 || powerOfSixteen == 1) + { + char *out; + state = WRITING_DIGITS; + out = dest++; + + if (digit <= 0xF) + c = sDigits[digit]; + else + c = CHAR_QUESTION_MARK; + + *out = c; + } + else if (state == WRITING_SPACES) + { + *dest++ = 0x77; + } + + value = temp; + } + + *dest = EOS; + return dest; +} + +u8 *StringExpandPlaceholders(u8 *dest, const u8 *src) +{ + for (;;) + { + u8 c = *src++; + u8 placeholderId; + u8 *expandedString; + + switch (c) + { + case PLACEHOLDER_BEGIN: + placeholderId = *src++; + expandedString = GetExpandedPlaceholder(placeholderId); + dest = StringExpandPlaceholders(dest, expandedString); + break; + case EXT_CTRL_CODE_BEGIN: + *dest++ = c; + c = *src++; + *dest++ = c; + + switch (c) + { + case 0x07: + case 0x09: + case 0x0F: + case 0x15: + case 0x16: + case 0x17: + case 0x18: + break; + case 0x04: + *dest++ = *src++; + case 0x0B: + *dest++ = *src++; + default: + *dest++ = *src++; + } + break; + case EOS: + *dest = EOS; + return dest; + case 0xFA: + case 0xFB: + case 0xFE: + default: + *dest++ = c; + } + } +} + +u8 *StringBraille(u8 *dest, const u8 *src) +{ + u8 setBrailleFont[4]; + u8 gotoLine2[5]; + + memcpy(setBrailleFont, sSetBrailleFont, 4); + memcpy(gotoLine2, sGotoLine2, 5); + + dest = StringCopy(dest, setBrailleFont); + + for (;;) + { + u8 c = *src++; + + switch (c) + { + case EOS: + *dest = c; + return dest; + case 0xFE: + dest = StringCopy(dest, gotoLine2); + break; + default: + *dest++ = c; + *dest++ = c + 0x40; + break; + } + } +} + +u8 *ExpandPlaceholder_UnknownStringVar(void) +{ + return gUnknownStringVar; +} + +u8 *ExpandPlaceholder_PlayerName(void) +{ + return gSaveBlock2Ptr->playerName; +} + +u8 *ExpandPlaceholder_StringVar1(void) +{ + return gStringVar1; +} + +u8 *ExpandPlaceholder_StringVar2(void) +{ + return gStringVar2; +} + +u8 *ExpandPlaceholder_StringVar3(void) +{ + return gStringVar3; +} + +u8 *ExpandPlaceholder_KunChan(void) +{ + if (gSaveBlock2Ptr->playerGender == MALE) + return gExpandedPlaceholder_Kun; + else + return gExpandedPlaceholder_Chan; +} + +u8 *ExpandPlaceholder_RivalName(void) +{ + if (gSaveBlock2Ptr->playerGender == MALE) + return gExpandedPlaceholder_May; + else + return gExpandedPlaceholder_Brendan; +} + +u8 *ExpandPlaceholder_Version(void) +{ + return gExpandedPlaceholder_Emerald; +} + +u8 *ExpandPlaceholder_Aqua(void) +{ + return gExpandedPlaceholder_Aqua; +} + +u8 *ExpandPlaceholder_Magma(void) +{ + return gExpandedPlaceholder_Magma; +} + +u8 *ExpandPlaceholder_Archie(void) +{ + return gExpandedPlaceholder_Archie; +} + +u8 *ExpandPlaceholder_Maxie(void) +{ + return gExpandedPlaceholder_Maxie; +} + +u8 *ExpandPlaceholder_Kyogre(void) +{ + return gExpandedPlaceholder_Kyogre; +} + +u8 *ExpandPlaceholder_Groudon(void) +{ + return gExpandedPlaceholder_Groudon; +} + +u8 *GetExpandedPlaceholder(u32 id) +{ + if (id > MAX_PLACEHOLDER_ID) + return gExpandedPlaceholder_Empty; + else + return sExpandPlaceholderFuncs[id](); +} + +u8 *StringFill(u8 *dest, u8 c, u16 n) +{ + u16 i; + + for (i = 0; i < n; i++) + *dest++ = c; + + *dest = EOS; + return dest; +} + +u8 *StringCopyPadded(u8 *dest, const u8 *src, u8 c, u16 n) +{ + while (*src != EOS) + { + *dest++ = *src++; + + if (n) + n--; + } + + n--; + + while (n != (u16)-1) + { + *dest++ = c; + n--; + } + + *dest = EOS; + return dest; +} + +u8 *StringFillWithTerminator(u8 *dest, u16 n) +{ + return StringFill(dest, EOS, n); +} -- cgit v1.2.3 From 53935efc64b9945e49dc932917dc179bdbe58631 Mon Sep 17 00:00:00 2001 From: YamaArashi Date: Sat, 14 Jan 2017 15:17:51 -0800 Subject: mostly finish string_util.c --- src/string_util.c | 326 ++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 291 insertions(+), 35 deletions(-) (limited to 'src') diff --git a/src/string_util.c b/src/string_util.c index 35b48ceae..a00f261bd 100644 --- a/src/string_util.c +++ b/src/string_util.c @@ -2,22 +2,23 @@ #include "string_util.h" #include "text.h" -#define MAX_PLACEHOLDER_ID 0xD +EWRAM_DATA u8 gUnknownStringVar[16] = {0}; -extern const u8 sDigits[]; -extern const s32 sPowersOfTen[]; -extern const u8 sSetBrailleFont[]; -extern const u8 sGotoLine2[]; +static const u8 sDigits[] = @"0123456789ABCDEF"; -typedef u8 *(*ExpandPlaceholderFunc)(void); - -extern const ExpandPlaceholderFunc sExpandPlaceholderFuncs[]; - -extern u8 gUnknownStringVar[]; -extern u8 gStringVar1[]; -extern u8 gStringVar2[]; -extern u8 gStringVar3[]; -extern u8 gStringVar4[]; +static const s32 sPowersOfTen[] = +{ + 1, + 10, + 100, + 1000, + 10000, + 100000, + 1000000, + 10000000, + 100000000, + 1000000000, +}; extern u8 gExpandedPlaceholder_Empty[]; extern u8 gExpandedPlaceholder_Kun[]; @@ -393,11 +394,8 @@ u8 *StringExpandPlaceholders(u8 *dest, const u8 *src) u8 *StringBraille(u8 *dest, const u8 *src) { - u8 setBrailleFont[4]; - u8 gotoLine2[5]; - - memcpy(setBrailleFont, sSetBrailleFont, 4); - memcpy(gotoLine2, sGotoLine2, 5); + u8 setBrailleFont[] = { 0xFC, 0x06, 0x06, 0xFF }; + u8 gotoLine2[5] = { 0xFE, 0xFC, 0x0E, 0x02, 0xFF }; dest = StringCopy(dest, setBrailleFont); @@ -421,32 +419,32 @@ u8 *StringBraille(u8 *dest, const u8 *src) } } -u8 *ExpandPlaceholder_UnknownStringVar(void) +static u8 *ExpandPlaceholder_UnknownStringVar(void) { return gUnknownStringVar; } -u8 *ExpandPlaceholder_PlayerName(void) +static u8 *ExpandPlaceholder_PlayerName(void) { return gSaveBlock2Ptr->playerName; } -u8 *ExpandPlaceholder_StringVar1(void) +static u8 *ExpandPlaceholder_StringVar1(void) { return gStringVar1; } -u8 *ExpandPlaceholder_StringVar2(void) +static u8 *ExpandPlaceholder_StringVar2(void) { return gStringVar2; } -u8 *ExpandPlaceholder_StringVar3(void) +static u8 *ExpandPlaceholder_StringVar3(void) { return gStringVar3; } -u8 *ExpandPlaceholder_KunChan(void) +static u8 *ExpandPlaceholder_KunChan(void) { if (gSaveBlock2Ptr->playerGender == MALE) return gExpandedPlaceholder_Kun; @@ -454,7 +452,7 @@ u8 *ExpandPlaceholder_KunChan(void) return gExpandedPlaceholder_Chan; } -u8 *ExpandPlaceholder_RivalName(void) +static u8 *ExpandPlaceholder_RivalName(void) { if (gSaveBlock2Ptr->playerGender == MALE) return gExpandedPlaceholder_May; @@ -462,47 +460,67 @@ u8 *ExpandPlaceholder_RivalName(void) return gExpandedPlaceholder_Brendan; } -u8 *ExpandPlaceholder_Version(void) +static u8 *ExpandPlaceholder_Version(void) { return gExpandedPlaceholder_Emerald; } -u8 *ExpandPlaceholder_Aqua(void) +static u8 *ExpandPlaceholder_Aqua(void) { return gExpandedPlaceholder_Aqua; } -u8 *ExpandPlaceholder_Magma(void) +static u8 *ExpandPlaceholder_Magma(void) { return gExpandedPlaceholder_Magma; } -u8 *ExpandPlaceholder_Archie(void) +static u8 *ExpandPlaceholder_Archie(void) { return gExpandedPlaceholder_Archie; } -u8 *ExpandPlaceholder_Maxie(void) +static u8 *ExpandPlaceholder_Maxie(void) { return gExpandedPlaceholder_Maxie; } -u8 *ExpandPlaceholder_Kyogre(void) +static u8 *ExpandPlaceholder_Kyogre(void) { return gExpandedPlaceholder_Kyogre; } -u8 *ExpandPlaceholder_Groudon(void) +static u8 *ExpandPlaceholder_Groudon(void) { return gExpandedPlaceholder_Groudon; } u8 *GetExpandedPlaceholder(u32 id) { - if (id > MAX_PLACEHOLDER_ID) + typedef u8 *(*ExpandPlaceholderFunc)(void); + + static const ExpandPlaceholderFunc funcs[] = + { + ExpandPlaceholder_UnknownStringVar, + ExpandPlaceholder_PlayerName, + ExpandPlaceholder_StringVar1, + ExpandPlaceholder_StringVar2, + ExpandPlaceholder_StringVar3, + ExpandPlaceholder_KunChan, + ExpandPlaceholder_RivalName, + ExpandPlaceholder_Version, + ExpandPlaceholder_Aqua, + ExpandPlaceholder_Magma, + ExpandPlaceholder_Archie, + ExpandPlaceholder_Maxie, + ExpandPlaceholder_Kyogre, + ExpandPlaceholder_Groudon, + }; + + if (id >= ARRAY_COUNT(funcs)) return gExpandedPlaceholder_Empty; else - return sExpandPlaceholderFuncs[id](); + return funcs[id](); } u8 *StringFill(u8 *dest, u8 c, u16 n) @@ -542,3 +560,241 @@ u8 *StringFillWithTerminator(u8 *dest, u16 n) { return StringFill(dest, EOS, n); } + +__attribute__((naked)) +u8 *StringCopyN_Multibyte(u8 *dest, u8 *src, u32 n) +{ + asm(".syntax unified\n\ + push {r4,r5,lr}\n\ + adds r4, r0, 0\n\ + adds r3, r1, 0\n\ + subs r2, 0x1\n\ + movs r5, 0x1\n\ + negs r5, r5\n\ + b _080091B2\n\ +_0800919A:\n\ + strb r0, [r4]\n\ + adds r3, 0x1\n\ + adds r4, 0x1\n\ + subs r0, r3, 0x1\n\ + ldrb r0, [r0]\n\ + cmp r0, 0xF9\n\ + bne _080091B0\n\ + ldrb r0, [r3]\n\ + strb r0, [r4]\n\ + adds r3, 0x1\n\ + adds r4, 0x1\n\ +_080091B0:\n\ + subs r2, 0x1\n\ +_080091B2:\n\ + cmp r2, r5\n\ + beq _080091BE\n\ + ldrb r0, [r3]\n\ + adds r1, r0, 0\n\ + cmp r1, 0xFF\n\ + bne _0800919A\n\ +_080091BE:\n\ + movs r0, 0xFF\n\ + strb r0, [r4]\n\ + adds r0, r4, 0\n\ + pop {r4,r5}\n\ + pop {r1}\n\ + bx r1\n\ + .syntax divided"); +} + +u32 StringLength_Multibyte(u8 *str) +{ + u32 length = 0; + + while (*str != EOS) + { + if (*str == 0xF9) + str++; + str++; + length++; + } + + return length; +} + +u8 *WriteColorChangeControlCode(u8 *dest, u32 colorType, u8 color) +{ + *dest = 0xFC; + dest++; + + switch (colorType) + { + case 0: + *dest = 1; + dest++; + break; + case 1: + *dest = 3; + dest++; + break; + case 2: + *dest = 2; + dest++; + break; + } + + *dest = color; + dest++; + *dest = EOS; + return dest; +} + +bool32 sub_8009228(u8 *str) +{ + while (*str != EOS) + { + if (*str <= 0xA0) + if (*str != 0) + return TRUE; + str++; + } + + return FALSE; +} + +bool32 sub_800924C(u8 *str, s32 n) +{ + s32 i; + + for (i = 0; *str != EOS && i < n; i++) + { + if (*str <= 0xA0) + if (*str != 0) + return TRUE; + str++; + } + + return FALSE; +} + +u8 GetExtCtrlCodeLength(u8 code) +{ + static const u8 lengths[] = + { + 1, + 2, + 2, + 2, + 4, + 2, + 2, + 1, + 2, + 1, + 1, + 3, + 2, + 2, + 2, + 1, + 3, + 2, + 2, + 2, + 2, + 1, + 1, + 1, + 1, + }; + + u8 length = 0; + if (code < ARRAY_COUNT(lengths)) + length = lengths[code]; + return length; +} + +static const u8 *SkipExtCtrlCode(const u8 *s) +{ + while (*s == 0xFC) + { + s++; + s += GetExtCtrlCodeLength(*s); + } + + return s; +} + +s32 StringCompareWithoutExtCtrlCodes(const u8 *str1, const u8 *str2) +{ + s32 retVal = 0; + + while (1) + { + str1 = SkipExtCtrlCode(str1); + str2 = SkipExtCtrlCode(str2); + + if (*str1 > *str2) + break; + + if (*str1 < *str2) + { + retVal = -1; + if (*str2 == 0xFF) + retVal = 1; + } + + if (*str1 == 0xFF) + return retVal; + + str1++; + str2++; + } + + retVal = 1; + + if (*str1 == 0xFF) + retVal = -1; + + return retVal; +} + +void ConvertInternationalString(u8 *s, u8 language) +{ + if (language == LANGUAGE_JAPANESE) + { + u8 i; + + StripExtCtrlCodes(s); + i = StringLength(s); + s[i++] = 0xFC; + s[i++] = 22; + s[i++] = 0xFF; + + i--; + + while (i != (u8)-1) + { + s[i + 2] = s[i]; + i--; + } + + s[0] = 0xFC; + s[1] = 21; + } +} + +void StripExtCtrlCodes(u8 *str) +{ + u16 srcIndex = 0; + u16 destIndex = 0; + while (str[srcIndex] != 0xFF) + { + if (str[srcIndex] == 0xFC) + { + srcIndex++; + srcIndex += GetExtCtrlCodeLength(str[srcIndex]); + } + else + { + str[destIndex++] = str[srcIndex++]; + } + } + str[destIndex] = 0xFF; +} -- cgit v1.2.3 From 72470c70488b73ca1ad25f055a0dc2e1ced15486 Mon Sep 17 00:00:00 2001 From: YamaArashi Date: Sat, 14 Jan 2017 15:50:29 -0800 Subject: remove explicit array size --- src/string_util.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/string_util.c b/src/string_util.c index a00f261bd..c7e8b4e9c 100644 --- a/src/string_util.c +++ b/src/string_util.c @@ -395,7 +395,7 @@ u8 *StringExpandPlaceholders(u8 *dest, const u8 *src) u8 *StringBraille(u8 *dest, const u8 *src) { u8 setBrailleFont[] = { 0xFC, 0x06, 0x06, 0xFF }; - u8 gotoLine2[5] = { 0xFE, 0xFC, 0x0E, 0x02, 0xFF }; + u8 gotoLine2[] = { 0xFE, 0xFC, 0x0E, 0x02, 0xFF }; dest = StringCopy(dest, setBrailleFont); -- cgit v1.2.3 From b7e2a259152fe716ac532dcc23c2dcfd579eee55 Mon Sep 17 00:00:00 2001 From: YamaArashi Date: Sat, 14 Jan 2017 17:14:36 -0800 Subject: port matching InsertTask() from pokeruby --- src/task.c | 111 ++++++------------------------------------------------------- 1 file changed, 10 insertions(+), 101 deletions(-) (limited to 'src') diff --git a/src/task.c b/src/task.c index f84c83e80..bf8abd794 100644 --- a/src/task.c +++ b/src/task.c @@ -49,7 +49,6 @@ u8 CreateTask(TaskFunc func, u8 priority) return 0; } -#ifdef NONMATCHING static void InsertTask(u8 newTaskId) { u8 taskId = FindFirstActiveTask(); @@ -62,7 +61,7 @@ static void InsertTask(u8 newTaskId) return; } - for (;;) + while (1) { if (gTasks[newTaskId].priority < gTasks[taskId].priority) { @@ -70,112 +69,22 @@ static void InsertTask(u8 newTaskId) // so we insert the new task before it. gTasks[newTaskId].prev = gTasks[taskId].prev; gTasks[newTaskId].next = taskId; - if (gTasks[taskId].prev != HEAD_SENTINEL) gTasks[gTasks[taskId].prev].next = newTaskId; - gTasks[taskId].prev = newTaskId; return; } - - if (gTasks[taskId].next != TAIL_SENTINEL) - taskId = gTasks[taskId].next; - else - break; + if (gTasks[taskId].next == TAIL_SENTINEL) + { + // We've reached the end. + gTasks[newTaskId].prev = taskId; + gTasks[newTaskId].next = gTasks[taskId].next; + gTasks[taskId].next = newTaskId; + return; + } + taskId = gTasks[taskId].next; } - - // We've reached the end. - gTasks[newTaskId].prev = taskId; - gTasks[newTaskId].next = gTasks[taskId].next; - gTasks[taskId].next = newTaskId; -} -#else -__attribute__((naked)) -static void InsertTask(u8 newTaskId) -{ - asm("push {r4, r5, r6, r7, lr}\n\ - mov r7, r8\n\ - push {r7}\n\ - lsl r0, r0, #24\n\ - lsr r4, r0, #24\n\ - bl FindFirstActiveTask\n\ - lsl r0, r0, #24\n\ - lsr r1, r0, #24\n\ - cmp r1, #16\n\ - bne .LInsertTask_foundActiveTask\n\ - ldr r1, .LInsertTask_gTasks1\n\ - lsl r0, r4, #2\n\ - add r0, r0, r4\n\ - lsl r0, r0, #3\n\ - add r0, r0, r1\n\ - mov r1, #254\n\ - strb r1, [r0, #5]\n\ - mov r1, #255\n\ - strb r1, [r0, #6]\n\ - b .LInsertTask_done\n\ - .align 2, 0\n\ -.LInsertTask_gTasks1:\n\ - .word gTasks\n\ -.LInsertTask_foundActiveTask:\n\ - ldr r6, .LInsertTask_gTasks2\n\ - lsl r0, r4, #2\n\ - mov r12, r0\n\ - mov r8, r6\n\ - add r0, r0, r4\n\ - lsl r0, r0, #3\n\ - add r2, r0, r6\n\ -.LInsertTask_loop:\n\ - lsl r0, r1, #2\n\ - add r0, r0, r1\n\ - lsl r5, r0, #3\n\ - mov r7, r8\n\ - add r3, r5, r7\n\ - ldrb r0, [r2, #7]\n\ - ldrb r7, [r3, #7]\n\ - cmp r0, r7\n\ - bcs .LInsertTask_next\n\ - ldrb r0, [r3, #5]\n\ - strb r0, [r2, #5]\n\ - strb r1, [r2, #6]\n\ - ldrb r0, [r3, #5]\n\ - cmp r0, #254\n\ - beq .LInsertTask_insertAtHead\n\ - add r1, r0, #0\n\ - lsl r0, r1, #2\n\ - add r0, r0, r1\n\ - lsl r0, r0, #3\n\ - add r0, r0, r8\n\ - strb r4, [r0, #6]\n\ -.LInsertTask_insertAtHead:\n\ - strb r4, [r3, #5]\n\ - b .LInsertTask_done\n\ - .align 2, 0\n\ -.LInsertTask_gTasks2:\n\ - .word gTasks\n\ -.LInsertTask_next:\n\ - ldrb r0, [r3, #6]\n\ - cmp r0, #255\n\ - beq .LInsertTask_insertAtTail\n\ - add r1, r0, #0\n\ - b .LInsertTask_loop\n\ -.LInsertTask_insertAtTail:\n\ - mov r2, r12\n\ - add r0, r2, r4\n\ - lsl r0, r0, #3\n\ - add r0, r0, r6\n\ - strb r1, [r0, #5]\n\ - add r2, r5, r6\n\ - ldrb r1, [r2, #6]\n\ - strb r1, [r0, #6]\n\ - strb r4, [r2, #6]\n\ -.LInsertTask_done:\n\ - pop {r3}\n\ - mov r8, r3\n\ - pop {r4, r5, r6, r7}\n\ - pop {r0}\n\ - bx r0\n"); } -#endif // NONMATCHING void DestroyTask(u8 taskId) { -- cgit v1.2.3 From af822ef2a71e66a61e0d3fad4c641445b4c1b9cd Mon Sep 17 00:00:00 2001 From: YamaArashi Date: Sun, 15 Jan 2017 14:05:54 -0800 Subject: make StringCopyN_Multibyte match --- src/string_util.c | 56 ++++++++++++++++++------------------------------------- 1 file changed, 18 insertions(+), 38 deletions(-) (limited to 'src') diff --git a/src/string_util.c b/src/string_util.c index c7e8b4e9c..aebbf76c9 100644 --- a/src/string_util.c +++ b/src/string_util.c @@ -561,46 +561,26 @@ u8 *StringFillWithTerminator(u8 *dest, u16 n) return StringFill(dest, EOS, n); } -__attribute__((naked)) u8 *StringCopyN_Multibyte(u8 *dest, u8 *src, u32 n) { - asm(".syntax unified\n\ - push {r4,r5,lr}\n\ - adds r4, r0, 0\n\ - adds r3, r1, 0\n\ - subs r2, 0x1\n\ - movs r5, 0x1\n\ - negs r5, r5\n\ - b _080091B2\n\ -_0800919A:\n\ - strb r0, [r4]\n\ - adds r3, 0x1\n\ - adds r4, 0x1\n\ - subs r0, r3, 0x1\n\ - ldrb r0, [r0]\n\ - cmp r0, 0xF9\n\ - bne _080091B0\n\ - ldrb r0, [r3]\n\ - strb r0, [r4]\n\ - adds r3, 0x1\n\ - adds r4, 0x1\n\ -_080091B0:\n\ - subs r2, 0x1\n\ -_080091B2:\n\ - cmp r2, r5\n\ - beq _080091BE\n\ - ldrb r0, [r3]\n\ - adds r1, r0, 0\n\ - cmp r1, 0xFF\n\ - bne _0800919A\n\ -_080091BE:\n\ - movs r0, 0xFF\n\ - strb r0, [r4]\n\ - adds r0, r4, 0\n\ - pop {r4,r5}\n\ - pop {r1}\n\ - bx r1\n\ - .syntax divided"); + u32 i; + + for (i = n - 1; i != (u32)-1; i--) + { + if (*src == EOS) + { + break; + } + else + { + *dest++ = *src++; + if (*(src - 1) == 0xF9) + *dest++ = *src++; + } + } + + *dest = EOS; + return dest; } u32 StringLength_Multibyte(u8 *str) -- cgit v1.2.3 From 3c6e4dba69d8ab1fa819b81435af60de9eb829ea Mon Sep 17 00:00:00 2001 From: YamaArashi Date: Sun, 15 Jan 2017 14:15:38 -0800 Subject: formatting --- src/string_util.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/string_util.c b/src/string_util.c index aebbf76c9..fba19ae52 100644 --- a/src/string_util.c +++ b/src/string_util.c @@ -575,7 +575,7 @@ u8 *StringCopyN_Multibyte(u8 *dest, u8 *src, u32 n) { *dest++ = *src++; if (*(src - 1) == 0xF9) - *dest++ = *src++; + *dest++ = *src++; } } -- cgit v1.2.3 From 8a36c77ac8fd10350eed197f28e519c9a7a3b8a6 Mon Sep 17 00:00:00 2001 From: camthesaxman Date: Tue, 31 Jan 2017 23:31:28 -0600 Subject: make emerald build --- src/string_util.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/string_util.c b/src/string_util.c index fba19ae52..009072dca 100644 --- a/src/string_util.c +++ b/src/string_util.c @@ -4,7 +4,7 @@ EWRAM_DATA u8 gUnknownStringVar[16] = {0}; -static const u8 sDigits[] = @"0123456789ABCDEF"; +static const u8 sDigits[] = __("0123456789ABCDEF"); static const s32 sPowersOfTen[] = { -- cgit v1.2.3 From bcff8d1b45d6cfdc0c2e5e94137aa0e578009f7c Mon Sep 17 00:00:00 2001 From: camthesaxman Date: Wed, 1 Feb 2017 22:15:38 -0600 Subject: start decompiling battle_ai --- src/battle_ai.c | 789 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 789 insertions(+) create mode 100644 src/battle_ai.c (limited to 'src') diff --git a/src/battle_ai.c b/src/battle_ai.c new file mode 100644 index 000000000..7f020fd75 --- /dev/null +++ b/src/battle_ai.c @@ -0,0 +1,789 @@ +#include "global.h" + +#define AIScriptRead32(ptr) ((ptr)[0] | (ptr)[1] << 8 | (ptr)[2] << 16 | (ptr)[3] << 24) +#define AIScriptRead16(ptr) ((ptr)[0] | (ptr)[1] << 8) +#define AIScriptRead8(ptr) ((ptr)[0]) +#define AIScriptReadPtr(ptr) (u8*) AIScriptRead32(ptr) + +//Copied from pokeruby -- hopefully the same +struct Trainer +{ + /*0x00*/ u8 partyFlags; + /*0x01*/ u8 trainerClass; + /*0x02*/ u8 encounterMusic:7; + /*0x02*/ u8 gender:1; + /*0x03*/ u8 trainerPic; + /*0x04*/ u8 trainerName[12]; + /*0x10*/ u16 items[4]; + /*0x18*/ bool8 doubleBattle; + /*0x1C*/ u32 aiFlags; + /*0x20*/ u8 partySize; + /*0x24*/ void *party; +}; + +#define POKEMON_NAME_LENGTH 10 + +struct BattlePokemon +{ + /* 0x00 */ u16 species; + /* 0x02 */ u16 attack; + /* 0x04 */ u16 defense; + /* 0x06 */ u16 speed; + /* 0x08 */ u16 spAttack; + /* 0x0A */ u16 spDefense; + /* 0x0C */ u16 moves[4]; + /* 0x14 */ u32 hpIV:5; + /* 0x14 */ u32 attackIV:5; + /* 0x15 */ u32 defenseIV:5; + /* 0x15 */ u32 speedIV:5; + /* 0x16 */ u32 spAttackIV:5; + /* 0x17 */ u32 spDefenseIV:5; + /* 0x17 */ u32 isEgg:1; + /* 0x17 */ u32 altAbility:1; + /* 0x18 */ s8 statStages[8]; + /* 0x20 */ u8 ability; + /* 0x21 */ u8 type1; + /* 0x22 */ u8 type2; + /* 0x23 */ u8 unknown; + /* 0x24 */ u8 pp[4]; + /* 0x28 */ u16 hp; + /* 0x2A */ u8 level; + /* 0x2B */ u8 friendship; + /* 0x2C */ u16 maxHP; + /* 0x2E */ u16 item; + /* 0x30 */ u8 nickname[POKEMON_NAME_LENGTH + 1]; + /* 0x3B */ u8 ppBonuses; + /* 0x3C */ u8 otName[8]; + /* 0x44 */ u32 experience; + /* 0x48 */ u32 personality; + /* 0x4C */ u32 status1; + /* 0x50 */ u32 status2; + /* 0x54 */ u32 otId; +}; + +//size should be 0x1C +struct UnknownStruct3 +{ + u8 unk0; + u8 unk1; + u16 unk2; + s8 unk4[4]; + u8 filler8[4]; + u32 unkC; + u8 unk10; + u8 unk11; + u8 filler12[6]; + u8 unk18[4]; +}; + +//size should be 0x54 +struct UnknownStruct2 +{ + u16 unk0[2][8]; + u8 filler20[0x20]; + u8 unk40[4]; + u8 unk44[4]; + u16 unk48[4]; + u8 unk50; +}; + +struct UnknownStruct4 +{ + u8 filler0[0x20]; + u8 unk20; +}; + +struct UnknownStruct1 +{ + u8 unk0; + u8 filler1[0x13]; + struct UnknownStruct3 *unk14; + struct UnknownStruct2 *unk18; + struct UnknownStruct4 *unk1C; +}; + +extern u32 gBattleTypeFlags; +extern u8 gUnknown_02024064; +extern struct BattlePokemon gBattleMons[]; +extern u16 gUnknown_020241EA; +extern u8 gUnknown_0202420C; +extern u8 gUnknown_02024210; +extern u16 gUnknown_02024248[]; +extern u8 *gUnknown_0202449C; +extern struct UnknownStruct1 *gUnknown_020244A8; +extern u16 gUnknown_02038BCA; +extern u16 gUnknown_02038BCC; +extern const u8 *gAIScriptPtr; +extern u8 gUnknown_0203AB3C; +extern struct Trainer gTrainers[]; +extern const u32 gBitTable[]; +extern const u8 *const gUnknown_082DBEF8[]; + +typedef void (*BattleAICmdFunc)(void); + +extern const BattleAICmdFunc gUnknown_085B083C[]; + +extern u8 sub_803FECC(); +extern u16 Random(); +extern u32 battle_side_get_owner(); +extern u32 sub_8186438(); +extern u32 sub_81A6FB4(); + +void BattleAI_SetupAIData(u8 a); +u8 sub_8130BDC(void); +u8 sub_8130CF4(void); +void sub_8131074(void); +void BattleAI_DoAIProcessing(void); + +void BattleAI_HandleItemUseBeforeAISetup(u8 a) +{ + s32 i; + u8 *data = (u8 *)gUnknown_020244A8->unk18; + + for (i = 0; (u32)i < 0x54; i++) + data[i] = 0; + if ((gBattleTypeFlags & 0x0A7F098A) == 8) + { + for (i = 0; i < 4; i++) + { + if (gTrainers[gUnknown_02038BCA].items[i] != 0) + { + gUnknown_020244A8->unk18->unk48[gUnknown_020244A8->unk18->unk50] = gTrainers[gUnknown_02038BCA].items[i]; + gUnknown_020244A8->unk18->unk50++; + } + } + } + + BattleAI_SetupAIData(a); +} + +void BattleAI_SetupAIData(u8 a) +{ + s32 i; + u8 *data = (u8 *)gUnknown_020244A8->unk14; + u8 r6; + + for (i = 0; (u32)i < 0x1C; i++) + data[i] = 0; + for (i = 0; i < 4; i++) + { + if (a & 1) + gUnknown_020244A8->unk14->unk4[i] = 100; + else + gUnknown_020244A8->unk14->unk4[i] = 0; + a >>= 1; + } + r6 = sub_803FECC(gUnknown_02024064, 0, 0xFF); + for (i = 0; i < 4; i++) + { + if (gBitTable[i] & r6) + gUnknown_020244A8->unk14->unk4[i] = 0; + gUnknown_020244A8->unk14->unk18[i] = 100 - (Random() % 16); + } + gUnknown_020244A8->unk1C->unk20 = 0; + gUnknown_0203AB3C = gUnknown_02024064; + if (gBattleTypeFlags & 1) + { + gUnknown_0202420C = (Random() & 2) + (battle_side_get_owner(gUnknown_02024064) ^ 1); + if (gUnknown_02024210 & gBitTable[gUnknown_0202420C]) + gUnknown_0202420C ^= 2; + } + else + { + //_08130A60 + gUnknown_0202420C = gUnknown_0203AB3C ^ 1; + } + //_08130A68 + if (gBattleTypeFlags & 0x1000000) + gUnknown_020244A8->unk14->unkC = sub_8186438(); + else if (gBattleTypeFlags & 0x80) + gUnknown_020244A8->unk14->unkC = 0x40000000; + else if (gBattleTypeFlags & 0x400) + gUnknown_020244A8->unk14->unkC = 0x20000000; + else if (gBattleTypeFlags & 0x10) + gUnknown_020244A8->unk14->unkC = 0x80000000; + else if (gBattleTypeFlags & 0x80000) + gUnknown_020244A8->unk14->unkC = sub_81A6FB4(); + else if (gBattleTypeFlags & 0x0C3F0900) + gUnknown_020244A8->unk14->unkC = 7; + else if (gBattleTypeFlags & 0x8000) + gUnknown_020244A8->unk14->unkC = gTrainers[gUnknown_02038BCA].aiFlags | gTrainers[gUnknown_02038BCC].aiFlags; + else + gUnknown_020244A8->unk14->unkC = gTrainers[gUnknown_02038BCA].aiFlags; + if (gBattleTypeFlags & 1) + gUnknown_020244A8->unk14->unkC |= 0x80; +} + +u8 sub_8130BA4(void) +{ + u16 r4 = gUnknown_020241EA; + u8 ret; + + if (!(gBattleTypeFlags & 1)) + ret = sub_8130BDC(); + else + ret = sub_8130CF4(); + gUnknown_020241EA = r4; + return ret; +} + +u8 sub_8130BDC(void) +{ + u8 r6; + s32 i; + u8 arr1[4]; + u8 arr2[4]; + + sub_8131074(); + while (gUnknown_020244A8->unk14->unkC != 0) + { + if (gUnknown_020244A8->unk14->unkC & 1) + { + gUnknown_020244A8->unk14->unk0 = 0; + BattleAI_DoAIProcessing(); + } + gUnknown_020244A8->unk14->unkC >>= 1; + gUnknown_020244A8->unk14->unk11++; + gUnknown_020244A8->unk14->unk1 = 0; + } + //_08130C2C + if (gUnknown_020244A8->unk14->unk10 & 2) + return 4; + if (gUnknown_020244A8->unk14->unk10 & 4) + return 5; + r6 = 1; + arr1[0] = gUnknown_020244A8->unk14->unk4[0]; + arr2[0] = 0; + for (i = 1; i < 4; i++) + { + if (gBattleMons[gUnknown_0203AB3C].moves[i] != 0) + { + if (arr1[0] == gUnknown_020244A8->unk14->unk4[i]) + { + arr1[r6] = gUnknown_020244A8->unk14->unk4[i]; + arr2[r6++] = i; + } + //_08130CAA + if (arr1[0] < gUnknown_020244A8->unk14->unk4[i]) + { + r6 = 1; + arr1[0] = gUnknown_020244A8->unk14->unk4[i]; + arr2[0] = i; + } + } + //_08130CC6 + } + return arr2[Random() % r6]; +} + +#ifdef NONMATCHING +u8 sub_8130CF4(void) +{ + s32 i; + s32 j; + //s32 r4_2; + #define r4_2 r4 + s32 r5; + s16 r5_2; + s32 r4; + s16 sp0[4]; + s8 sp8[4]; + s8 spC[4]; + u8 sp10[4]; // definitely unsigned + u8 sp14[4]; + //u8 *sp1C = spC; + //u8 *sp18 = sp8; + //u8 *sp20 = spC; + + for (i = 0; i < 4; i++) //_08130D14 + { + if (i == gUnknown_0203AB3C || gBattleMons[i].hp == 0) + { + //_08130D2E + spC[i] = -1; + sp0[i] = -1; + } + //_08130D48 + else + { + if (gBattleTypeFlags & 0x20000) + BattleAI_SetupAIData(gUnknown_0202449C[0x92] >> 4); + else + BattleAI_SetupAIData(0xF); + //_08130D76 + gUnknown_0202420C = i; + if ((i & 1) != (gUnknown_0203AB3C & 1)) + sub_8131074(); + //_08130D90 + gUnknown_020244A8->unk14->unk11 = 0; + gUnknown_020244A8->unk14->unk1 = 0; + r4 = gUnknown_020244A8->unk14->unkC; + while (r4 != 0) + { + if (r4 & 1) + { + gUnknown_020244A8->unk14->unk0 = 0; + BattleAI_DoAIProcessing(); + } + r4 >>= 1; + gUnknown_020244A8->unk14->unk11++; + gUnknown_020244A8->unk14->unk1 = 0; + } + //_08130DD8 + if (gUnknown_020244A8->unk14->unk10 & 2) + spC[i] = 4; + else if (gUnknown_020244A8->unk14->unk10 & 4) + spC[i] = 5; + else + { + //_08130E10 + sp10[0] = gUnknown_020244A8->unk14->unk4[0]; + sp14[0] = 0; + r5 = 1; + for (j = 1; j < 4; j++) + { + if (gBattleMons[gUnknown_0203AB3C].moves[j] != 0) + { + if (sp10[0] == gUnknown_020244A8->unk14->unk4[j]) + { + sp10[r5] = gUnknown_020244A8->unk14->unk4[j]; + sp14[r5] = j; + r5++; + } + if (sp10[0] < gUnknown_020244A8->unk14->unk4[j]) + { + sp10[0] = gUnknown_020244A8->unk14->unk4[j]; + sp14[0] = j; + r5 = 1; + } + } + //_08130E72 + } + spC[i] = sp14[Random() % r5]; + //asm("":::"r3"); + sp0[i] = sp10[0]; + if (i == (gUnknown_0203AB3C ^ 2) && sp0[i] < 100) + sp0[i] = -1; + } + } + //_08130EAE + } + + //#define i r5 + + //_08130EC4 + r5_2 = sp0[0]; + sp8[0] = 0; + r4_2 = 1; + for (i = 1; i < 4; i++) + { + //_08130EDA + if (r5_2 == sp0[i]) + { + sp8[r4_2] = i; + r4_2++; + } + //_08130EEE + if (r5_2 < sp0[i]) + { + r5_2 = sp0[i]; + sp8[0] = i; + r4_2 = 1; + } + } + gUnknown_0202420C = sp8[Random() % r4_2]; + return spC[gUnknown_0202420C]; +} +#else +__attribute__((naked)) +u8 sub_8130CF4(void) +{ + 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\ + movs r0, 0\n\ + mov r8, r0\n\ + mov r1, sp\n\ + adds r1, 0xC\n\ + str r1, [sp, 0x1C]\n\ + mov r2, sp\n\ + adds r2, 0x8\n\ + str r2, [sp, 0x18]\n\ + str r1, [sp, 0x20]\n\ + mov r10, sp\n\ +_08130D14:\n\ + ldr r0, =gUnknown_0203AB3C\n\ + ldrb r0, [r0]\n\ + cmp r8, r0\n\ + beq _08130D2E\n\ + movs r0, 0x58\n\ + mov r7, r8\n\ + muls r7, r0\n\ + adds r0, r7, 0\n\ + ldr r1, =gBattleMons\n\ + adds r0, r1\n\ + ldrh r0, [r0, 0x28]\n\ + cmp r0, 0\n\ + bne _08130D48\n\ +_08130D2E:\n\ + movs r0, 0xFF\n\ + ldr r2, [sp, 0x20]\n\ + strb r0, [r2]\n\ + ldr r0, =0x0000ffff\n\ + mov r7, r10\n\ + strh r0, [r7]\n\ + b _08130EAE\n\ + .pool\n\ +_08130D48:\n\ + ldr r0, =gBattleTypeFlags\n\ + ldr r0, [r0]\n\ + movs r1, 0x80\n\ + lsls r1, 10\n\ + ands r0, r1\n\ + cmp r0, 0\n\ + beq _08130D70\n\ + ldr r0, =gUnknown_0202449C\n\ + ldr r0, [r0]\n\ + adds r0, 0x92\n\ + ldrb r0, [r0]\n\ + lsrs r0, 4\n\ + bl BattleAI_SetupAIData\n\ + b _08130D76\n\ + .pool\n\ +_08130D70:\n\ + movs r0, 0xF\n\ + bl BattleAI_SetupAIData\n\ +_08130D76:\n\ + ldr r0, =gUnknown_0202420C\n\ + mov r1, r8\n\ + strb r1, [r0]\n\ + movs r1, 0x1\n\ + mov r2, r8\n\ + ands r2, r1\n\ + ldr r0, =gUnknown_0203AB3C\n\ + ldrb r0, [r0]\n\ + ands r1, r0\n\ + cmp r2, r1\n\ + beq _08130D90\n\ + bl sub_8131074\n\ +_08130D90:\n\ + ldr r2, =gUnknown_020244A8\n\ + ldr r0, [r2]\n\ + ldr r0, [r0, 0x14]\n\ + movs r1, 0\n\ + strb r1, [r0, 0x11]\n\ + ldr r0, [r2]\n\ + ldr r0, [r0, 0x14]\n\ + strb r1, [r0, 0x1]\n\ + ldr r0, [r2]\n\ + ldr r0, [r0, 0x14]\n\ + ldr r4, [r0, 0xC]\n\ + mov r9, r2\n\ + cmp r4, 0\n\ + beq _08130DD8\n\ + mov r5, r9\n\ + movs r6, 0\n\ +_08130DB0:\n\ + movs r0, 0x1\n\ + ands r0, r4\n\ + cmp r0, 0\n\ + beq _08130DC2\n\ + ldr r0, [r5]\n\ + ldr r0, [r0, 0x14]\n\ + strb r6, [r0]\n\ + bl BattleAI_DoAIProcessing\n\ +_08130DC2:\n\ + asrs r4, 1\n\ + ldr r0, [r5]\n\ + ldr r1, [r0, 0x14]\n\ + ldrb r0, [r1, 0x11]\n\ + adds r0, 0x1\n\ + strb r0, [r1, 0x11]\n\ + ldr r0, [r5]\n\ + ldr r0, [r0, 0x14]\n\ + strb r6, [r0, 0x1]\n\ + cmp r4, 0\n\ + bne _08130DB0\n\ +_08130DD8:\n\ + mov r2, r9\n\ + ldr r0, [r2]\n\ + ldr r3, [r0, 0x14]\n\ + ldrb r1, [r3, 0x10]\n\ + movs r0, 0x2\n\ + ands r0, r1\n\ + cmp r0, 0\n\ + beq _08130DFC\n\ + movs r0, 0x4\n\ + ldr r7, [sp, 0x20]\n\ + strb r0, [r7]\n\ + b _08130EAE\n\ + .pool\n\ +_08130DFC:\n\ + movs r0, 0x4\n\ + ands r0, r1\n\ + lsls r0, 24\n\ + lsrs r2, r0, 24\n\ + cmp r2, 0\n\ + beq _08130E10\n\ + movs r0, 0x5\n\ + ldr r1, [sp, 0x20]\n\ + strb r0, [r1]\n\ + b _08130EAE\n\ +_08130E10:\n\ + add r1, sp, 0x10\n\ + ldrb r0, [r3, 0x4]\n\ + strb r0, [r1]\n\ + add r0, sp, 0x14\n\ + strb r2, [r0]\n\ + movs r5, 0x1\n\ + movs r3, 0x1\n\ + adds r6, r1, 0\n\ + ldr r0, =gUnknown_0203AB3C\n\ + ldrb r1, [r0]\n\ + movs r0, 0x58\n\ + muls r0, r1\n\ + ldr r2, =gUnknown_02024090\n\ + adds r0, r2\n\ + adds r4, r0, 0x2\n\ + add r7, sp, 0x14\n\ +_08130E30:\n\ + ldrh r0, [r4]\n\ + cmp r0, 0\n\ + beq _08130E72\n\ + ldrb r1, [r6]\n\ + mov r2, r9\n\ + ldr r0, [r2]\n\ + ldr r0, [r0, 0x14]\n\ + adds r0, 0x4\n\ + adds r2, r0, r3\n\ + movs r0, 0\n\ + ldrsb r0, [r2, r0]\n\ + cmp r1, r0\n\ + bne _08130E56\n\ + adds r0, r6, r5\n\ + ldrb r1, [r2]\n\ + strb r1, [r0]\n\ + adds r0, r7, r5\n\ + strb r3, [r0]\n\ + adds r5, 0x1\n\ +_08130E56:\n\ + ldrb r1, [r6]\n\ + mov r2, r9\n\ + ldr r0, [r2]\n\ + ldr r0, [r0, 0x14]\n\ + adds r0, 0x4\n\ + adds r2, r0, r3\n\ + movs r0, 0\n\ + ldrsb r0, [r2, r0]\n\ + cmp r1, r0\n\ + bge _08130E72\n\ + ldrb r0, [r2]\n\ + strb r0, [r6]\n\ + strb r3, [r7]\n\ + movs r5, 0x1\n\ +_08130E72:\n\ + adds r4, 0x2\n\ + adds r3, 0x1\n\ + cmp r3, 0x3\n\ + ble _08130E30\n\ + bl Random\n\ + lsls r0, 16\n\ + lsrs r0, 16\n\ + adds r1, r5, 0\n\ + bl __modsi3\n\ + add r0, sp\n\ + adds r0, 0x14\n\ + ldrb r0, [r0]\n\ + ldr r7, [sp, 0x20]\n\ + strb r0, [r7]\n\ + ldrb r2, [r6]\n\ + mov r0, r10\n\ + strh r2, [r0]\n\ + ldr r0, =gUnknown_0203AB3C\n\ + ldrb r1, [r0]\n\ + movs r0, 0x2\n\ + eors r0, r1\n\ + cmp r8, r0\n\ + bne _08130EAE\n\ + cmp r2, 0x63\n\ + bgt _08130EAE\n\ + ldr r0, =0x0000ffff\n\ + mov r1, r10\n\ + strh r0, [r1]\n\ +_08130EAE:\n\ + ldr r2, [sp, 0x20]\n\ + adds r2, 0x1\n\ + str r2, [sp, 0x20]\n\ + movs r7, 0x2\n\ + add r10, r7\n\ + movs r0, 0x1\n\ + add r8, r0\n\ + mov r1, r8\n\ + cmp r1, 0x3\n\ + bgt _08130EC4\n\ + b _08130D14\n\ +_08130EC4:\n\ + mov r0, sp\n\ + ldrh r5, [r0]\n\ + movs r0, 0\n\ + ldr r2, [sp, 0x18]\n\ + strb r0, [r2]\n\ + movs r4, 0x1\n\ + mov r8, r4\n\ + ldr r6, =gUnknown_0202420C\n\ + ldr r3, [sp, 0x18]\n\ + mov r1, sp\n\ + adds r1, 0x2\n\ +_08130EDA:\n\ + lsls r0, r5, 16\n\ + asrs r2, r0, 16\n\ + movs r7, 0\n\ + ldrsh r0, [r1, r7]\n\ + cmp r2, r0\n\ + bne _08130EEE\n\ + adds r0, r3, r4\n\ + mov r7, r8\n\ + strb r7, [r0]\n\ + adds r4, 0x1\n\ +_08130EEE:\n\ + movs r7, 0\n\ + ldrsh r0, [r1, r7]\n\ + cmp r2, r0\n\ + bge _08130EFE\n\ + ldrh r5, [r1]\n\ + mov r0, r8\n\ + strb r0, [r3]\n\ + movs r4, 0x1\n\ +_08130EFE:\n\ + adds r1, 0x2\n\ + movs r2, 0x1\n\ + add r8, r2\n\ + mov r7, r8\n\ + cmp r7, 0x3\n\ + ble _08130EDA\n\ + bl Random\n\ + lsls r0, 16\n\ + lsrs r0, 16\n\ + adds r1, r4, 0\n\ + bl __modsi3\n\ + ldr r1, [sp, 0x18]\n\ + adds r0, r1, r0\n\ + ldrb r0, [r0]\n\ + strb r0, [r6]\n\ + ldrb r0, [r6]\n\ + ldr r2, [sp, 0x1C]\n\ + adds r0, r2, r0\n\ + ldrb r0, [r0]\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 {r1}\n\ + bx r1\n\ + .pool\n\ + .syntax divided\n"); +} +#endif + +void BattleAI_DoAIProcessing(void) +{ + while (gUnknown_020244A8->unk14->unk0 != 2) + { + switch (gUnknown_020244A8->unk14->unk0) + { + case 3: //Needed to match. + break; + case 0: + gAIScriptPtr = gUnknown_082DBEF8[gUnknown_020244A8->unk14->unk11]; + if (gBattleMons[gUnknown_0203AB3C].pp[gUnknown_020244A8->unk14->unk1] == 0) + { + gUnknown_020244A8->unk14->unk2 = 0; + } + else + { + gUnknown_020244A8->unk14->unk2 = gBattleMons[gUnknown_0203AB3C].moves[gUnknown_020244A8->unk14->unk1]; + } + gUnknown_020244A8->unk14->unk0++; + break; + case 1: + if (gUnknown_020244A8->unk14->unk2 != 0) + gUnknown_085B083C[*gAIScriptPtr](); + else + { + gUnknown_020244A8->unk14->unk4[gUnknown_020244A8->unk14->unk1] = 0; + gUnknown_020244A8->unk14->unk10 |= 1; + } + if (gUnknown_020244A8->unk14->unk10 & 1) + { + gUnknown_020244A8->unk14->unk1++; + if (gUnknown_020244A8->unk14->unk1 < 4 && !(gUnknown_020244A8->unk14->unk10 & 8)) + gUnknown_020244A8->unk14->unk0 = 0; + else + gUnknown_020244A8->unk14->unk0++; + gUnknown_020244A8->unk14->unk10 &= 0xFE; + } + break; + } + } +} + +void sub_8131074(void) +{ + s32 i; + + for (i = 0; i < 4; i++) + { + if (gUnknown_020244A8->unk18->unk0[gUnknown_0202420C][i] == gUnknown_02024248[gUnknown_0202420C]) + break; + if (gUnknown_020244A8->unk18->unk0[gUnknown_0202420C][i] != gUnknown_02024248[gUnknown_0202420C] //HACK: This redundant condition is a hack to make the asm match. + && gUnknown_020244A8->unk18->unk0[gUnknown_0202420C][i] == 0) + { + gUnknown_020244A8->unk18->unk0[gUnknown_0202420C][i] = gUnknown_02024248[gUnknown_0202420C]; + break; + } + } +} + +void sub_81310F0(u8 a) +{ + s32 i; + + for (i = 0; i < 4; i++) + gUnknown_020244A8->unk18->unk0[a][i] = 0; +} + +void b_history__record_ability_usage_of_player(u8 a, u8 b) +{ + gUnknown_020244A8->unk18->unk40[a] = b; +} + +void sub_8131130(u8 a) +{ + gUnknown_020244A8->unk18->unk40[a] = 0; +} + +void b_history__record_item_x12_of_player(u8 a, u8 b) +{ + gUnknown_020244A8->unk18->unk44[a] = b; +} + +void sub_8131160(u8 a) +{ + gUnknown_020244A8->unk18->unk44[a] = 0; +} + +void BattleAICmd_if_random(void) +{ + u16 random = Random(); + + if ((random & 0xFF) < gAIScriptPtr[1]) + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 2); + else + gAIScriptPtr += 6; +} -- cgit v1.2.3 From 8f9ed6e585a361e957650b871fc56a0406c2dac8 Mon Sep 17 00:00:00 2001 From: YamaArashi Date: Thu, 2 Feb 2017 16:30:08 -0800 Subject: decompile rng --- src/rng.c | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 src/rng.c (limited to 'src') diff --git a/src/rng.c b/src/rng.c new file mode 100644 index 000000000..9e473ef62 --- /dev/null +++ b/src/rng.c @@ -0,0 +1,35 @@ +#include "global.h" +#include "rng.h" + +// The number 1103515245 comes from the example implementation of rand and srand +// in the ISO C standard. + +extern u32 gRngValue; +extern u32 gRng2Value; + +EWRAM_DATA u8 sUnknown = 0; +EWRAM_DATA u32 sRandCount = 0; + +u16 Random() +{ + gRngValue = 1103515245 * gRngValue + 24691; + sRandCount++; + return gRngValue >> 16; +} + +void SeedRng(u16 seed) +{ + gRngValue = seed; + sUnknown = 0; +} + +void SeedRng2(u16 seed) +{ + gRng2Value = seed; +} + +u16 Random2(void) +{ + gRng2Value = 1103515245 * gRng2Value + 24691; + return gRng2Value >> 16; +} -- cgit v1.2.3 From ae1f731e60360437044c724675627c56bf404f25 Mon Sep 17 00:00:00 2001 From: YamaArashi Date: Fri, 3 Feb 2017 09:32:51 -0800 Subject: add missing 'static' --- src/rng.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/rng.c b/src/rng.c index 9e473ef62..6f4f2ce55 100644 --- a/src/rng.c +++ b/src/rng.c @@ -7,8 +7,8 @@ extern u32 gRngValue; extern u32 gRng2Value; -EWRAM_DATA u8 sUnknown = 0; -EWRAM_DATA u32 sRandCount = 0; +EWRAM_DATA static u8 sUnknown = 0; +EWRAM_DATA static u32 sRandCount = 0; u16 Random() { -- cgit v1.2.3 From e2b834d21d96332c5bcf788b390a09e285c7a5cb Mon Sep 17 00:00:00 2001 From: YamaArashi Date: Fri, 3 Feb 2017 16:44:06 -0800 Subject: begin decompiling main.s --- src/main.c | 380 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 380 insertions(+) create mode 100644 src/main.c (limited to 'src') diff --git a/src/main.c b/src/main.c new file mode 100644 index 000000000..ff28b1e84 --- /dev/null +++ b/src/main.c @@ -0,0 +1,380 @@ +#include "global.h" +#include "main.h" +#include "gba/flash_internal.h" +#include "gba/m4a_internal.h" + +extern struct SoundInfo gSoundInfo; +extern u32 gFlashMemoryPresent; +extern u32 IntrMain[]; +extern u8 gHeap[]; +extern struct SaveBlock2 gUnknown_02024A54; +extern char *gUnknown_03005D94; +extern char gUnknown_02029808[]; +extern u32 gUnknown_0203CF5C; + +void Timer3Intr(void); +bool8 HandleLinkConnection(void); +void c2_copyright_1(void); + +static void VBlankIntr(void); +static void HBlankIntr(void); +static void VCountIntr(void); +static void SerialIntr(void); +static void IntrDummy(void); + + +const u8 gGameVersion = VERSION_EMERALD; + +const u8 gGameLanguage = GAME_LANGUAGE; // English + +const char BuildDateTime[] = "2005 02 21 11:10"; + +const IntrFunc gIntrTableTemplate[] = +{ + VCountIntr, // V-count interrupt + SerialIntr, // Serial interrupt + Timer3Intr, // Timer 3 interrupt + HBlankIntr, // H-blank interrupt + VBlankIntr, // V-blank interrupt + IntrDummy, // Timer 0 interrupt + IntrDummy, // Timer 1 interrupt + IntrDummy, // Timer 2 interrupt + IntrDummy, // DMA 0 interrupt + IntrDummy, // DMA 1 interrupt + IntrDummy, // DMA 2 interrupt + IntrDummy, // DMA 3 interrupt + IntrDummy, // Key interrupt + IntrDummy, // Game Pak interrupt +}; + +#define INTR_COUNT ((int)(sizeof(gIntrTableTemplate)/sizeof(IntrFunc))) + +extern u16 gUnknown_03000000; + +extern u16 gKeyRepeatStartDelay; +extern u8 gUnknown_030022B4; +extern struct Main gMain; +extern u16 gKeyRepeatContinueDelay; +extern u8 gSoftResetDisabled; +extern IntrFunc gIntrTable[INTR_COUNT]; +extern bool8 gLinkVSyncDisabled; +extern u32 IntrMain_Buffer[0x200]; +extern u8 gPcmDmaCounter; + +extern u16 gTrainerId; + +EWRAM_DATA void (**gFlashTimerIntrFunc)(void) = NULL; + +static void UpdateLinkAndCallCallbacks(void); +static void InitMainCallbacks(void); +static void CallCallbacks(void); +static void SeedRngWithRtc(void); +static void ReadKeys(void); +static void InitIntrHandlers(void); +static void WaitForVBlank(void); + +#define B_START_SELECT (B_BUTTON | START_BUTTON | SELECT_BUTTON) + +void AgbMain() +{ + RegisterRamReset(RESET_ALL); + *(vu16 *)BG_PLTT = 0x7FFF; + InitGpuRegManager(); + REG_WAITCNT = WAITCNT_PREFETCH_ENABLE | WAITCNT_WS0_S_1 | WAITCNT_WS0_N_3; + InitKeys(); + InitIntrHandlers(); + m4aSoundInit(); + EnableVCountIntrAtLine150(); + sub_800E6D0(); + RtcInit(); + CheckForFlashMemory(); + InitMainCallbacks(); + InitMapMusic(); + ClearDma3Requests(); + ResetBgs(); + SetDefaultFontsPointer(); + InitHeap(gHeap, 0x1C000); + + gSoftResetDisabled = FALSE; + + if (gFlashMemoryPresent != TRUE) + SetMainCallback2(NULL); + + gUnknown_030022B4 = 0; + gUnknown_03000000 = 0xFC0; + + for (;;) + { + ReadKeys(); + + if (gSoftResetDisabled == FALSE + && (gMain.heldKeysRaw & A_BUTTON) + && (gMain.heldKeysRaw & B_START_SELECT) == B_START_SELECT) + { + rfu_REQ_stopMode(); + rfu_waitREQComplete(); + DoSoftReset(); + } + + if (sub_8087634() == 1) + { + gUnknown_030022B4 = 1; + UpdateLinkAndCallCallbacks(); + gUnknown_030022B4 = 0; + } + else + { + gUnknown_030022B4 = 0; + UpdateLinkAndCallCallbacks(); + + if (sub_80875C8() == 1) + { + gMain.newKeys = 0; + ClearObjectCopyRequests(); + gUnknown_030022B4 = 1; + UpdateLinkAndCallCallbacks(); + gUnknown_030022B4 = 0; + } + } + + PlayTimeCounter_Update(); + MapMusicMain(); + WaitForVBlank(); + } +} + +static void UpdateLinkAndCallCallbacks(void) +{ + if (!HandleLinkConnection()) + CallCallbacks(); +} + +static void InitMainCallbacks(void) +{ + gMain.vblankCounter1 = 0; + gUnknown_0203CF5C = 0; + gMain.vblankCounter2 = 0; + gMain.callback1 = NULL; + SetMainCallback2(c2_copyright_1); + gSaveBlock2Ptr = &gUnknown_02024A54; + gUnknown_03005D94 = gUnknown_02029808; +} + +static void CallCallbacks(void) +{ + if (gMain.callback1) + gMain.callback1(); + + if (gMain.callback2) + gMain.callback2(); +} + +void SetMainCallback2(MainCallback callback) +{ + gMain.callback2 = callback; + gMain.state = 0; +} + +void StartTimer1(void) +{ + REG_TM1CNT_H = 0x80; +} + +void SeedRngAndSetTrainerId(void) +{ + u16 val = REG_TM1CNT_L; + SeedRng(val); + REG_TM1CNT_H = 0; + gTrainerId = val; +} + +u16 GetTrainerId(void) +{ + return gTrainerId; +} + +/* +void InitKeys(void) +{ + gKeyRepeatContinueDelay = 5; + gKeyRepeatStartDelay = 40; + + gMain.heldKeys = 0; + gMain.newKeys = 0; + gMain.newAndRepeatedKeys = 0; + gMain.heldKeysRaw = 0; + gMain.newKeysRaw = 0; +} + +static void ReadKeys(void) +{ + u16 keyInput = REG_KEYINPUT ^ KEYS_MASK; + gMain.newKeysRaw = keyInput & ~gMain.heldKeysRaw; + gMain.newKeys = gMain.newKeysRaw; + gMain.newAndRepeatedKeys = gMain.newKeysRaw; + + // BUG: Key repeat won't work when pressing L using L=A button mode + // because it compares the raw key input with the remapped held keys. + // Note that newAndRepeatedKeys is never remapped either. + + if (keyInput != 0 && gMain.heldKeys == keyInput) + { + gMain.keyRepeatCounter--; + + if (gMain.keyRepeatCounter == 0) + { + gMain.newAndRepeatedKeys = keyInput; + gMain.keyRepeatCounter = gKeyRepeatContinueDelay; + } + } + else + { + // If there is no input or the input has changed, reset the counter. + gMain.keyRepeatCounter = gKeyRepeatStartDelay; + } + + gMain.heldKeysRaw = keyInput; + gMain.heldKeys = gMain.heldKeysRaw; + + // Remap L to A if the L=A option is enabled. + if (gSaveBlock2.optionsButtonMode == 2) + { + if (gMain.newKeys & L_BUTTON) + gMain.newKeys |= A_BUTTON; + + if (gMain.heldKeys & L_BUTTON) + gMain.heldKeys |= A_BUTTON; + } + + if (gMain.newKeys & gMain.watchedKeysMask) + gMain.watchedKeysPressed = TRUE; +} + +static void InitIntrHandlers(void) +{ + int i; + + for (i = 0; i < INTR_COUNT; i++) + gIntrTable[i] = gIntrTableTemplate[i]; + + DmaCopy32(3, IntrMain, IntrMain_Buffer, sizeof(IntrMain_Buffer)); + + INTR_VECTOR = IntrMain_Buffer; + + SetVBlankCallback(NULL); + SetHBlankCallback(NULL); + SetSerialCallback(NULL); + + REG_IME = 1; + REG_IE = INTR_FLAG_VBLANK; + REG_DISPSTAT = DISPSTAT_VBLANK_INTR; + REG_IE |= INTR_FLAG_VBLANK; +} + +void SetVBlankCallback(IntrCallback callback) +{ + gMain.vblankCallback = callback; +} + +void SetHBlankCallback(IntrCallback callback) +{ + gMain.hblankCallback = callback; +} + +void SetVCountCallback(IntrCallback callback) +{ + gMain.vcountCallback = callback; +} + +void SetSerialCallback(IntrCallback callback) +{ + gMain.serialCallback = callback; +} + +static void VBlankIntr(void) +{ + u16 savedIme; + + if (!gLinkVSyncDisabled) + LinkVSync(); + + savedIme = REG_IME; + REG_IME = 0; + m4aSoundVSync(); + REG_IME = savedIme; + + gMain.vblankCounter1++; + + if (gMain.vblankCallback) + gMain.vblankCallback(); + + gMain.vblankCounter2++; + + gPcmDmaCounter = gSoundInfo.pcmDmaCounter; + + m4aSoundMain(); + sub_800C35C(); + Random(); + + INTR_CHECK |= INTR_FLAG_VBLANK; + gMain.intrCheck |= INTR_FLAG_VBLANK; +} + +void InitFlashTimer(void) +{ + SetFlashTimerIntr(2, gFlashTimerIntrFunc); +} + +static void HBlankIntr(void) +{ + if (gMain.hblankCallback) + gMain.hblankCallback(); + + INTR_CHECK |= INTR_FLAG_HBLANK; + gMain.intrCheck |= INTR_FLAG_HBLANK; +} + +static void VCountIntr(void) +{ + if (gMain.vcountCallback) + gMain.vcountCallback(); + + INTR_CHECK |= INTR_FLAG_VCOUNT; + gMain.intrCheck |= INTR_FLAG_VCOUNT; +} + +static void SerialIntr(void) +{ + if (gMain.serialCallback) + gMain.serialCallback(); + + INTR_CHECK |= INTR_FLAG_SERIAL; + gMain.intrCheck |= INTR_FLAG_SERIAL; +} + +static void IntrDummy(void) +{} + +static void WaitForVBlank(void) +{ + gMain.intrCheck &= ~INTR_FLAG_VBLANK; + VBlankIntrWait(); +} + +void DoSoftReset(void) +{ + REG_IME = 0; + m4aSoundVSyncOff(); + remove_some_task(); + DmaStop(1); + DmaStop(2); + DmaStop(3); + SiiRtcProtect(); + SoftReset(RESET_ALL); +} + +void ClearPokemonCrySongs(void) +{ + CpuFill16(0, gPokemonCrySongs, MAX_POKEMON_CRIES * sizeof(struct PokemonCrySong)); +} +*/ \ No newline at end of file -- cgit v1.2.3 From 689df5cff8386d85f1f1da1fc332db18d282f928 Mon Sep 17 00:00:00 2001 From: ProjectRevoTPP Date: Fri, 3 Feb 2017 21:34:56 -0500 Subject: finish decompiling battle_ai.c (#16) * partially decompile battle_ai.c up to tai60_unk * nonmatching tai60_unk * decompile more of battle_ai.c * formatting * finish porting battle_ai.c * formatting --- src/battle_ai.c | 2291 ++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 2170 insertions(+), 121 deletions(-) (limited to 'src') diff --git a/src/battle_ai.c b/src/battle_ai.c index 7f020fd75..8f3b7cf1e 100644 --- a/src/battle_ai.c +++ b/src/battle_ai.c @@ -1,10 +1,43 @@ #include "global.h" +#include "pokemon.h" +#include "battle.h" +#include "species.h" +#include "abilities.h" #define AIScriptRead32(ptr) ((ptr)[0] | (ptr)[1] << 8 | (ptr)[2] << 16 | (ptr)[3] << 24) #define AIScriptRead16(ptr) ((ptr)[0] | (ptr)[1] << 8) #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_ACTION_UNK1 0x0001 +#define AI_ACTION_UNK2 0x0002 +#define AI_ACTION_UNK3 0x0004 +#define AI_ACTION_UNK4 0x0008 +#define AI_ACTION_UNK5 0x0010 +#define AI_ACTION_UNK6 0x0020 +#define AI_ACTION_UNK7 0x0040 +#define AI_ACTION_UNK8 0x0080 + +enum +{ + TARGET, + USER +}; + +// AI states +enum +{ + AIState_SettingUp, + AIState_Processing, + AIState_FinishedProcessing, + AIState_DoNotProcess +}; + //Copied from pokeruby -- hopefully the same struct Trainer { @@ -62,16 +95,16 @@ struct BattlePokemon }; //size should be 0x1C -struct UnknownStruct3 +struct AI_ThinkingStruct { - u8 unk0; - u8 unk1; - u16 unk2; - s8 unk4[4]; - u8 filler8[4]; - u32 unkC; - u8 unk10; - u8 unk11; + u8 aiState; + u8 movesetIndex; + u16 moveConsidered; + s8 score[4]; + u32 funcResult; + u32 aiFlags; + u8 aiAction; + u8 aiLogicId; u8 filler12[6]; u8 unk18[4]; }; @@ -80,7 +113,8 @@ struct UnknownStruct3 struct UnknownStruct2 { u16 unk0[2][8]; - u8 filler20[0x20]; + u8 unk20[2]; + u8 filler20[0x1E]; u8 unk40[4]; u8 unk44[4]; u16 unk48[4]; @@ -89,35 +123,88 @@ struct UnknownStruct2 struct UnknownStruct4 { - u8 filler0[0x20]; + u8 *ptr[8]; u8 unk20; }; +struct SimpleUnknownStruct +{ + u32 unkArray[4]; // unknown size +}; + struct UnknownStruct1 { u8 unk0; - u8 filler1[0x13]; - struct UnknownStruct3 *unk14; + u8 filler1[0x3]; + struct SimpleUnknownStruct *unk4; + u8 filler8[0xC]; + struct AI_ThinkingStruct *ai; struct UnknownStruct2 *unk18; struct UnknownStruct4 *unk1C; }; +struct UnknownStruct5 +{ + u8 filler0[0x3]; + u16 unk4; + u16 unk6; + u8 unk8; + u8 unk9; + u8 fillerA[0x9]; + u8 taunt:4; + u8 unkC:4; + u8 fillerD[0x2]; + u8 unk16; + u8 filler17[0x4]; +}; + +extern struct UnknownStruct5 gUnknown_020242BC[]; + +/* +gAIScriptPtr is a pointer to the next battle AI cmd command to read. +when a command finishes processing, gAIScriptPtr is incremented by +the number of bytes that the current command had reserved for arguments +in order to read the next command correctly. refer to battle_ai_scripts.s for the +AI scripts. +*/ +extern u8 *gAIScriptPtr; + extern u32 gBattleTypeFlags; extern u8 gUnknown_02024064; extern struct BattlePokemon gBattleMons[]; extern u16 gUnknown_020241EA; -extern u8 gUnknown_0202420C; +extern u8 gEnemyMonIndex; extern u8 gUnknown_02024210; extern u16 gUnknown_02024248[]; extern u8 *gUnknown_0202449C; extern struct UnknownStruct1 *gUnknown_020244A8; extern u16 gUnknown_02038BCA; extern u16 gUnknown_02038BCC; -extern const u8 *gAIScriptPtr; -extern u8 gUnknown_0203AB3C; +extern u8 gPlayerMonIndex; extern struct Trainer gTrainers[]; extern const u32 gBitTable[]; -extern const u8 *const gUnknown_082DBEF8[]; +extern u8 *gUnknown_082DBEF8[]; +extern u32 gUnknown_020242AC[]; +extern u16 gUnknown_0202428E[]; +extern struct BattleMove gBattleMoves[]; +extern u8 gUnknown_03005D10[]; +extern u8 gUnknown_0202406E[][2]; +extern struct BaseStats gBaseStats[]; +extern u16 gUnknown_02024400; +extern u8 gUnknown_02024474[]; +extern u8 gBattleMoveFlags; +extern int gBattleMoveDamage; +extern u8 gCritMultiplier; +extern u16 gBattleWeather; + +extern u8 battle_get_per_side_status(u8); +extern u8 b_first_side(u8, u8, u8); +extern u8 battle_get_side_with_given_state(u8); +extern void move_effectiveness_something(u16, u8, u8); +extern u8 itemid_get_x12(); +extern void b_mc_stack_push(u8 *); +extern bool8 b_mc_stack_pop_cursor(void); +extern void sub_8046E7C(u8, u8); typedef void (*BattleAICmdFunc)(void); @@ -125,12 +212,12 @@ extern const BattleAICmdFunc gUnknown_085B083C[]; extern u8 sub_803FECC(); extern u16 Random(); -extern u32 battle_side_get_owner(); +extern u8 battle_side_get_owner(); extern u32 sub_8186438(); extern u32 sub_81A6FB4(); void BattleAI_SetupAIData(u8 a); -u8 sub_8130BDC(void); +u8 BattleAI_GetAIActionToUse(void); u8 sub_8130CF4(void); void sub_8131074(void); void BattleAI_DoAIProcessing(void); @@ -160,58 +247,64 @@ void BattleAI_HandleItemUseBeforeAISetup(u8 a) void BattleAI_SetupAIData(u8 a) { s32 i; - u8 *data = (u8 *)gUnknown_020244A8->unk14; + u8 *data = (u8 *)AI_THINKING_STRUCT; u8 r6; - - for (i = 0; (u32)i < 0x1C; i++) + + // clear AI data. + for (i = 0; (u32)i < sizeof(struct AI_ThinkingStruct); i++) data[i] = 0; + + // conditional score reset, unlike Ruby. for (i = 0; i < 4; i++) { if (a & 1) - gUnknown_020244A8->unk14->unk4[i] = 100; + AI_THINKING_STRUCT->score[i] = 100; else - gUnknown_020244A8->unk14->unk4[i] = 0; + AI_THINKING_STRUCT->score[i] = 0; a >>= 1; } + r6 = sub_803FECC(gUnknown_02024064, 0, 0xFF); + for (i = 0; i < 4; i++) { if (gBitTable[i] & r6) - gUnknown_020244A8->unk14->unk4[i] = 0; - gUnknown_020244A8->unk14->unk18[i] = 100 - (Random() % 16); + AI_THINKING_STRUCT->score[i] = 0; + + AI_THINKING_STRUCT->unk18[i] = 100 - (Random() % 16); } gUnknown_020244A8->unk1C->unk20 = 0; - gUnknown_0203AB3C = gUnknown_02024064; + gPlayerMonIndex = gUnknown_02024064; if (gBattleTypeFlags & 1) { - gUnknown_0202420C = (Random() & 2) + (battle_side_get_owner(gUnknown_02024064) ^ 1); - if (gUnknown_02024210 & gBitTable[gUnknown_0202420C]) - gUnknown_0202420C ^= 2; + gEnemyMonIndex = (Random() & 2) + ((u32)battle_side_get_owner(gUnknown_02024064) ^ 1); + if (gUnknown_02024210 & gBitTable[gEnemyMonIndex]) + gEnemyMonIndex ^= 2; } else { //_08130A60 - gUnknown_0202420C = gUnknown_0203AB3C ^ 1; + gEnemyMonIndex = gPlayerMonIndex ^ 1; } //_08130A68 if (gBattleTypeFlags & 0x1000000) - gUnknown_020244A8->unk14->unkC = sub_8186438(); + AI_THINKING_STRUCT->aiFlags = sub_8186438(); else if (gBattleTypeFlags & 0x80) - gUnknown_020244A8->unk14->unkC = 0x40000000; + AI_THINKING_STRUCT->aiFlags = 0x40000000; else if (gBattleTypeFlags & 0x400) - gUnknown_020244A8->unk14->unkC = 0x20000000; + AI_THINKING_STRUCT->aiFlags = 0x20000000; else if (gBattleTypeFlags & 0x10) - gUnknown_020244A8->unk14->unkC = 0x80000000; + AI_THINKING_STRUCT->aiFlags = 0x80000000; else if (gBattleTypeFlags & 0x80000) - gUnknown_020244A8->unk14->unkC = sub_81A6FB4(); + AI_THINKING_STRUCT->aiFlags = sub_81A6FB4(); else if (gBattleTypeFlags & 0x0C3F0900) - gUnknown_020244A8->unk14->unkC = 7; + AI_THINKING_STRUCT->aiFlags = 7; else if (gBattleTypeFlags & 0x8000) - gUnknown_020244A8->unk14->unkC = gTrainers[gUnknown_02038BCA].aiFlags | gTrainers[gUnknown_02038BCC].aiFlags; + AI_THINKING_STRUCT->aiFlags = gTrainers[gUnknown_02038BCA].aiFlags | gTrainers[gUnknown_02038BCC].aiFlags; else - gUnknown_020244A8->unk14->unkC = gTrainers[gUnknown_02038BCA].aiFlags; + AI_THINKING_STRUCT->aiFlags = gTrainers[gUnknown_02038BCA].aiFlags; if (gBattleTypeFlags & 1) - gUnknown_020244A8->unk14->unkC |= 0x80; + AI_THINKING_STRUCT->aiFlags |= 0x80; } u8 sub_8130BA4(void) @@ -220,60 +313,64 @@ u8 sub_8130BA4(void) u8 ret; if (!(gBattleTypeFlags & 1)) - ret = sub_8130BDC(); + ret = BattleAI_GetAIActionToUse(); else ret = sub_8130CF4(); + gUnknown_020241EA = r4; return ret; } -u8 sub_8130BDC(void) +u8 BattleAI_GetAIActionToUse(void) { - u8 r6; + u8 currentMoveArray[4]; + u8 consideredMoveArray[4]; + u8 numOfBestMoves; s32 i; - u8 arr1[4]; - u8 arr2[4]; sub_8131074(); - while (gUnknown_020244A8->unk14->unkC != 0) + + while (AI_THINKING_STRUCT->aiFlags != 0) { - if (gUnknown_020244A8->unk14->unkC & 1) + if (AI_THINKING_STRUCT->aiFlags & 1) { - gUnknown_020244A8->unk14->unk0 = 0; + AI_THINKING_STRUCT->aiState = AIState_SettingUp; BattleAI_DoAIProcessing(); } - gUnknown_020244A8->unk14->unkC >>= 1; - gUnknown_020244A8->unk14->unk11++; - gUnknown_020244A8->unk14->unk1 = 0; + AI_THINKING_STRUCT->aiFlags >>= 1; + AI_THINKING_STRUCT->aiLogicId++; + AI_THINKING_STRUCT->movesetIndex = 0; } - //_08130C2C - if (gUnknown_020244A8->unk14->unk10 & 2) + + // special flags for safari watch/flee. + if (AI_THINKING_STRUCT->aiAction & 2) return 4; - if (gUnknown_020244A8->unk14->unk10 & 4) + if (AI_THINKING_STRUCT->aiAction & 4) return 5; - r6 = 1; - arr1[0] = gUnknown_020244A8->unk14->unk4[0]; - arr2[0] = 0; + + numOfBestMoves = 1; + currentMoveArray[0] = AI_THINKING_STRUCT->score[0]; + consideredMoveArray[0] = 0; + for (i = 1; i < 4; i++) { - if (gBattleMons[gUnknown_0203AB3C].moves[i] != 0) + if (gBattleMons[gPlayerMonIndex].moves[i] != 0) // emerald adds an extra move ID check for some reason. { - if (arr1[0] == gUnknown_020244A8->unk14->unk4[i]) + // in ruby, the order of these if statements are reversed. + if (currentMoveArray[0] == AI_THINKING_STRUCT->score[i]) { - arr1[r6] = gUnknown_020244A8->unk14->unk4[i]; - arr2[r6++] = i; + currentMoveArray[numOfBestMoves] = AI_THINKING_STRUCT->score[i]; + consideredMoveArray[numOfBestMoves++] = i; } - //_08130CAA - if (arr1[0] < gUnknown_020244A8->unk14->unk4[i]) + if (currentMoveArray[0] < AI_THINKING_STRUCT->score[i]) { - r6 = 1; - arr1[0] = gUnknown_020244A8->unk14->unk4[i]; - arr2[0] = i; + numOfBestMoves = 1; + currentMoveArray[0] = AI_THINKING_STRUCT->score[i]; + consideredMoveArray[0] = i; } } - //_08130CC6 } - return arr2[Random() % r6]; + return consideredMoveArray[Random() % numOfBestMoves]; } #ifdef NONMATCHING @@ -297,7 +394,7 @@ u8 sub_8130CF4(void) for (i = 0; i < 4; i++) //_08130D14 { - if (i == gUnknown_0203AB3C || gBattleMons[i].hp == 0) + if (i == gPlayerMonIndex || gBattleMons[i].hp == 0) { //_08130D2E spC[i] = -1; @@ -311,48 +408,48 @@ u8 sub_8130CF4(void) else BattleAI_SetupAIData(0xF); //_08130D76 - gUnknown_0202420C = i; - if ((i & 1) != (gUnknown_0203AB3C & 1)) + gEnemyMonIndex = i; + if ((i & 1) != (gPlayerMonIndex & 1)) sub_8131074(); //_08130D90 - gUnknown_020244A8->unk14->unk11 = 0; - gUnknown_020244A8->unk14->unk1 = 0; - r4 = gUnknown_020244A8->unk14->unkC; + AI_THINKING_STRUCT->unk11 = 0; + AI_THINKING_STRUCT->unk1 = 0; + r4 = AI_THINKING_STRUCT->aiFlags; while (r4 != 0) { if (r4 & 1) { - gUnknown_020244A8->unk14->unk0 = 0; + AI_THINKING_STRUCT->aiState = AIState_SettingUp; BattleAI_DoAIProcessing(); } r4 >>= 1; - gUnknown_020244A8->unk14->unk11++; - gUnknown_020244A8->unk14->unk1 = 0; + AI_THINKING_STRUCT->unk11++; + AI_THINKING_STRUCT->unk1 = 0; } //_08130DD8 - if (gUnknown_020244A8->unk14->unk10 & 2) + if (AI_THINKING_STRUCT->unk10 & 2) spC[i] = 4; - else if (gUnknown_020244A8->unk14->unk10 & 4) + else if (AI_THINKING_STRUCT->unk10 & 4) spC[i] = 5; else { //_08130E10 - sp10[0] = gUnknown_020244A8->unk14->unk4[0]; + sp10[0] = AI_THINKING_STRUCT->score[0]; sp14[0] = 0; r5 = 1; for (j = 1; j < 4; j++) { - if (gBattleMons[gUnknown_0203AB3C].moves[j] != 0) + if (gBattleMons[gPlayerMonIndex].moves[j] != 0) { - if (sp10[0] == gUnknown_020244A8->unk14->unk4[j]) + if (sp10[0] == AI_THINKING_STRUCT->score[j]) { - sp10[r5] = gUnknown_020244A8->unk14->unk4[j]; + sp10[r5] = AI_THINKING_STRUCT->score[j]; sp14[r5] = j; r5++; } - if (sp10[0] < gUnknown_020244A8->unk14->unk4[j]) + if (sp10[0] < AI_THINKING_STRUCT->score[j]) { - sp10[0] = gUnknown_020244A8->unk14->unk4[j]; + sp10[0] = AI_THINKING_STRUCT->score[j]; sp14[0] = j; r5 = 1; } @@ -362,7 +459,7 @@ u8 sub_8130CF4(void) spC[i] = sp14[Random() % r5]; //asm("":::"r3"); sp0[i] = sp10[0]; - if (i == (gUnknown_0203AB3C ^ 2) && sp0[i] < 100) + if (i == (gPlayerMonIndex ^ 2) && sp0[i] < 100) sp0[i] = -1; } } @@ -391,8 +488,8 @@ u8 sub_8130CF4(void) r4_2 = 1; } } - gUnknown_0202420C = sp8[Random() % r4_2]; - return spC[gUnknown_0202420C]; + gEnemyMonIndex = sp8[Random() % r4_2]; + return spC[gEnemyMonIndex]; } #else __attribute__((naked)) @@ -416,7 +513,7 @@ u8 sub_8130CF4(void) str r1, [sp, 0x20]\n\ mov r10, sp\n\ _08130D14:\n\ - ldr r0, =gUnknown_0203AB3C\n\ + ldr r0, =gPlayerMonIndex\n\ ldrb r0, [r0]\n\ cmp r8, r0\n\ beq _08130D2E\n\ @@ -458,13 +555,13 @@ _08130D70:\n\ movs r0, 0xF\n\ bl BattleAI_SetupAIData\n\ _08130D76:\n\ - ldr r0, =gUnknown_0202420C\n\ + ldr r0, =gEnemyMonIndex\n\ mov r1, r8\n\ strb r1, [r0]\n\ movs r1, 0x1\n\ mov r2, r8\n\ ands r2, r1\n\ - ldr r0, =gUnknown_0203AB3C\n\ + ldr r0, =gPlayerMonIndex\n\ ldrb r0, [r0]\n\ ands r1, r0\n\ cmp r2, r1\n\ @@ -542,7 +639,7 @@ _08130E10:\n\ movs r5, 0x1\n\ movs r3, 0x1\n\ adds r6, r1, 0\n\ - ldr r0, =gUnknown_0203AB3C\n\ + ldr r0, =gPlayerMonIndex\n\ ldrb r1, [r0]\n\ movs r0, 0x58\n\ muls r0, r1\n\ @@ -603,7 +700,7 @@ _08130E72:\n\ ldrb r2, [r6]\n\ mov r0, r10\n\ strh r2, [r0]\n\ - ldr r0, =gUnknown_0203AB3C\n\ + ldr r0, =gPlayerMonIndex\n\ ldrb r1, [r0]\n\ movs r0, 0x2\n\ eors r0, r1\n\ @@ -634,7 +731,7 @@ _08130EC4:\n\ strb r0, [r2]\n\ movs r4, 0x1\n\ mov r8, r4\n\ - ldr r6, =gUnknown_0202420C\n\ + ldr r6, =gEnemyMonIndex\n\ ldr r3, [sp, 0x18]\n\ mov r1, sp\n\ adds r1, 0x2\n\ @@ -693,40 +790,42 @@ _08130EFE:\n\ void BattleAI_DoAIProcessing(void) { - while (gUnknown_020244A8->unk14->unk0 != 2) + while (AI_THINKING_STRUCT->aiState != AIState_FinishedProcessing) { - switch (gUnknown_020244A8->unk14->unk0) + switch (AI_THINKING_STRUCT->aiState) { - case 3: //Needed to match. + case AIState_DoNotProcess: //Needed to match. break; - case 0: - gAIScriptPtr = gUnknown_082DBEF8[gUnknown_020244A8->unk14->unk11]; - if (gBattleMons[gUnknown_0203AB3C].pp[gUnknown_020244A8->unk14->unk1] == 0) + case AIState_SettingUp: + gAIScriptPtr = gUnknown_082DBEF8[AI_THINKING_STRUCT->aiLogicId]; // set AI ptr to logic ID. + if (gBattleMons[gPlayerMonIndex].pp[AI_THINKING_STRUCT->movesetIndex] == 0) { - gUnknown_020244A8->unk14->unk2 = 0; + AI_THINKING_STRUCT->moveConsidered = 0; } else { - gUnknown_020244A8->unk14->unk2 = gBattleMons[gUnknown_0203AB3C].moves[gUnknown_020244A8->unk14->unk1]; + AI_THINKING_STRUCT->moveConsidered = gBattleMons[gPlayerMonIndex].moves[AI_THINKING_STRUCT->movesetIndex]; } - gUnknown_020244A8->unk14->unk0++; + AI_THINKING_STRUCT->aiState++; break; - case 1: - if (gUnknown_020244A8->unk14->unk2 != 0) - gUnknown_085B083C[*gAIScriptPtr](); + case AIState_Processing: + if (AI_THINKING_STRUCT->moveConsidered != 0) + gUnknown_085B083C[*gAIScriptPtr](); // run AI command. else { - gUnknown_020244A8->unk14->unk4[gUnknown_020244A8->unk14->unk1] = 0; - gUnknown_020244A8->unk14->unk10 |= 1; + AI_THINKING_STRUCT->score[AI_THINKING_STRUCT->movesetIndex] = 0; + AI_THINKING_STRUCT->aiAction |= 1; } - if (gUnknown_020244A8->unk14->unk10 & 1) + if (AI_THINKING_STRUCT->aiAction & 1) { - gUnknown_020244A8->unk14->unk1++; - if (gUnknown_020244A8->unk14->unk1 < 4 && !(gUnknown_020244A8->unk14->unk10 & 8)) - gUnknown_020244A8->unk14->unk0 = 0; + AI_THINKING_STRUCT->movesetIndex++; + + if (AI_THINKING_STRUCT->movesetIndex < 4 && !(AI_THINKING_STRUCT->aiAction & 8)) + AI_THINKING_STRUCT->aiState = AIState_SettingUp; else - gUnknown_020244A8->unk14->unk0++; - gUnknown_020244A8->unk14->unk10 &= 0xFE; + AI_THINKING_STRUCT->aiState++; + + AI_THINKING_STRUCT->aiAction &= 0xFE; } break; } @@ -739,12 +838,12 @@ void sub_8131074(void) for (i = 0; i < 4; i++) { - if (gUnknown_020244A8->unk18->unk0[gUnknown_0202420C][i] == gUnknown_02024248[gUnknown_0202420C]) + if (gUnknown_020244A8->unk18->unk0[gEnemyMonIndex][i] == gUnknown_02024248[gEnemyMonIndex]) break; - if (gUnknown_020244A8->unk18->unk0[gUnknown_0202420C][i] != gUnknown_02024248[gUnknown_0202420C] //HACK: This redundant condition is a hack to make the asm match. - && gUnknown_020244A8->unk18->unk0[gUnknown_0202420C][i] == 0) + 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) { - gUnknown_020244A8->unk18->unk0[gUnknown_0202420C][i] = gUnknown_02024248[gUnknown_0202420C]; + gUnknown_020244A8->unk18->unk0[gEnemyMonIndex][i] = gUnknown_02024248[gEnemyMonIndex]; break; } } @@ -778,12 +877,1962 @@ void sub_8131160(u8 a) gUnknown_020244A8->unk18->unk44[a] = 0; } -void BattleAICmd_if_random(void) +static void BattleAICmd_if_random_less_than(void) { u16 random = Random(); - - if ((random & 0xFF) < gAIScriptPtr[1]) + + if (random % 256 < gAIScriptPtr[1]) + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 2); + else + gAIScriptPtr += 6; +} + +static void BattleAICmd_if_random_greater_than(void) +{ + u16 random = Random(); + + if (random % 256 > gAIScriptPtr[1]) + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 2); + else + gAIScriptPtr += 6; +} + +static void BattleAICmd_if_random_equal(void) +{ + u16 random = Random(); + + if (random % 256 == gAIScriptPtr[1]) + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 2); + else + gAIScriptPtr += 6; +} + +static void BattleAICmd_if_random_not_equal(void) +{ + u16 random = Random(); + + if (random % 256 != gAIScriptPtr[1]) + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 2); + else + gAIScriptPtr += 6; +} + +static void BattleAICmd_score(void) +{ + AI_THINKING_STRUCT->score[AI_THINKING_STRUCT->movesetIndex] += gAIScriptPtr[1]; // add the result to the array of the move consider's score. + + if (AI_THINKING_STRUCT->score[AI_THINKING_STRUCT->movesetIndex] < 0) // if the score is negative, flatten it to 0. + AI_THINKING_STRUCT->score[AI_THINKING_STRUCT->movesetIndex] = 0; + + gAIScriptPtr += 2; // AI return. +} + +static void BattleAICmd_if_hp_less_than(void) +{ + u16 index; + + if (gAIScriptPtr[1] == USER) + index = gPlayerMonIndex; + else + index = gEnemyMonIndex; + + if ((u32)(100 * gBattleMons[index].hp / gBattleMons[index].maxHP) < gAIScriptPtr[2]) + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 3); + else + gAIScriptPtr += 7; +} + +static void BattleAICmd_if_hp_more_than(void) +{ + u16 index; + + if (gAIScriptPtr[1] == USER) + index = gPlayerMonIndex; + else + index = gEnemyMonIndex; + + if ((u32)(100 * gBattleMons[index].hp / gBattleMons[index].maxHP) > gAIScriptPtr[2]) + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 3); + else + gAIScriptPtr += 7; +} + +static void BattleAICmd_if_hp_equal(void) +{ + u16 index; + + if (gAIScriptPtr[1] == USER) + index = gPlayerMonIndex; + else + index = gEnemyMonIndex; + + if ((u32)(100 * gBattleMons[index].hp / gBattleMons[index].maxHP) == gAIScriptPtr[2]) + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 3); + else + gAIScriptPtr += 7; +} + +static void BattleAICmd_if_hp_not_equal(void) +{ + u16 index; + + if (gAIScriptPtr[1] == USER) + index = gPlayerMonIndex; + else + index = gEnemyMonIndex; + + if ((u32)(100 * gBattleMons[index].hp / gBattleMons[index].maxHP) != gAIScriptPtr[2]) + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 3); + else + gAIScriptPtr += 7; +} + +static void BattleAICmd_if_status(void) +{ + u16 index; + u32 arg; + + if (gAIScriptPtr[1] == USER) + index = gPlayerMonIndex; + else + index = gEnemyMonIndex; + + arg = AIScriptRead32(gAIScriptPtr + 2); + + if ((gBattleMons[index].status1 & arg) != 0) + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 6); + else + gAIScriptPtr += 10; +} + +static void BattleAICmd_if_not_status(void) +{ + u16 index; + u32 arg; + + if (gAIScriptPtr[1] == USER) + index = gPlayerMonIndex; + else + index = gEnemyMonIndex; + + arg = AIScriptRead32(gAIScriptPtr + 2); + + if ((gBattleMons[index].status1 & arg) == 0) + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 6); + else + gAIScriptPtr += 10; +} + +static void BattleAICmd_if_status2(void) +{ + u16 index; + u32 arg; + + if (gAIScriptPtr[1] == USER) + index = gPlayerMonIndex; + else + index = gEnemyMonIndex; + + arg = AIScriptRead32(gAIScriptPtr + 2); + + if ((gBattleMons[index].status2 & arg) != 0) + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 6); + else + gAIScriptPtr += 10; +} + +static void BattleAICmd_if_not_status2(void) +{ + u16 index; + u32 arg; + + if (gAIScriptPtr[1] == USER) + index = gPlayerMonIndex; + else + index = gEnemyMonIndex; + + arg = AIScriptRead32(gAIScriptPtr + 2); + + if ((gBattleMons[index].status2 & arg) == 0) + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 6); + else + gAIScriptPtr += 10; +} + +static void BattleAICmd_if_status3(void) +{ + u16 index; + u32 arg; + + if (gAIScriptPtr[1] == USER) + index = gPlayerMonIndex; + else + index = gEnemyMonIndex; + + arg = AIScriptRead32(gAIScriptPtr + 2); + + if ((gUnknown_020242AC[index] & arg) != 0) + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 6); + else + gAIScriptPtr += 10; +} + +static void BattleAICmd_if_not_status3(void) +{ + u16 index; + u32 arg; + + if (gAIScriptPtr[1] == USER) + index = gPlayerMonIndex; + else + index = gEnemyMonIndex; + + arg = AIScriptRead32(gAIScriptPtr + 2); + + if ((gUnknown_020242AC[index] & arg) == 0) + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 6); + else + gAIScriptPtr += 10; +} + +static void BattleAICmd_if_status4(void) +{ + u16 index; + u32 arg1, arg2; + + if (gAIScriptPtr[1] == USER) + index = gPlayerMonIndex; + else + index = gEnemyMonIndex; + + arg1 = battle_get_per_side_status(index) & 1; + arg2 = AIScriptRead32(gAIScriptPtr + 2); + + if ((gUnknown_0202428E[arg1] & arg2) != 0) + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 6); + else + gAIScriptPtr += 10; +} + +static void BattleAICmd_if_not_status4(void) +{ + u16 index; + u32 arg1, arg2; + + if (gAIScriptPtr[1] == USER) + index = gPlayerMonIndex; + else + index = gEnemyMonIndex; + + arg1 = battle_get_per_side_status(index) & 1; + arg2 = AIScriptRead32(gAIScriptPtr + 2); + + if ((gUnknown_0202428E[arg1] & arg2) == 0) + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 6); + else + gAIScriptPtr += 10; +} + +static void BattleAICmd_if_less_than(void) +{ + if (AI_THINKING_STRUCT->funcResult < gAIScriptPtr[1]) + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 2); + else + gAIScriptPtr += 6; +} + +static void BattleAICmd_if_more_than(void) +{ + if (AI_THINKING_STRUCT->funcResult > gAIScriptPtr[1]) + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 2); + else + gAIScriptPtr += 6; +} + +static void BattleAICmd_if_equal(void) +{ + if (AI_THINKING_STRUCT->funcResult == gAIScriptPtr[1]) + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 2); + else + gAIScriptPtr += 6; +} + +static void BattleAICmd_if_not_equal(void) +{ + if (AI_THINKING_STRUCT->funcResult != gAIScriptPtr[1]) gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 2); else gAIScriptPtr += 6; } + +static void BattleAICmd_if_less_than_32(void) +{ + u8 *temp = AIScriptReadPtr(gAIScriptPtr + 1); + + if (AI_THINKING_STRUCT->funcResult < *temp) + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 5); + else + gAIScriptPtr += 9; +} + +static void BattleAICmd_if_more_than_32(void) +{ + u8 *temp = AIScriptReadPtr(gAIScriptPtr + 1); + + if (AI_THINKING_STRUCT->funcResult > *temp) + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 5); + else + gAIScriptPtr += 9; +} + +static void BattleAICmd_if_equal_32(void) +{ + u8 *temp = AIScriptReadPtr(gAIScriptPtr + 1); + + if (AI_THINKING_STRUCT->funcResult == *temp) + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 5); + else + gAIScriptPtr += 9; +} + +static void BattleAICmd_if_not_equal_32(void) +{ + u8 *temp = AIScriptReadPtr(gAIScriptPtr + 1); + + if (AI_THINKING_STRUCT->funcResult != *temp) + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 5); + else + gAIScriptPtr += 9; +} + +static void BattleAICmd_if_move(void) +{ + u16 move = AIScriptRead16(gAIScriptPtr + 1); + + if (AI_THINKING_STRUCT->moveConsidered == move) + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 3); + else + gAIScriptPtr += 7; +} + +static void BattleAICmd_if_not_move(void) +{ + u16 move = AIScriptRead16(gAIScriptPtr + 1); + + if (AI_THINKING_STRUCT->moveConsidered != move) + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 3); + else + gAIScriptPtr += 7; +} + +static void BattleAICmd_if_in_bytes(void) +{ + u8 *ptr = AIScriptReadPtr(gAIScriptPtr + 1); + + while (*ptr != 0xFF) + { + if (AI_THINKING_STRUCT->funcResult == *ptr) + { + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 5); + return; + } + ptr++; + } + gAIScriptPtr += 9; +} + +static void BattleAICmd_if_not_in_bytes(void) +{ + u8 *ptr = AIScriptReadPtr(gAIScriptPtr + 1); + + while (*ptr != 0xFF) + { + if (AI_THINKING_STRUCT->funcResult == *ptr) + { + gAIScriptPtr += 9; + return; + } + ptr++; + } + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 5); +} + +static void BattleAICmd_if_in_words(void) +{ + u16 *ptr = (u16 *)AIScriptReadPtr(gAIScriptPtr + 1); + + while (*ptr != 0xFFFF) + { + if (AI_THINKING_STRUCT->funcResult == *ptr) + { + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 5); + return; + } + ptr++; + } + gAIScriptPtr += 9; +} + +static void BattleAICmd_if_not_in_words(void) +{ + u16 *ptr = (u16 *)AIScriptReadPtr(gAIScriptPtr + 1); + + while (*ptr != 0xFFFF) + { + if (AI_THINKING_STRUCT->funcResult == *ptr) + { + gAIScriptPtr += 9; + return; + } + ptr++; + } + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 5); +} + +static void BattleAICmd_if_user_can_damage(void) +{ + s32 i; + + for (i = 0; i < 4; i++) + { + if (gBattleMons[gPlayerMonIndex].moves[i] != 0 + && gBattleMoves[gBattleMons[gPlayerMonIndex].moves[i]].power != 0) + break; + } + if (i == 4) + gAIScriptPtr += 5; + else + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 1); +} + +static void BattleAICmd_if_user_cant_damage(void) +{ + s32 i; + + for (i = 0; i < 4; i++) + { + if (gBattleMons[gPlayerMonIndex].moves[i] != 0 + && gBattleMoves[gBattleMons[gPlayerMonIndex].moves[i]].power != 0) + break; + } + if (i != 4) + gAIScriptPtr += 5; + else + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 1); +} + +static void BattleAICmd_get_turn_count(void) +{ + AI_THINKING_STRUCT->funcResult = gUnknown_03005D10[19]; + gAIScriptPtr += 1; +} + +static void BattleAICmd_get_type(void) +{ + u8 typeVar = gAIScriptPtr[1]; + + switch (typeVar) + { + case 1: // player primary type + AI_THINKING_STRUCT->funcResult = gBattleMons[gPlayerMonIndex].type1; + break; + case 0: // enemy primary type + AI_THINKING_STRUCT->funcResult = gBattleMons[gEnemyMonIndex].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; + break; + case 4: // type of move being pointed to + AI_THINKING_STRUCT->funcResult = gBattleMoves[AI_THINKING_STRUCT->moveConsidered].type; + break; + } + gAIScriptPtr += 2; +} + +// util for double battles? whats this doing in the middle of the battle AI macros? +u8 sub_8131E70(u8 index) +{ + switch (index) + { + case 1: + return gPlayerMonIndex; + case 0: + default: + return gEnemyMonIndex; + case 3: + return gPlayerMonIndex ^ 2; + case 2: + return gEnemyMonIndex ^ 2; + } +} + +static void BattleAICmd_unk_5F(void) +{ + u8 index = sub_8131E70(gAIScriptPtr[1]); + + if(gBattleMons[index].type1 == gAIScriptPtr[2] || gBattleMons[index].type2 == gAIScriptPtr[2]) + { + AI_THINKING_STRUCT->funcResult = 1; + } + else + { + AI_THINKING_STRUCT->funcResult = 0; + } + + gAIScriptPtr += 3; +} + +static void BattleAICmd_get_move_power(void) +{ + AI_THINKING_STRUCT->funcResult = gBattleMoves[AI_THINKING_STRUCT->moveConsidered].power; + gAIScriptPtr += 1; +} + +__attribute__((naked)) // not even going to try. if it doesnt match in ruby, it wont match in emerald (yet). +static void BattleAICmd_is_most_powerful_move(void) +{ + 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, 0x14\n\ + movs r3, 0\n\ + ldr r0, =gUnknown_085B09C8\n\ + ldrh r1, [r0]\n\ + ldr r5, =0x0000ffff\n\ + ldr r6, =gBattleMoves\n\ + ldr r2, =gUnknown_020244A8\n\ + cmp r1, r5\n\ + beq _08131F86\n\ + ldr r0, [r2]\n\ + ldr r0, [r0, 0x14]\n\ + ldrh r1, [r0, 0x2]\n\ + lsls r0, r1, 1\n\ + adds r0, r1\n\ + lsls r0, 2\n\ + adds r0, r6\n\ + ldrb r4, [r0]\n\ + ldr r1, =gUnknown_085B09C8\n\ +_08131F76:\n\ + ldrh r0, [r1]\n\ + cmp r4, r0\n\ + beq _08131F86\n\ + adds r1, 0x2\n\ + adds r3, 0x1\n\ + ldrh r0, [r1]\n\ + cmp r0, r5\n\ + bne _08131F76\n\ +_08131F86:\n\ + ldr r0, [r2]\n\ + ldr r0, [r0, 0x14]\n\ + ldrh r1, [r0, 0x2]\n\ + lsls r0, r1, 1\n\ + adds r0, r1\n\ + lsls r0, 2\n\ + adds r0, r6\n\ + ldrb r0, [r0, 0x1]\n\ + cmp r0, 0x1\n\ + bhi _08131F9C\n\ + b _08132126\n\ +_08131F9C:\n\ + lsls r0, r3, 1\n\ + ldr r1, =gUnknown_085B09C8\n\ + adds r0, r1\n\ + ldrh r3, [r0]\n\ + ldr r0, =0x0000ffff\n\ + cmp r3, r0\n\ + beq _08131FAC\n\ + b _08132126\n\ +_08131FAC:\n\ + ldr r0, =gUnknown_02024400\n\ + movs r1, 0\n\ + strh r1, [r0]\n\ + ldr r0, =gUnknown_0202449C\n\ + ldr r0, [r0]\n\ + strb r1, [r0, 0x13]\n\ + ldr r0, =gUnknown_02024474\n\ + movs r2, 0x1\n\ + strb r2, [r0, 0xE]\n\ + ldr r0, =gBattleMoveFlags\n\ + strb r1, [r0]\n\ + ldr r0, =gCritMultiplier\n\ + strb r2, [r0]\n\ + movs r6, 0\n\ + mov r9, r3\n\ + ldr r2, =gUnknown_085B09C8\n\ + ldrh r2, [r2]\n\ + str r2, [sp, 0x10]\n\ +_08131FD0:\n\ + movs r3, 0\n\ + ldr r5, =gBattleMons\n\ + lsls r4, r6, 1\n\ + ldr r7, =gPlayerMonIndex\n\ + lsls r0, r6, 2\n\ + mov r8, r0\n\ + adds r1, r6, 0x1\n\ + mov r10, r1\n\ + ldr r2, [sp, 0x10]\n\ + cmp r2, r9\n\ + beq _08132014\n\ + ldr r2, =gBattleMoves\n\ + ldrb r1, [r7]\n\ + movs r0, 0x58\n\ + muls r0, r1\n\ + adds r0, r4, r0\n\ + adds r1, r5, 0\n\ + adds r1, 0xC\n\ + adds r0, r1\n\ + ldrh r1, [r0]\n\ + lsls r0, r1, 1\n\ + adds r0, r1\n\ + lsls r0, 2\n\ + adds r0, r2\n\ + ldrb r2, [r0]\n\ + ldr r1, =gUnknown_085B09C8\n\ +_08132004:\n\ + ldrh r0, [r1]\n\ + cmp r2, r0\n\ + beq _08132014\n\ + adds r1, 0x2\n\ + adds r3, 0x1\n\ + ldrh r0, [r1]\n\ + cmp r0, r9\n\ + bne _08132004\n\ +_08132014:\n\ + ldrb r1, [r7]\n\ + movs r0, 0x58\n\ + muls r0, r1\n\ + adds r0, r4, r0\n\ + adds r1, r5, 0\n\ + adds r1, 0xC\n\ + adds r1, r0, r1\n\ + ldrh r0, [r1]\n\ + cmp r0, 0\n\ + beq _081320C0\n\ + lsls r0, r3, 1\n\ + ldr r2, =gUnknown_085B09C8\n\ + adds r0, r2\n\ + ldrh r0, [r0]\n\ + cmp r0, r9\n\ + bne _081320C0\n\ + ldr r0, =gBattleMoves\n\ + ldrh r2, [r1]\n\ + lsls r1, r2, 1\n\ + adds r1, r2\n\ + lsls r1, 2\n\ + adds r1, r0\n\ + ldrb r0, [r1, 0x1]\n\ + cmp r0, 0x1\n\ + bls _081320C0\n\ + ldr r5, =gUnknown_020241EA\n\ + strh r2, [r5]\n\ + ldrb r0, [r7]\n\ + ldr r4, =gEnemyMonIndex\n\ + ldrb r1, [r4]\n\ + bl sub_8046E7C\n\ + ldrh r0, [r5]\n\ + ldrb r1, [r7]\n\ + ldrb r2, [r4]\n\ + bl move_effectiveness_something\n\ + mov r4, sp\n\ + add r4, r8\n\ + ldr r2, =gBattleMoveDamage\n\ + ldr r0, =gUnknown_020244A8\n\ + ldr r0, [r0]\n\ + ldr r0, [r0, 0x14]\n\ + adds r0, 0x18\n\ + adds r0, r6\n\ + ldrb r1, [r0]\n\ + ldr r0, [r2]\n\ + muls r0, r1\n\ + movs r1, 0x64\n\ + bl __divsi3\n\ + str r0, [r4]\n\ + cmp r0, 0\n\ + bne _081320C8\n\ + movs r0, 0x1\n\ + str r0, [r4]\n\ + b _081320C8\n\ + .pool\n\ +_081320C0:\n\ + mov r1, sp\n\ + add r1, r8\n\ + movs r0, 0\n\ + str r0, [r1]\n\ +_081320C8:\n\ + mov r6, r10\n\ + cmp r6, 0x3\n\ + bgt _081320D0\n\ + b _08131FD0\n\ +_081320D0:\n\ + movs r6, 0\n\ + ldr r2, =gUnknown_020244A8\n\ + ldr r0, [r2]\n\ + ldr r0, [r0, 0x14]\n\ + ldrb r0, [r0, 0x1]\n\ + lsls r0, 2\n\ + add r0, sp\n\ + ldr r1, [sp]\n\ + ldr r0, [r0]\n\ + ldr r5, =gAIScriptPtr\n\ + cmp r1, r0\n\ + bgt _08132106\n\ + adds r4, r2, 0\n\ + mov r3, sp\n\ +_081320EC:\n\ + adds r3, 0x4\n\ + adds r6, 0x1\n\ + cmp r6, 0x3\n\ + bgt _08132106\n\ + ldr r0, [r4]\n\ + ldr r0, [r0, 0x14]\n\ + ldrb r0, [r0, 0x1]\n\ + lsls r0, 2\n\ + add r0, sp\n\ + ldr r1, [r3]\n\ + ldr r0, [r0]\n\ + cmp r1, r0\n\ + ble _081320EC\n\ +_08132106:\n\ + cmp r6, 0x4\n\ + bne _0813211C\n\ + ldr r0, [r2]\n\ + ldr r1, [r0, 0x14]\n\ + movs r0, 0x2\n\ + str r0, [r1, 0x8]\n\ + b _08132130\n\ + .pool\n\ +_0813211C:\n\ + ldr r0, [r2]\n\ + ldr r1, [r0, 0x14]\n\ + movs r0, 0x1\n\ + str r0, [r1, 0x8]\n\ + b _08132130\n\ +_08132126:\n\ + ldr r0, [r2]\n\ + ldr r1, [r0, 0x14]\n\ + movs r0, 0\n\ + str r0, [r1, 0x8]\n\ + ldr r5, =gAIScriptPtr\n\ +_08132130:\n\ + ldr r0, [r5]\n\ + adds r0, 0x1\n\ + str r0, [r5]\n\ + add sp, 0x14\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\ + .pool\n\ + .syntax divided"); +} + +static void BattleAICmd_get_move(void) +{ + if (gAIScriptPtr[1] == USER) + AI_THINKING_STRUCT->funcResult = gUnknown_02024248[gPlayerMonIndex]; + else + AI_THINKING_STRUCT->funcResult = gUnknown_02024248[gEnemyMonIndex]; + + gAIScriptPtr += 2; +} + +static void BattleAICmd_if_arg_equal(void) +{ + if (gAIScriptPtr[1] == AI_THINKING_STRUCT->funcResult) + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 2); + else + gAIScriptPtr += 6; +} + +static void BattleAICmd_if_arg_not_equal(void) +{ + if (gAIScriptPtr[1] != AI_THINKING_STRUCT->funcResult) + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 2); + else + gAIScriptPtr += 6; +} + +static void BattleAICmd_if_would_go_first(void) +{ + if (b_first_side(gPlayerMonIndex, gEnemyMonIndex, 1) == gAIScriptPtr[1]) + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 2); + else + gAIScriptPtr += 6; +} + +static void BattleAICmd_if_would_not_go_first(void) +{ + if (b_first_side(gPlayerMonIndex, gEnemyMonIndex, 1) != gAIScriptPtr[1]) + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 2); + else + gAIScriptPtr += 6; +} + +static void BattleAICmd_nullsub_2A(void) +{ +} + +static void BattleAICmd_nullsub_2B(void) +{ +} + +static void BattleAICmd_count_alive_pokemon(void) +{ + u8 index; + u8 var, var2; + struct Pokemon *party; + int i; + + AI_THINKING_STRUCT->funcResult = 0; + + if (gAIScriptPtr[1] == USER) + index = gPlayerMonIndex; + else + index = gEnemyMonIndex; + + if (battle_side_get_owner(index) == 0) + party = gPlayerParty; + else + party = gEnemyParty; + + 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]; + } + else + { + var = gUnknown_0202406E[index][0]; + var2 = gUnknown_0202406E[index][0]; + } + + for (i = 0; i < 6; i++) + { + if (i != var && i != var2 + && GetMonData(&party[i], MON_DATA_HP) != 0 + && GetMonData(&party[i], MON_DATA_SPECIES2) != SPECIES_NONE + && GetMonData(&party[i], MON_DATA_SPECIES2) != SPECIES_EGG) + { + AI_THINKING_STRUCT->funcResult++; + } + } + + gAIScriptPtr += 2; +} + +static void BattleAICmd_get_considered_move(void) +{ + AI_THINKING_STRUCT->funcResult = AI_THINKING_STRUCT->moveConsidered; + gAIScriptPtr += 1; +} + +static void BattleAICmd_get_considered_move_effect(void) +{ + AI_THINKING_STRUCT->funcResult = gBattleMoves[AI_THINKING_STRUCT->moveConsidered].effect; + gAIScriptPtr += 1; +} + +static void BattleAICmd_get_ability(void) +{ + u8 index; + + if (gAIScriptPtr[1] == USER) + index = gPlayerMonIndex; + else + index = gEnemyMonIndex; + + if(gUnknown_02024064 != index) + { + if(UNK_2016A00_STRUCT->unk40[index] != 0) + { + AI_THINKING_STRUCT->funcResult = UNK_2016A00_STRUCT->unk40[index]; + gAIScriptPtr += 2; + return; + } + + // abilities that prevent fleeing. + if (gBattleMons[index].ability == ABILITY_SHADOW_TAG + || gBattleMons[index].ability == ABILITY_MAGNET_PULL + || gBattleMons[index].ability == ABILITY_ARENA_TRAP) + { + AI_THINKING_STRUCT->funcResult = gBattleMons[index].ability; + gAIScriptPtr += 2; + return; + } + + if (gBaseStats[gBattleMons[index].species].ability1 != ABILITY_NONE) + { + if (gBaseStats[gBattleMons[index].species].ability2 != ABILITY_NONE) + { + // AI has no knowledge of opponent, so it guesses which ability. + if(Random() & 1) + { + AI_THINKING_STRUCT->funcResult = gBaseStats[gBattleMons[index].species].ability1; + } + else + { + AI_THINKING_STRUCT->funcResult = gBaseStats[gBattleMons[index].species].ability2; + } + } + else + { + AI_THINKING_STRUCT->funcResult = gBaseStats[gBattleMons[index].species].ability1; // it's definitely ability 1. + } + } + else + { + AI_THINKING_STRUCT->funcResult = gBaseStats[gBattleMons[index].species].ability2; // AI cant actually reach this part since every mon has at least 1 ability. + } + } + else + { + // The AI knows its own ability. + AI_THINKING_STRUCT->funcResult = gBattleMons[index].ability; + } + gAIScriptPtr += 2; +} + +#ifdef NONMATCHING +static void tai60_unk(void) +{ + u8 index = sub_8131E70(gAIScriptPtr[1]); + u8 arg2 = gAIScriptPtr[2]; + u8 var; + + if(gAIScriptPtr[1] == 0 || gAIScriptPtr[1] == 2) + { + // _0813253A + if(UNK_2016A00_STRUCT->unk40[index] != 0) + { + var = UNK_2016A00_STRUCT->unk40[index]; + AI_THINKING_STRUCT->funcResult = var; + } + else + { + // _0813255C + if (gBattleMons[index].ability == ABILITY_SHADOW_TAG + || gBattleMons[index].ability == ABILITY_MAGNET_PULL + || gBattleMons[index].ability == ABILITY_ARENA_TRAP) + { + var = gBattleMons[index].ability; + } + else + { + // _08132588 + if (gBaseStats[gBattleMons[index].species].ability1 != ABILITY_NONE) + { + if (gBaseStats[gBattleMons[index].species].ability2 != ABILITY_NONE) + { + if(gBaseStats[gBattleMons[index].species].ability1 != arg2 && gBaseStats[gBattleMons[index].species].ability2 != arg2) + { + var = 2; + } + else + { + var = gBaseStats[gBattleMons[index].species].ability1; + } + } + else + { + // _081325B4 + var = gBaseStats[gBattleMons[index].species].ability1; + } + } + else + { + // _081325B8 + var = gBaseStats[gBattleMons[index].species].ability2; + } + } + } + } + else + { + // _081325BC + var = gBattleMons[index].ability; + } + + // _081325CA + if(var == ABILITY_NONE) + { + AI_THINKING_STRUCT->funcResult = 2; + } + else if(var == arg2) + { + AI_THINKING_STRUCT->funcResult = 1; + } + else + { + AI_THINKING_STRUCT->funcResult = 0; + } + gAIScriptPtr += 3; +} +#else +__attribute__((naked)) +static void tai60_unk(void) +{ + asm(".syntax unified\n\ + push {r4-r6,lr}\n\ + ldr r4, =gAIScriptPtr\n\ + ldr r0, [r4]\n\ + ldrb r0, [r0, 0x1]\n\ + bl sub_8131E70\n\ + lsls r0, 24\n\ + lsrs r5, r0, 24\n\ + ldr r0, [r4]\n\ + ldrb r3, [r0, 0x2]\n\ + ldrb r0, [r0, 0x1]\n\ + cmp r0, 0\n\ + beq _0813253A\n\ + cmp r0, 0x2\n\ + bne _081325BC\n\ +_0813253A:\n\ + ldr r0, =gUnknown_020244A8\n\ + ldr r4, [r0]\n\ + ldr r1, [r4, 0x18]\n\ + adds r1, 0x40\n\ + adds r2, r1, r5\n\ + ldrb r1, [r2]\n\ + adds r6, r0, 0\n\ + cmp r1, 0\n\ + beq _0813255C\n\ + adds r3, r1, 0\n\ + ldr r0, [r4, 0x14]\n\ + str r3, [r0, 0x8]\n\ + b _081325CA\n\ + .pool\n\ +_0813255C:\n\ + ldr r1, =gBattleMons\n\ + movs r0, 0x58\n\ + muls r0, r5\n\ + adds r4, r0, r1\n\ + adds r0, r4, 0\n\ + adds r0, 0x20\n\ + ldrb r0, [r0]\n\ + cmp r0, 0x17\n\ + beq _08132576\n\ + cmp r0, 0x2A\n\ + beq _08132576\n\ + cmp r0, 0x47\n\ + bne _08132588\n\ +_08132576:\n\ + movs r0, 0x58\n\ + muls r0, r5\n\ + adds r0, r1\n\ + adds r0, 0x20\n\ + ldrb r3, [r0]\n\ + b _081325CA\n\ + .pool\n\ +_08132588:\n\ + ldr r2, =gBaseStats\n\ + ldrh r1, [r4]\n\ + lsls r0, r1, 3\n\ + subs r0, r1\n\ + lsls r0, 2\n\ + adds r1, r0, r2\n\ + ldrb r4, [r1, 0x16]\n\ + cmp r4, 0\n\ + beq _081325B8\n\ + ldrb r2, [r1, 0x17]\n\ + cmp r2, 0\n\ + beq _081325B4\n\ + adds r0, r3, 0\n\ + cmp r4, r0\n\ + beq _081325CE\n\ + cmp r2, r0\n\ + beq _081325CE\n\ + adds r3, r4, 0\n\ + b _081325CA\n\ + .pool\n\ +_081325B4:\n\ + ldrb r3, [r1, 0x16]\n\ + b _081325CA\n\ +_081325B8:\n\ + ldrb r3, [r1, 0x17]\n\ + b _081325CA\n\ +_081325BC:\n\ + ldr r1, =gBattleMons\n\ + movs r0, 0x58\n\ + muls r0, r5\n\ + adds r0, r1\n\ + adds r0, 0x20\n\ + ldrb r3, [r0]\n\ + ldr r6, =gUnknown_020244A8\n\ +_081325CA:\n\ + cmp r3, 0\n\ + bne _081325E8\n\ +_081325CE:\n\ + ldr r0, [r6]\n\ + ldr r1, [r0, 0x14]\n\ + movs r0, 0x2\n\ + str r0, [r1, 0x8]\n\ + ldr r2, =gAIScriptPtr\n\ + b _08132608\n\ + .pool\n\ +_081325E8:\n\ + ldr r0, =gAIScriptPtr\n\ + ldr r1, [r0]\n\ + adds r2, r0, 0\n\ + ldrb r1, [r1, 0x2]\n\ + cmp r3, r1\n\ + bne _08132600\n\ + ldr r0, [r6]\n\ + ldr r1, [r0, 0x14]\n\ + movs r0, 0x1\n\ + b _08132606\n\ + .pool\n\ +_08132600:\n\ + ldr r0, [r6]\n\ + ldr r1, [r0, 0x14]\n\ + movs r0, 0\n\ +_08132606:\n\ + str r0, [r1, 0x8]\n\ +_08132608:\n\ + ldr r0, [r2]\n\ + adds r0, 0x3\n\ + str r0, [r2]\n\ + pop {r4-r6}\n\ + pop {r0}\n\ + bx r0\n\ + .pool\n\ + .syntax divided"); +} +#endif + +static void BattleAICmd_get_highest_possible_damage(void) +{ + s32 i; + + gUnknown_02024400 = 0; + gUnknown_0202449C[0x13] = 0; + gUnknown_02024474[0xE] = 1; + gBattleMoveFlags = 0; + gCritMultiplier = 1; + AI_THINKING_STRUCT->funcResult = 0; + + for (i = 0; i < 4; i++) + { + gBattleMoveDamage = 40; + gUnknown_020241EA = gBattleMons[gPlayerMonIndex].moves[i]; + + if (gUnknown_020241EA) + { + move_effectiveness_something(gUnknown_020241EA, gPlayerMonIndex, gEnemyMonIndex); + + // reduce by 1/3. + if (gBattleMoveDamage == 120) + gBattleMoveDamage = 80; + if (gBattleMoveDamage == 240) + gBattleMoveDamage = 160; + if (gBattleMoveDamage == 30) + gBattleMoveDamage = 20; + if (gBattleMoveDamage == 15) + gBattleMoveDamage = 10; + + if (gBattleMoveFlags & 8) // if it's a status move, it wont do anything. + gBattleMoveDamage = 0; + + if (AI_THINKING_STRUCT->funcResult < gBattleMoveDamage) + AI_THINKING_STRUCT->funcResult = gBattleMoveDamage; + } + } + gAIScriptPtr += 1; +} + +static void BattleAICmd_if_damage_bonus(void) +{ + u8 damageVar; + + gUnknown_02024400 = 0; + gUnknown_0202449C[0x13] = 0; + gUnknown_02024474[0xE] = 1; + gBattleMoveFlags = 0; + gCritMultiplier = 1; + + gBattleMoveDamage = 40; + gUnknown_020241EA = AI_THINKING_STRUCT->moveConsidered; + + move_effectiveness_something(gUnknown_020241EA, gPlayerMonIndex, gEnemyMonIndex); + + if (gBattleMoveDamage == 120) + gBattleMoveDamage = 80; + if (gBattleMoveDamage == 240) + gBattleMoveDamage = 160; + if (gBattleMoveDamage == 30) + gBattleMoveDamage = 20; + if (gBattleMoveDamage == 15) + gBattleMoveDamage = 10; + + if (gBattleMoveFlags & 8) + gBattleMoveDamage = 0; + + // store gBattleMoveDamage in a u8 variable because gAIScriptPtr[1] is a u8. + damageVar = gBattleMoveDamage; + + if (damageVar == gAIScriptPtr[1]) + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 2); + else + gAIScriptPtr += 6; +} + +static void BattleAICmd_nullsub_32(void) +{ +} + +static void BattleAICmd_nullsub_33(void) +{ +} + +static void BattleAICmd_if_status_in_party(void) +{ + struct Pokemon *party; + int i; + u32 statusToCompareTo; + u8 index; + + switch(gAIScriptPtr[1]) + { + case 1: + index = gPlayerMonIndex; + break; + default: + index = gEnemyMonIndex; + break; + } + + party = (battle_side_get_owner(index) == 0) ? gPlayerParty : gEnemyParty; + + statusToCompareTo = AIScriptRead32(gAIScriptPtr + 2); + + for (i = 0; i < 6; i++) + { + u16 species = GetMonData(&party[i], MON_DATA_SPECIES); + u16 hp = GetMonData(&party[i], MON_DATA_HP); + u32 status = GetMonData(&party[i], MON_DATA_STATUS); + + if (species != SPECIES_NONE && species != SPECIES_EGG && hp != 0 && status == statusToCompareTo) + { + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 6); + return; + } + } + + gAIScriptPtr += 10; +} + +static void BattleAICmd_if_status_not_in_party(void) +{ + struct Pokemon *party; + int i; + u32 statusToCompareTo; + u8 index; + + switch(gAIScriptPtr[1]) + { + case 1: + index = gPlayerMonIndex; + break; + default: + index = gEnemyMonIndex; + break; + } + + party = (battle_side_get_owner(index) == 0) ? gPlayerParty : gEnemyParty; + + statusToCompareTo = AIScriptRead32(gAIScriptPtr + 2); + + for (i = 0; i < 6; i++) + { + u16 species = GetMonData(&party[i], MON_DATA_SPECIES); + u16 hp = GetMonData(&party[i], MON_DATA_HP); + u32 status = GetMonData(&party[i], MON_DATA_STATUS); + + if (species != SPECIES_NONE && species != SPECIES_EGG && hp != 0 && status == statusToCompareTo) + { + gAIScriptPtr += 10; // still bugged in Emerald + } + } + + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 6); +} + +static void BattleAICmd_get_weather(void) +{ + if (gBattleWeather & 7) + AI_THINKING_STRUCT->funcResult = 1; + if (gBattleWeather & 0x18) + AI_THINKING_STRUCT->funcResult = 2; + if (gBattleWeather & 0x60) + AI_THINKING_STRUCT->funcResult = 0; + if (gBattleWeather & 0x80) + AI_THINKING_STRUCT->funcResult = 3; + + gAIScriptPtr += 1; +} + +static void BattleAICmd_if_effect(void) +{ + if (gBattleMoves[AI_THINKING_STRUCT->moveConsidered].effect == gAIScriptPtr[1]) + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 2); + else + gAIScriptPtr += 6; +} + +static void BattleAICmd_if_not_effect(void) +{ + if (gBattleMoves[AI_THINKING_STRUCT->moveConsidered].effect != gAIScriptPtr[1]) + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 2); + else + gAIScriptPtr += 6; +} + +static void BattleAICmd_if_stat_level_less_than(void) +{ + u32 party; + + if (gAIScriptPtr[1] == USER) + party = gPlayerMonIndex; + else + party = gEnemyMonIndex; + + if (gBattleMons[party].statStages[gAIScriptPtr[2]] < gAIScriptPtr[3]) + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 4); + else + gAIScriptPtr += 8; +} + +static void BattleAICmd_if_stat_level_more_than(void) +{ + u32 party; + + if (gAIScriptPtr[1] == USER) + party = gPlayerMonIndex; + else + party = gEnemyMonIndex; + + if (gBattleMons[party].statStages[gAIScriptPtr[2]] > gAIScriptPtr[3]) + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 4); + else + gAIScriptPtr += 8; +} + +static void BattleAICmd_if_stat_level_equal(void) +{ + u32 party; + + if (gAIScriptPtr[1] == USER) + party = gPlayerMonIndex; + else + party = gEnemyMonIndex; + + if (gBattleMons[party].statStages[gAIScriptPtr[2]] == gAIScriptPtr[3]) + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 4); + else + gAIScriptPtr += 8; +} + +static void BattleAICmd_if_stat_level_not_equal(void) +{ + u32 party; + + if (gAIScriptPtr[1] == USER) + party = gPlayerMonIndex; + else + party = gEnemyMonIndex; + + if (gBattleMons[party].statStages[gAIScriptPtr[2]] != gAIScriptPtr[3]) + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 4); + else + gAIScriptPtr += 8; +} + +static void BattleAICmd_if_can_faint(void) +{ + if (gBattleMoves[AI_THINKING_STRUCT->moveConsidered].power < 2) + { + gAIScriptPtr += 5; + return; + } + + gUnknown_02024400 = 0; + gUnknown_0202449C[0x13] = 0; + gUnknown_02024474[0xE] = 1; + gBattleMoveFlags = 0; + gCritMultiplier = 1; + gUnknown_020241EA = AI_THINKING_STRUCT->moveConsidered; + sub_8046E7C(gPlayerMonIndex, gEnemyMonIndex); + move_effectiveness_something(gUnknown_020241EA, gPlayerMonIndex, gEnemyMonIndex); + + gBattleMoveDamage = gBattleMoveDamage * AI_THINKING_STRUCT->unk18[AI_THINKING_STRUCT->movesetIndex] / 100; + + // moves always do at least 1 damage. + if (gBattleMoveDamage == 0) + gBattleMoveDamage = 1; + + if (gBattleMons[gEnemyMonIndex].hp <= gBattleMoveDamage) + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 1); + else + gAIScriptPtr += 5; +} + +static void BattleAICmd_if_cant_faint(void) +{ + if (gBattleMoves[AI_THINKING_STRUCT->moveConsidered].power < 2) + { + gAIScriptPtr += 5; + return; + } + + gUnknown_02024400 = 0; + gUnknown_0202449C[0x13] = 0; + gUnknown_02024474[0xE] = 1; + gBattleMoveFlags = 0; + gCritMultiplier = 1; + gUnknown_020241EA = AI_THINKING_STRUCT->moveConsidered; + sub_8046E7C(gPlayerMonIndex, gEnemyMonIndex); + move_effectiveness_something(gUnknown_020241EA, gPlayerMonIndex, gEnemyMonIndex); + + 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) + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 1); + else + gAIScriptPtr += 5; +} + +static void BattleAICmd_if_has_move(void) +{ + int i; + u16 *temp_ptr = (u16 *)(gAIScriptPtr + 2); + + switch(gAIScriptPtr[1]) + { + case 1: + // _08132E42 + for (i = 0; i < 4; i++) + { + if (gBattleMons[gPlayerMonIndex].moves[i] == *temp_ptr) + break; + } + if (i == 4) + { + gAIScriptPtr += 8; + return; + } + else + { + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 4); + return; + } + case 3: // new to Emerald + if(gBattleMons[gPlayerMonIndex ^ 2].hp == 0) + { + gAIScriptPtr += 8; + return; + } + else + { + for (i = 0; i < 4; i++) + { + if (gBattleMons[gPlayerMonIndex ^ 2].moves[i] == *temp_ptr) + break; + } + } + if (i == 4) + { + gAIScriptPtr += 8; + return; + } + else + { + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 4); + return; + } + case 0: + case 2: + for (i = 0; i < 4; i++) + { + if (UNK_2016A00_STRUCT->unk0[gEnemyMonIndex][i] == *temp_ptr) + break; + } + if (i == 4) + { + gAIScriptPtr += 8; + return; + } + else + { + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 4); + return; + } + } +} + +static void BattleAICmd_if_dont_have_move(void) +{ + int i; + u16 *temp_ptr = (u16 *)(gAIScriptPtr + 2); + + switch(gAIScriptPtr[1]) + { + case 1: + case 3: // if_dont_have_move does not have the seperate 3 case check in Emerald unlike if_has_move. + for (i = 0; i < 4; i++) + { + if (gBattleMons[gPlayerMonIndex].moves[i] == *temp_ptr) + break; + } + if (i != 4) + { + gAIScriptPtr += 8; + return; + } + else + { + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 4); + return; + } + case 0: + case 2: + for (i = 0; i < 4; i++) + { + if (UNK_2016A00_STRUCT->unk0[gEnemyMonIndex][i] == *temp_ptr) + break; + } + if (i != 4) + { + gAIScriptPtr += 8; + return; + } + else + { + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 4); + return; + } + } +} + +static void BattleAICmd_if_move_effect(void) +{ + int i; + + switch (gAIScriptPtr[1]) + { + case 1: + case 3: // _08133044 + for(i = 0; i < 4; i++) + { + if(gBattleMons[gPlayerMonIndex].moves[i] != 0 && gBattleMoves[gBattleMons[gPlayerMonIndex].moves[i]].effect == gAIScriptPtr[2]) + break; + } + if (i == 4) + gAIScriptPtr += 7; + else + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 3); + break; + case 0: + 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]) + break; + } + if (i == 4) + gAIScriptPtr += 7; + else + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 3); + break; + } +} + +static void BattleAICmd_if_not_move_effect(void) +{ + int i; + + switch (gAIScriptPtr[1]) + { + case 1: + case 3: // _0813313C + for(i = 0; i < 4; i++) + { + if(gBattleMons[gPlayerMonIndex].moves[i] != 0 && gBattleMoves[gBattleMons[gPlayerMonIndex].moves[i]].effect == gAIScriptPtr[2]) + break; + } + if (i != 4) + gAIScriptPtr += 7; + else + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 3); + break; + case 0: + 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]) + break; + } + if (i != 4) + gAIScriptPtr += 7; + else + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 3); + break; + } +} + +static void BattleAICmd_if_last_move_did_damage(void) +{ + u8 index; + + if (gAIScriptPtr[1] == USER) + index = gPlayerMonIndex; + else + index = gEnemyMonIndex; + + if (gAIScriptPtr[2] == 0) + { + if (gUnknown_020242BC[index].unk4 == 0) + { + gAIScriptPtr += 7; + return; + } + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 3); + return; + } + else if (gAIScriptPtr[2] != 1) // ignore the macro if its not 0 or 1. + { + gAIScriptPtr += 7; + return; + } + else if (gUnknown_020242BC[index].unk6 != 0) + { + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 3); + return; + } + gAIScriptPtr += 7; +} + +static void BattleAICmd_if_encored(void) +{ + switch (gAIScriptPtr[1]) + { + case 0: // _08109348 + if (gUnknown_020242BC[gUnknown_02024064].unk4 == AI_THINKING_STRUCT->moveConsidered) + { + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 2); + return; + } + gAIScriptPtr += 6; + return; + case 1: // _08109370 + if (gUnknown_020242BC[gUnknown_02024064].unk6 == AI_THINKING_STRUCT->moveConsidered) + { + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 2); + return; + } + gAIScriptPtr += 6; + return; + default: + gAIScriptPtr += 6; + return; + } +} + +static void BattleAICmd_flee(void) +{ + AI_THINKING_STRUCT->aiAction |= (AI_ACTION_UNK1 | AI_ACTION_UNK2 | AI_ACTION_UNK4); // what matters is UNK2 being enabled. +} + +static void BattleAICmd_if_random_100(void) +{ + u8 safariFleeRate = gUnknown_0202449C[0x7B] * 5; // safari flee rate, from 0-20 + + if ((u8)(Random() % 100) < safariFleeRate) + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 1); + else + gAIScriptPtr += 5; +} + +static void BattleAICmd_watch(void) +{ + AI_THINKING_STRUCT->aiAction |= (AI_ACTION_UNK1 | AI_ACTION_UNK3 | AI_ACTION_UNK4); // what matters is UNK3 being enabled. +} + +static void BattleAICmd_get_hold_effect(void) +{ + u8 index; + u16 status; + + if (gAIScriptPtr[1] == USER) + index = gPlayerMonIndex; + else + index = gEnemyMonIndex; + + if (gUnknown_02024064 != index) + { + AI_THINKING_STRUCT->funcResult = itemid_get_x12(UNK_2016A00_STRUCT->unk44[index]); + } + else + AI_THINKING_STRUCT->funcResult = itemid_get_x12(gBattleMons[index].item); + + gAIScriptPtr += 2; +} + +static void tai62_unk(void) +{ + u8 index = sub_8131E70(gAIScriptPtr[1]); + u16 item; + u8 var1, var2; + + if((index & 1) == (gPlayerMonIndex & 1)) + item = gBattleMons[index].item; + else + item = UNK_2016A00_STRUCT->unk44[index]; + + // strange way of loading a 16-bit argument from the AI command. + var2 = gAIScriptPtr[2]; + var1 = gAIScriptPtr[3]; + + if((var1 | var2) == item) + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 4); + else + gAIScriptPtr += 8; +} + +static void BattleAICmd_get_gender(void) +{ + u8 index; + + if (gAIScriptPtr[1] == USER) + index = gPlayerMonIndex; + else + index = gEnemyMonIndex; + + AI_THINKING_STRUCT->funcResult = pokemon_species_get_gender_info(gBattleMons[index].species, gBattleMons[index].personality); + + gAIScriptPtr += 2; +} + +static void BattleAICmd_is_first_turn(void) +{ + u8 index; + + if (gAIScriptPtr[1] == USER) + index = gPlayerMonIndex; + else + index = gEnemyMonIndex; + + AI_THINKING_STRUCT->funcResult = gUnknown_020242BC[index].unk16; + + gAIScriptPtr += 2; +} + +static void BattleAICmd_get_stockpile_count(void) +{ + u8 index; + + if (gAIScriptPtr[1] == USER) + index = gPlayerMonIndex; + else + index = gEnemyMonIndex; + + AI_THINKING_STRUCT->funcResult = gUnknown_020242BC[index].unk9; + + gAIScriptPtr += 2; +} + +static void BattleAICmd_is_double_battle(void) +{ + AI_THINKING_STRUCT->funcResult = gBattleTypeFlags & BATTLE_TYPE_DOUBLE; + + gAIScriptPtr += 1; +} + +static void BattleAICmd_get_item(void) +{ + u8 index; + + if (gAIScriptPtr[1] == USER) + index = gPlayerMonIndex; + else + index = gEnemyMonIndex; + + // 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)]; + + gAIScriptPtr += 2; +} + +static void BattleAICmd_get_move_type_from_result(void) +{ + AI_THINKING_STRUCT->funcResult = gBattleMoves[AI_THINKING_STRUCT->funcResult].type; + + gAIScriptPtr += 1; +} + +static void BattleAICmd_get_move_power_from_result(void) +{ + AI_THINKING_STRUCT->funcResult = gBattleMoves[AI_THINKING_STRUCT->funcResult].power; + + gAIScriptPtr += 1; +} + +static void BattleAICmd_get_move_effect_from_result(void) +{ + AI_THINKING_STRUCT->funcResult = gBattleMoves[AI_THINKING_STRUCT->funcResult].effect; + + gAIScriptPtr += 1; +} + +static void BattleAICmd_get_protect_count(void) +{ + u8 index; + + if (gAIScriptPtr[1] == USER) + index = gPlayerMonIndex; + else + index = gEnemyMonIndex; + + AI_THINKING_STRUCT->funcResult = gUnknown_020242BC[index].unk8; + + gAIScriptPtr += 2; +} + +static void BattleAICmd_nullsub_52(void) +{ +} + +static void BattleAICmd_nullsub_53(void) +{ +} + +static void BattleAICmd_nullsub_54(void) +{ +} + +static void BattleAICmd_nullsub_55(void) +{ +} + +static void BattleAICmd_nullsub_56(void) +{ +} + +static void BattleAICmd_nullsub_57(void) +{ +} + +static void BattleAICmd_call(void) +{ + b_mc_stack_push(gAIScriptPtr + 5); + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 1); +} + +static void BattleAICmd_jump(void) +{ + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 1); +} + +static void BattleAICmd_end(void) +{ + if (b_mc_stack_pop_cursor() == 0) + AI_THINKING_STRUCT->aiAction |= AI_ACTION_UNK1; +} + +static void BattleAICmd_if_level_cond(void) +{ + switch (gAIScriptPtr[1]) + { + case 0: // greater than + if (gBattleMons[gPlayerMonIndex].level > gBattleMons[gEnemyMonIndex].level) + { + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 2); + return; + } + gAIScriptPtr += 6; + return; + case 1: // less than + if (gBattleMons[gPlayerMonIndex].level < gBattleMons[gEnemyMonIndex].level) + { + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 2); + return; + } + gAIScriptPtr += 6; + return; + case 2: // equal + if (gBattleMons[gPlayerMonIndex].level == gBattleMons[gEnemyMonIndex].level) + { + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 2); + return; + } + gAIScriptPtr += 6; + return; + } +} + +static void BattleAICmd_if_taunted(void) +{ + if (gUnknown_020242BC[gEnemyMonIndex].taunt != 0) + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 1); + else + gAIScriptPtr += 5; +} + +static void BattleAICmd_if_not_taunted(void) +{ + if (gUnknown_020242BC[gEnemyMonIndex].taunt == 0) + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 1); + else + gAIScriptPtr += 5; +} + +static void tai5E_unk(void) +{ + if((gPlayerMonIndex & 1) == (gEnemyMonIndex & 1)) + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 1); + else + gAIScriptPtr += 5; +} + +static void tai61_unk(void) +{ + u8 index = sub_8131E70(gAIScriptPtr[1]); + + if(UNK_BATTLE_STRUCT->unk4->unkArray[index] & 1) + gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 2); + else + gAIScriptPtr += 6; +} + +void b_mc_stack_push(u8 *var) +{ + UNK_2016C00_STRUCT->ptr[UNK_2016C00_STRUCT->unk20++] = var; +} + +void b_mc_stack_push_cursor(void) +{ + UNK_2016C00_STRUCT->ptr[UNK_2016C00_STRUCT->unk20++] = gAIScriptPtr; +} + +bool8 b_mc_stack_pop_cursor(void) +{ + if (UNK_2016C00_STRUCT->unk20 != 0) + { + --UNK_2016C00_STRUCT->unk20; + gAIScriptPtr = UNK_2016C00_STRUCT->ptr[UNK_2016C00_STRUCT->unk20]; + return TRUE; + } + else + return FALSE; +} -- cgit v1.2.3 From 9a80b550f0adc7faad4a323f3c7baeb2f9de6102 Mon Sep 17 00:00:00 2001 From: ProjectRevoTPP Date: Wed, 15 Feb 2017 16:25:21 -0500 Subject: finish decompiling main.c (#17) * partially decompile battle_ai.c up to tai60_unk * nonmatching tai60_unk * decompile more of battle_ai.c * formatting * finish porting battle_ai.c * formatting * decompile up to nonmatching VBlankIntr * finish decompiling main.c * formatting --- src/main.c | 194 ++++++++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 165 insertions(+), 29 deletions(-) (limited to 'src') diff --git a/src/main.c b/src/main.c index ff28b1e84..32e0429d3 100644 --- a/src/main.c +++ b/src/main.c @@ -3,6 +3,12 @@ #include "gba/flash_internal.h" #include "gba/m4a_internal.h" +extern u16 GetGpuReg(u8); +extern void SetGpuReg(u8, u16); +extern void LinkVSync(void); +extern void sub_800E174(void); +extern void sub_800B9B8(void); + extern struct SoundInfo gSoundInfo; extern u32 gFlashMemoryPresent; extern u32 IntrMain[]; @@ -10,7 +16,10 @@ extern u8 gHeap[]; extern struct SaveBlock2 gUnknown_02024A54; extern char *gUnknown_03005D94; extern char gUnknown_02029808[]; -extern u32 gUnknown_0203CF5C; +extern u16 gIntrCheck; +extern u32 gBattleTypeFlags; +extern u8 gUnknown_03002748; +//extern u32 gUnknown_0203CF5C; void Timer3Intr(void); bool8 HandleLinkConnection(void); @@ -22,7 +31,6 @@ static void VCountIntr(void); static void SerialIntr(void); static void IntrDummy(void); - const u8 gGameVersion = VERSION_EMERALD; const u8 gGameLanguage = GAME_LANGUAGE; // English @@ -70,7 +78,7 @@ static void InitMainCallbacks(void); static void CallCallbacks(void); static void SeedRngWithRtc(void); static void ReadKeys(void); -static void InitIntrHandlers(void); +void InitIntrHandlers(void); static void WaitForVBlank(void); #define B_START_SELECT (B_BUTTON | START_BUTTON | SELECT_BUTTON) @@ -149,10 +157,17 @@ static void UpdateLinkAndCallCallbacks(void) CallCallbacks(); } +struct gUnknown_0203CF5C_Struct +{ + u32 value; +}; + +extern struct gUnknown_0203CF5C_Struct gUnknown_0203CF5C; + static void InitMainCallbacks(void) { gMain.vblankCounter1 = 0; - gUnknown_0203CF5C = 0; + gUnknown_0203CF5C.value = 0; gMain.vblankCounter2 = 0; gMain.callback1 = NULL; SetMainCallback2(c2_copyright_1); @@ -193,12 +208,19 @@ u16 GetTrainerId(void) return gTrainerId; } -/* +void EnableVCountIntrAtLine150(void) +{ + u16 gpuReg = GetGpuReg(0x4) & 0xFF | 0x9600; + + SetGpuReg(4, gpuReg | 0x20); + EnableInterrupts(0x4); // please use IRQ_MASK_VCOUNT +} + void InitKeys(void) { gKeyRepeatContinueDelay = 5; gKeyRepeatStartDelay = 40; - + gMain.heldKeys = 0; gMain.newKeys = 0; gMain.newAndRepeatedKeys = 0; @@ -237,7 +259,7 @@ static void ReadKeys(void) gMain.heldKeys = gMain.heldKeysRaw; // Remap L to A if the L=A option is enabled. - if (gSaveBlock2.optionsButtonMode == 2) + if (gSaveBlock2Ptr->optionsButtonMode == 2) { if (gMain.newKeys & L_BUTTON) gMain.newKeys |= A_BUTTON; @@ -250,7 +272,7 @@ static void ReadKeys(void) gMain.watchedKeysPressed = TRUE; } -static void InitIntrHandlers(void) +void InitIntrHandlers(void) { int i; @@ -266,9 +288,8 @@ static void InitIntrHandlers(void) SetSerialCallback(NULL); REG_IME = 1; - REG_IE = INTR_FLAG_VBLANK; - REG_DISPSTAT = DISPSTAT_VBLANK_INTR; - REG_IE |= INTR_FLAG_VBLANK; + + EnableInterrupts(0x1); } void SetVBlankCallback(IntrCallback callback) @@ -286,43 +307,146 @@ void SetVCountCallback(IntrCallback callback) gMain.vcountCallback = callback; } +void RestoreSerialTimer3IntrHandlers(void) +{ + gIntrTable[1] = SerialIntr; + gIntrTable[2] = Timer3Intr; +} + void SetSerialCallback(IntrCallback callback) { gMain.serialCallback = callback; } +extern void CopyBufferedValuesToGpuRegs(void); +extern void ProcessDma3Requests(void); + +#ifdef NONMATCHING static void VBlankIntr(void) { - u16 savedIme; - - if (!gLinkVSyncDisabled) + if (gLinkVSyncDisabled != FALSE) LinkVSync(); + else if(gUnknown_03002748 == FALSE) + sub_800B9B8(); - savedIme = REG_IME; - REG_IME = 0; - m4aSoundVSync(); - REG_IME = savedIme; - - gMain.vblankCounter1++; + gMain.vblankCounter1++; // in the original asm, gMain is put into r0 for this addition and then preserved in r4 after it. the compiler wants to skip that and put it in either r4 or r1. + if(gUnknown_0203CF5C.value > 0) + if(gUnknown_0203CF5C.value < 0xFFFFFFFF) + gUnknown_0203CF5C.value++; + if (gMain.vblankCallback) gMain.vblankCallback(); gMain.vblankCounter2++; + + CopyBufferedValuesToGpuRegs(); + ProcessDma3Requests(); gPcmDmaCounter = gSoundInfo.pcmDmaCounter; m4aSoundMain(); - sub_800C35C(); - Random(); + sub_8033648(); + + if(!gMain.inBattle || (gBattleTypeFlags & 0x013F0102) == 0) + Random(); - INTR_CHECK |= INTR_FLAG_VBLANK; + sub_800E174(); + + gIntrCheck |= INTR_FLAG_VBLANK; gMain.intrCheck |= INTR_FLAG_VBLANK; } +#else +__attribute__((naked)) +static void VBlankIntr(void) +{ + asm(".syntax unified\n\ + push {r4,lr}\n\ + ldr r0, =gLinkVSyncDisabled\n\ + ldrb r0, [r0]\n\ + cmp r0, 0\n\ + beq _0800074C\n\ + bl LinkVSync\n\ + b _08000758\n\ + .pool\n\ +_0800074C:\n\ + ldr r0, =gUnknown_03002748\n\ + ldrb r0, [r0]\n\ + cmp r0, 0\n\ + bne _08000758\n\ + bl sub_800B9B8\n\ +_08000758:\n\ + ldr r0, =gMain\n\ + ldr r1, [r0, 0x20]\n\ + adds r1, 0x1\n\ + str r1, [r0, 0x20]\n\ + ldr r1, =gUnknown_0203CF5C\n\ + ldr r1, [r1]\n\ + adds r4, r0, 0\n\ + cmp r1, 0\n\ + beq _08000778\n\ + ldr r2, [r1]\n\ + movs r0, 0x2\n\ + negs r0, r0\n\ + cmp r2, r0\n\ + bhi _08000778\n\ + adds r0, r2, 0x1\n\ + str r0, [r1]\n\ +_08000778:\n\ + ldr r0, [r4, 0xC]\n\ + cmp r0, 0\n\ + beq _08000782\n\ + bl _call_via_r0\n\ +_08000782:\n\ + ldr r0, [r4, 0x24]\n\ + adds r0, 0x1\n\ + str r0, [r4, 0x24]\n\ + bl CopyBufferedValuesToGpuRegs\n\ + bl ProcessDma3Requests\n\ + ldr r1, =gPcmDmaCounter\n\ + ldr r0, =gSoundInfo\n\ + ldrb r0, [r0, 0x4]\n\ + strb r0, [r1]\n\ + bl m4aSoundMain\n\ + bl sub_8033648\n\ + ldr r1, =0x00000439\n\ + adds r0, r4, r1\n\ + ldrb r1, [r0]\n\ + movs r0, 0x2\n\ + ands r0, r1\n\ + cmp r0, 0\n\ + beq _080007BA\n\ + ldr r0, =gBattleTypeFlags\n\ + ldr r0, [r0]\n\ + ldr r1, =0x013f0102\n\ + ands r0, r1\n\ + cmp r0, 0\n\ + bne _080007BE\n\ +_080007BA:\n\ + bl Random\n\ +_080007BE:\n\ + bl sub_800E174\n\ + ldr r2, =gIntrCheck\n\ + ldrh r0, [r2]\n\ + movs r1, 0x1\n\ + orrs r0, r1\n\ + strh r0, [r2]\n\ + ldr r0, =gMain\n\ + ldrh r2, [r0, 0x1C]\n\ + ldrh r3, [r0, 0x1C]\n\ + orrs r1, r2\n\ + strh r1, [r0, 0x1C]\n\ + pop {r4}\n\ + pop {r0}\n\ + bx r0\n\ + .pool\n\ + .syntax divided"); +} +#endif -void InitFlashTimer(void) +void StartFlashMemoryTimer(void) { - SetFlashTimerIntr(2, gFlashTimerIntrFunc); + SetFlashTimerIntr(2, gIntrTable + 0x7); } static void HBlankIntr(void) @@ -339,7 +463,8 @@ static void VCountIntr(void) if (gMain.vcountCallback) gMain.vcountCallback(); - INTR_CHECK |= INTR_FLAG_VCOUNT; + m4aSoundVSync(); + gIntrCheck |= INTR_FLAG_VCOUNT; gMain.intrCheck |= INTR_FLAG_VCOUNT; } @@ -348,7 +473,7 @@ static void SerialIntr(void) if (gMain.serialCallback) gMain.serialCallback(); - INTR_CHECK |= INTR_FLAG_SERIAL; + gIntrCheck |= INTR_FLAG_SERIAL; gMain.intrCheck |= INTR_FLAG_SERIAL; } @@ -358,7 +483,19 @@ static void IntrDummy(void) static void WaitForVBlank(void) { gMain.intrCheck &= ~INTR_FLAG_VBLANK; - VBlankIntrWait(); + + while(!(gMain.intrCheck & 0x1)) + ; +} + +void sub_80008DC(u32 var) +{ + gUnknown_0203CF5C.value = var; +} + +void sub_80008E8(void) +{ + gUnknown_0203CF5C.value = 0; } void DoSoftReset(void) @@ -377,4 +514,3 @@ void ClearPokemonCrySongs(void) { CpuFill16(0, gPokemonCrySongs, MAX_POKEMON_CRIES * sizeof(struct PokemonCrySong)); } -*/ \ No newline at end of file -- cgit v1.2.3 From afd45e9dd4f6ee922b60a48cf2bb6d8ee44b1783 Mon Sep 17 00:00:00 2001 From: ProjectRevoTPP Date: Fri, 17 Feb 2017 12:26:45 -0500 Subject: finish decompiling dma3_manager.c except for ProcessDma3Requests (#18) --- src/dma3_manager.c | 528 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 528 insertions(+) create mode 100644 src/dma3_manager.c (limited to 'src') diff --git a/src/dma3_manager.c b/src/dma3_manager.c new file mode 100644 index 000000000..cd080a172 --- /dev/null +++ b/src/dma3_manager.c @@ -0,0 +1,528 @@ +#include "global.h" + +extern u8 gDma3ManagerLocked; +extern u8 gDma3RequestCursor; + +// size is 0x10 +struct DmaRequestsStruct +{ + /* 0x00 */ u8 *src; + /* 0x04 */ u8 *dest; + /* 0x08 */ u16 size; + /* 0x0A */ u16 mode; + /* 0x0C */ u32 value; +}; + +extern struct DmaRequestsStruct gDma3Requests[128]; + +void ClearDma3Requests(void) +{ + int i; + + gDma3ManagerLocked = TRUE; + gDma3RequestCursor = FALSE; + + for(i = 0; i < (u8)ARRAY_COUNT(gDma3Requests); i++) + { + gDma3Requests[i].size = 0; + gDma3Requests[i].src = 0; + gDma3Requests[i].dest = 0; + } + + gDma3ManagerLocked = FALSE; +} + +#ifdef NONMATCHING +void ProcessDma3Requests(void) +{ + // NOTE: the fillerA member of the DMA struct is actually u32 value; + // NOTE: gUnknown_0300001C is just a pointer inside the gDma3Requests structure, not a true symbol; feel free to remove + u16 total_size; + + if (gDma3ManagerLocked) + return; + + total_size = 0; + + // as long as there are DMA requests to process (unless size or vblank is an issue), do not exit + while (gDma3Requests[gDma3RequestCursor].size) + { + total_size += gDma3Requests[gDma3RequestCursor].size; + + if (total_size > 0xA000) + return; // don't do too much at once + + if (REG_VCOUNT > 224) + return;// we're about to leave vblank, stop + + switch (gDma3Requests[gDma3RequestCursor].mode) + { + case 1: // regular 32-bit copy + // _08000C8C + if(gDma3Requests[gDma3RequestCursor].size <= 0x1000) + { + DmaCopy32(3, gDma3Requests[gDma3RequestCursor].src, gDma3Requests[gDma3RequestCursor].dest, gDma3Requests[gDma3RequestCursor].size); + break; + } + while (gDma3Requests[gDma3RequestCursor].size > 0x1000) + { + DmaCopy32(3, gDma3Requests[gDma3RequestCursor].src, gDma3Requests[gDma3RequestCursor].dest, 0x1000); + gDma3Requests[gDma3RequestCursor].src += 0x1000; + gDma3Requests[gDma3RequestCursor].dest += 0x1000; + gDma3Requests[gDma3RequestCursor].size -= 0x1000; + } + DmaCopy32(3, gDma3Requests[gDma3RequestCursor].src, gDma3Requests[gDma3RequestCursor].dest, gDma3Requests[gDma3RequestCursor].size); + break; + case 2: // repeat a single 32-bit value across RAM + // _08000CD0 + while (gDma3Requests[gDma3RequestCursor].size > 0x1000) + { + DmaFill32(3, gDma3Requests[gDma3RequestCursor].value, gDma3Requests[gDma3RequestCursor].dest, 0x1000); + gDma3Requests[gDma3RequestCursor].dest += 0x1000; + gDma3Requests[gDma3RequestCursor].size -= 0x1000; + } + DmaFill32(3, gDma3Requests[gDma3RequestCursor].value, gDma3Requests[gDma3RequestCursor].dest, gDma3Requests[gDma3RequestCursor].size); + break; + case 3: // regular 16-bit copy + // _08000D3C + while (gDma3Requests[gDma3RequestCursor].size > 0x1000) + { + DmaCopy16(3, gDma3Requests[gDma3RequestCursor].src, gDma3Requests[gDma3RequestCursor].dest, 0x1000); + gDma3Requests[gDma3RequestCursor].src += 0x1000; + gDma3Requests[gDma3RequestCursor].dest += 0x1000; + gDma3Requests[gDma3RequestCursor].size -= 0x1000; + } + DmaCopy16(3, gDma3Requests[gDma3RequestCursor].src, gDma3Requests[gDma3RequestCursor].dest, gDma3Requests[gDma3RequestCursor].size); + break; + case 4: // repeat a single 16-bit value across RAM + // _08000D88 + while (gDma3Requests[gDma3RequestCursor].size > 0x1000) + { + DmaFill16(3, gDma3Requests[gDma3RequestCursor].value, gDma3Requests[gDma3RequestCursor].dest, 0x1000); + gDma3Requests[gDma3RequestCursor].dest += 0x1000; + gDma3Requests[gDma3RequestCursor].size -= 0x1000; + } + DmaFill16(3, gDma3Requests[gDma3RequestCursor].value, gDma3Requests[gDma3RequestCursor].dest, gDma3Requests[gDma3RequestCursor].size); + break; + } + gDma3Requests[gDma3RequestCursor].src = 0; + gDma3Requests[gDma3RequestCursor].dest = 0; + gDma3Requests[gDma3RequestCursor].size = 0; + gDma3Requests[gDma3RequestCursor].mode = 0; + gDma3Requests[gDma3RequestCursor].value = 0; + gDma3RequestCursor++; + + if (gDma3RequestCursor >= 128) // loop back to the first DMA request + gDma3RequestCursor = 0; + } +} +#else +__attribute__((naked)) +void ProcessDma3Requests(void) +{ + 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, 0xC\n\ + ldr r0, =gDma3ManagerLocked\n\ + ldrb r0, [r0]\n\ + cmp r0, 0\n\ + beq _08000C06\n\ + b _08000E46\n\ +_08000C06:\n\ + movs r0, 0\n\ + str r0, [sp, 0x8]\n\ + ldr r1, =gDma3Requests\n\ + ldr r2, =gDma3RequestCursor\n\ + ldrb r0, [r2]\n\ + lsls r0, 4\n\ + adds r0, r1\n\ + ldrh r0, [r0, 0x8]\n\ + mov r12, r2\n\ + cmp r0, 0\n\ + bne _08000C1E\n\ + b _08000E46\n\ +_08000C1E:\n\ + mov r8, r1\n\ + adds r1, 0x4\n\ + mov r10, r1\n\ + movs r6, 0x80\n\ + lsls r6, 5\n\ + ldr r7, =0x040000D4 @REG_DMA3\n\ + movs r2, 0\n\ + mov r9, r2\n\ +_08000C2E:\n\ + mov r3, r12 @ gDma3RequestCursor\n\ + ldrb r0, [r3]\n\ + lsls r5, r0, 4\n\ + mov r0, r8 @ gDma3Requests\n\ + adds r1, r5, r0 @ gDma3Requests[gDma3RequestCursor]\n\ + ldrh r0, [r1, 0x8] @ gDma3Requests[gDma3RequestCursor].size\n\ + ldr r2, [sp, 0x8]\n\ + adds r0, r2, r0\n\ + lsls r0, 16\n\ + lsrs r0, 16\n\ + str r0, [sp, 0x8]\n\ + movs r0, 0xA0\n\ + lsls r0, 8\n\ + ldr r3, [sp, 0x8]\n\ + cmp r3, r0\n\ + bls _08000C50\n\ + b _08000E46\n\ +_08000C50:\n\ + ldr r0, =0x04000006 @REG_VCOUNT\n\ + ldrb r0, [r0]\n\ + cmp r0, 0xE0\n\ + bls _08000C5A\n\ + b _08000E46\n\ +_08000C5A:\n\ + ldrh r0, [r1, 0xA]\n\ + cmp r0, 0x2\n\ + beq _08000CD0\n\ + cmp r0, 0x2\n\ + bgt _08000C80\n\ + cmp r0, 0x1\n\ + beq _08000C8C\n\ + b _08000DF0\n\ + .pool\n\ +_08000C80:\n\ + cmp r0, 0x3\n\ + beq _08000D3C\n\ + cmp r0, 0x4\n\ + bne _08000C8A\n\ + b _08000D88\n\ +_08000C8A:\n\ + b _08000DF0\n\ +_08000C8C:\n\ + ldr r3, [r1]\n\ + mov r2, r10\n\ + adds r0, r5, r2\n\ + ldr r2, [r0]\n\ + ldrh r1, [r1, 0x8]\n\ + cmp r1, r6\n\ + bhi _08000CA6\n\ + str r3, [r7]\n\ + str r2, [r7, 0x4]\n\ + lsrs r0, r1, 2\n\ + movs r1, 0x84\n\ + lsls r1, 24\n\ + b _08000DAA\n\ +_08000CA6:\n\ + ldr r4, =0x040000D4 @REG_DMA3\n\ + str r3, [r4]\n\ + str r2, [r4, 0x4]\n\ + ldr r0, =0x84000400\n\ + str r0, [r4, 0x8]\n\ + ldr r0, [r4, 0x8]\n\ + adds r3, r6\n\ + adds r2, r6\n\ + subs r1, r6\n\ + cmp r1, r6\n\ + bhi _08000CA6\n\ + str r3, [r4]\n\ + str r2, [r4, 0x4]\n\ + lsrs r0, r1, 2\n\ + movs r1, 0x84\n\ + lsls r1, 24\n\ + b _08000D76\n\ + .pool\n\ +_08000CD0:\n\ + mov r3, r10\n\ + adds r0, r5, r3\n\ + ldr r4, [r0]\n\ + ldrh r1, [r1, 0x8]\n\ + cmp r1, r6\n\ + bhi _08000CF4\n\ + mov r0, r8\n\ + adds r0, 0xC\n\ + adds r0, r5, r0\n\ + ldr r0, [r0]\n\ + str r0, [sp]\n\ + mov r5, sp\n\ + str r5, [r7]\n\ + str r4, [r7, 0x4]\n\ + lsrs r0, r1, 2\n\ + movs r1, 0x85\n\ + lsls r1, 24\n\ + b _08000DAA\n\ +_08000CF4:\n\ + mov r2, r12\n\ + ldrb r0, [r2]\n\ + lsls r0, 4\n\ + mov r5, r8\n\ + adds r5, 0xC\n\ + adds r0, r5\n\ + ldr r0, [r0]\n\ + str r0, [sp]\n\ + ldr r3, =0x040000D4 @REG_DMA3\n\ + mov r0, sp\n\ + str r0, [r3]\n\ + str r4, [r3, 0x4]\n\ + ldr r0, =0x85000400\n\ + str r0, [r3, 0x8]\n\ + ldr r0, [r3, 0x8]\n\ + adds r4, r6\n\ + subs r1, r6\n\ + cmp r1, r6\n\ + bhi _08000CF4\n\ + ldrb r0, [r2]\n\ + lsls r0, 4\n\ + adds r0, r5\n\ + ldr r0, [r0]\n\ + str r0, [sp]\n\ + mov r2, sp\n\ + str r2, [r3]\n\ + str r4, [r3, 0x4]\n\ + lsrs r0, r1, 2\n\ + movs r1, 0x85\n\ + lsls r1, 24\n\ + b _08000DEA\n\ + .pool\n\ +_08000D3C:\n\ + ldr r3, [r1]\n\ + mov r2, r10\n\ + adds r0, r5, r2\n\ + ldr r2, [r0]\n\ + ldrh r1, [r1, 0x8]\n\ + cmp r1, r6\n\ + bhi _08000D56\n\ + str r3, [r7]\n\ + str r2, [r7, 0x4]\n\ + lsrs r0, r1, 1\n\ + movs r1, 0x80\n\ + lsls r1, 24\n\ + b _08000DAA\n\ +_08000D56:\n\ + ldr r4, =0x040000D4 @REG_DMA3\n\ + str r3, [r4]\n\ + str r2, [r4, 0x4]\n\ + ldr r0, =0x80000800\n\ + str r0, [r4, 0x8]\n\ + ldr r0, [r4, 0x8]\n\ + adds r3, r6\n\ + adds r2, r6\n\ + subs r1, r6\n\ + cmp r1, r6\n\ + bhi _08000D56\n\ + str r3, [r4]\n\ + str r2, [r4, 0x4]\n\ + lsrs r0, r1, 1\n\ + movs r1, 0x80\n\ + lsls r1, 24\n\ +_08000D76:\n\ + orrs r0, r1\n\ + str r0, [r4, 0x8]\n\ + ldr r0, [r4, 0x8]\n\ + b _08000DF0\n\ + .pool\n\ +_08000D88:\n\ + mov r3, r10\n\ + adds r0, r5, r3\n\ + ldr r2, [r0]\n\ + ldrh r4, [r1, 0x8]\n\ + add r1, sp, 0x4\n\ + cmp r4, r6\n\ + bhi _08000DB2\n\ + mov r0, r8\n\ + adds r0, 0xC\n\ + adds r0, r5, r0\n\ + ldr r0, [r0]\n\ + strh r0, [r1]\n\ + str r1, [r7]\n\ + str r2, [r7, 0x4]\n\ + lsrs r0, r4, 1\n\ + movs r1, 0x81\n\ + lsls r1, 24\n\ +_08000DAA:\n\ + orrs r0, r1\n\ + str r0, [r7, 0x8]\n\ + ldr r0, [r7, 0x8]\n\ + b _08000DF0\n\ +_08000DB2:\n\ + mov r5, r12\n\ + ldrb r0, [r5]\n\ + lsls r0, 4\n\ + ldr r3, =gUnknown_0300001C\n\ + adds r0, r3\n\ + ldr r0, [r0]\n\ + strh r0, [r1]\n\ + ldr r3, =0x040000D4 @REG_DMA3\n\ + str r1, [r3]\n\ + str r2, [r3, 0x4]\n\ + ldr r0, =0x81000800\n\ + str r0, [r3, 0x8]\n\ + ldr r0, [r3, 0x8]\n\ + adds r2, r6\n\ + subs r4, r6\n\ + cmp r4, r6\n\ + bhi _08000DB2\n\ + ldrb r0, [r5]\n\ + lsls r0, 4\n\ + ldr r5, =gUnknown_0300001C\n\ + adds r0, r5\n\ + ldr r0, [r0]\n\ + strh r0, [r1]\n\ + str r1, [r3]\n\ + str r2, [r3, 0x4]\n\ + lsrs r0, r4, 1\n\ + movs r1, 0x81\n\ + lsls r1, 24\n\ +_08000DEA:\n\ + orrs r0, r1\n\ + str r0, [r3, 0x8]\n\ + ldr r0, [r3, 0x8]\n\ +_08000DF0:\n\ + ldr r1, =gDma3Requests\n\ + mov r3, r12\n\ + ldrb r0, [r3]\n\ + lsls r0, 4\n\ + adds r0, r1\n\ + mov r2, r9\n\ + str r2, [r0]\n\ + ldrb r0, [r3]\n\ + lsls r0, 4\n\ + add r0, r10\n\ + str r2, [r0]\n\ + ldrb r0, [r3]\n\ + lsls r0, 4\n\ + adds r0, r1\n\ + movs r4, 0\n\ + strh r2, [r0, 0x8]\n\ + ldrb r0, [r3]\n\ + lsls r0, 4\n\ + adds r0, r1\n\ + mov r5, r9\n\ + strh r5, [r0, 0xA]\n\ + ldrb r0, [r3]\n\ + lsls r0, 4\n\ + adds r1, 0xC\n\ + adds r0, r1\n\ + mov r1, r9\n\ + str r1, [r0]\n\ + ldrb r0, [r3]\n\ + adds r0, 0x1\n\ + strb r0, [r3]\n\ + lsls r0, 24\n\ + cmp r0, 0\n\ + bge _08000E34\n\ + strb r4, [r3]\n\ +_08000E34:\n\ + mov r2, r12\n\ + ldrb r0, [r2]\n\ + lsls r0, 4\n\ + ldr r3, =gDma3Requests\n\ + adds r0, r3\n\ + ldrh r0, [r0, 0x8]\n\ + cmp r0, 0\n\ + beq _08000E46\n\ + b _08000C2E\n\ +_08000E46:\n\ + add sp, 0xC\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\ + .pool\n\ + .syntax divided"); +} +#endif + +int RequestDma3Copy(void *src, void *dest, u16 size, u8 mode) +{ + int cursor; + int var = 0; + + gDma3ManagerLocked = 1; + + cursor = gDma3RequestCursor; + while(1) + { + if(!gDma3Requests[cursor].size) // an empty copy was found and the current cursor will be returned. + { + gDma3Requests[cursor].src = src; + gDma3Requests[cursor].dest = dest; + gDma3Requests[cursor].size = size; + + if(mode == 1) + gDma3Requests[cursor].mode = mode; + else + gDma3Requests[cursor].mode = 3; + + gDma3ManagerLocked = FALSE; + return (s16)cursor; + } + if(++cursor >= 0x80) // loop back to start. + { + cursor = 0; + } + if(++var >= 0x80) // max checks were made. all resulted in failure. + { + break; + } + } + gDma3ManagerLocked = FALSE; + return -1; +} + +int RequestDma3Fill(s32 value, void *dest, u16 size, u8 mode) +{ + int cursor; + int var = 0; + + cursor = gDma3RequestCursor; + gDma3ManagerLocked = 1; + + while(1) + { + if(!gDma3Requests[cursor].size) + { + gDma3Requests[cursor].dest = dest; + gDma3Requests[cursor].size = size; + gDma3Requests[cursor].mode = mode; + gDma3Requests[cursor].value = value; + + if(mode == 1) + gDma3Requests[cursor].mode = 2; + else + gDma3Requests[cursor].mode = 4; + + gDma3ManagerLocked = FALSE; + return (s16)cursor; + } + if(++cursor >= 0x80) // loop back to start. + { + cursor = 0; + } + if(++var >= 0x80) // max checks were made. all resulted in failure. + { + break; + } + } + gDma3ManagerLocked = FALSE; + return -1; +} + +int CheckForSpaceForDma3Request(s16 index) +{ + int current = 0; + + if (index == -1) + { + for (; current < 0x80; current ++) + if (gDma3Requests[current].size) + return -1; + + return 0; + } + + if (gDma3Requests[index].size) + return -1; + + return 0; +} -- cgit v1.2.3 From a60e850a861f686b7eccdd6bc942d9ad8d713429 Mon Sep 17 00:00:00 2001 From: YamaArashi Date: Fri, 17 Feb 2017 10:52:03 -0800 Subject: make VBlankIntr() match --- src/main.c | 133 +++++++++---------------------------------------------------- 1 file changed, 18 insertions(+), 115 deletions(-) (limited to 'src') diff --git a/src/main.c b/src/main.c index 32e0429d3..18cccfe08 100644 --- a/src/main.c +++ b/src/main.c @@ -16,10 +16,9 @@ extern u8 gHeap[]; extern struct SaveBlock2 gUnknown_02024A54; extern char *gUnknown_03005D94; extern char gUnknown_02029808[]; -extern u16 gIntrCheck; extern u32 gBattleTypeFlags; extern u8 gUnknown_03002748; -//extern u32 gUnknown_0203CF5C; +extern u32 *gUnknown_0203CF5C; void Timer3Intr(void); bool8 HandleLinkConnection(void); @@ -157,17 +156,10 @@ static void UpdateLinkAndCallCallbacks(void) CallCallbacks(); } -struct gUnknown_0203CF5C_Struct -{ - u32 value; -}; - -extern struct gUnknown_0203CF5C_Struct gUnknown_0203CF5C; - static void InitMainCallbacks(void) { gMain.vblankCounter1 = 0; - gUnknown_0203CF5C.value = 0; + gUnknown_0203CF5C = NULL; gMain.vblankCounter2 = 0; gMain.callback1 = NULL; SetMainCallback2(c2_copyright_1); @@ -220,7 +212,7 @@ void InitKeys(void) { gKeyRepeatContinueDelay = 5; gKeyRepeatStartDelay = 40; - + gMain.heldKeys = 0; gMain.newKeys = 0; gMain.newAndRepeatedKeys = 0; @@ -288,7 +280,7 @@ void InitIntrHandlers(void) SetSerialCallback(NULL); REG_IME = 1; - + EnableInterrupts(0x1); } @@ -321,25 +313,23 @@ void SetSerialCallback(IntrCallback callback) extern void CopyBufferedValuesToGpuRegs(void); extern void ProcessDma3Requests(void); -#ifdef NONMATCHING static void VBlankIntr(void) { if (gLinkVSyncDisabled != FALSE) LinkVSync(); - else if(gUnknown_03002748 == FALSE) + else if (gUnknown_03002748 == FALSE) sub_800B9B8(); - gMain.vblankCounter1++; // in the original asm, gMain is put into r0 for this addition and then preserved in r4 after it. the compiler wants to skip that and put it in either r4 or r1. + gMain.vblankCounter1++; + + if (gUnknown_0203CF5C && *gUnknown_0203CF5C < 0xFFFFFFFF) + (*gUnknown_0203CF5C)++; - if(gUnknown_0203CF5C.value > 0) - if(gUnknown_0203CF5C.value < 0xFFFFFFFF) - gUnknown_0203CF5C.value++; - if (gMain.vblankCallback) gMain.vblankCallback(); gMain.vblankCounter2++; - + CopyBufferedValuesToGpuRegs(); ProcessDma3Requests(); @@ -348,101 +338,14 @@ static void VBlankIntr(void) m4aSoundMain(); sub_8033648(); - if(!gMain.inBattle || (gBattleTypeFlags & 0x013F0102) == 0) + if (!gMain.inBattle || (gBattleTypeFlags & 0x013F0102) == 0) Random(); sub_800E174(); - gIntrCheck |= INTR_FLAG_VBLANK; + INTR_CHECK |= INTR_FLAG_VBLANK; gMain.intrCheck |= INTR_FLAG_VBLANK; } -#else -__attribute__((naked)) -static void VBlankIntr(void) -{ - asm(".syntax unified\n\ - push {r4,lr}\n\ - ldr r0, =gLinkVSyncDisabled\n\ - ldrb r0, [r0]\n\ - cmp r0, 0\n\ - beq _0800074C\n\ - bl LinkVSync\n\ - b _08000758\n\ - .pool\n\ -_0800074C:\n\ - ldr r0, =gUnknown_03002748\n\ - ldrb r0, [r0]\n\ - cmp r0, 0\n\ - bne _08000758\n\ - bl sub_800B9B8\n\ -_08000758:\n\ - ldr r0, =gMain\n\ - ldr r1, [r0, 0x20]\n\ - adds r1, 0x1\n\ - str r1, [r0, 0x20]\n\ - ldr r1, =gUnknown_0203CF5C\n\ - ldr r1, [r1]\n\ - adds r4, r0, 0\n\ - cmp r1, 0\n\ - beq _08000778\n\ - ldr r2, [r1]\n\ - movs r0, 0x2\n\ - negs r0, r0\n\ - cmp r2, r0\n\ - bhi _08000778\n\ - adds r0, r2, 0x1\n\ - str r0, [r1]\n\ -_08000778:\n\ - ldr r0, [r4, 0xC]\n\ - cmp r0, 0\n\ - beq _08000782\n\ - bl _call_via_r0\n\ -_08000782:\n\ - ldr r0, [r4, 0x24]\n\ - adds r0, 0x1\n\ - str r0, [r4, 0x24]\n\ - bl CopyBufferedValuesToGpuRegs\n\ - bl ProcessDma3Requests\n\ - ldr r1, =gPcmDmaCounter\n\ - ldr r0, =gSoundInfo\n\ - ldrb r0, [r0, 0x4]\n\ - strb r0, [r1]\n\ - bl m4aSoundMain\n\ - bl sub_8033648\n\ - ldr r1, =0x00000439\n\ - adds r0, r4, r1\n\ - ldrb r1, [r0]\n\ - movs r0, 0x2\n\ - ands r0, r1\n\ - cmp r0, 0\n\ - beq _080007BA\n\ - ldr r0, =gBattleTypeFlags\n\ - ldr r0, [r0]\n\ - ldr r1, =0x013f0102\n\ - ands r0, r1\n\ - cmp r0, 0\n\ - bne _080007BE\n\ -_080007BA:\n\ - bl Random\n\ -_080007BE:\n\ - bl sub_800E174\n\ - ldr r2, =gIntrCheck\n\ - ldrh r0, [r2]\n\ - movs r1, 0x1\n\ - orrs r0, r1\n\ - strh r0, [r2]\n\ - ldr r0, =gMain\n\ - ldrh r2, [r0, 0x1C]\n\ - ldrh r3, [r0, 0x1C]\n\ - orrs r1, r2\n\ - strh r1, [r0, 0x1C]\n\ - pop {r4}\n\ - pop {r0}\n\ - bx r0\n\ - .pool\n\ - .syntax divided"); -} -#endif void StartFlashMemoryTimer(void) { @@ -464,7 +367,7 @@ static void VCountIntr(void) gMain.vcountCallback(); m4aSoundVSync(); - gIntrCheck |= INTR_FLAG_VCOUNT; + INTR_CHECK |= INTR_FLAG_VCOUNT; gMain.intrCheck |= INTR_FLAG_VCOUNT; } @@ -473,7 +376,7 @@ static void SerialIntr(void) if (gMain.serialCallback) gMain.serialCallback(); - gIntrCheck |= INTR_FLAG_SERIAL; + INTR_CHECK |= INTR_FLAG_SERIAL; gMain.intrCheck |= INTR_FLAG_SERIAL; } @@ -483,19 +386,19 @@ static void IntrDummy(void) static void WaitForVBlank(void) { gMain.intrCheck &= ~INTR_FLAG_VBLANK; - + while(!(gMain.intrCheck & 0x1)) ; } -void sub_80008DC(u32 var) +void sub_80008DC(u32 *var) { - gUnknown_0203CF5C.value = var; + gUnknown_0203CF5C = var; } void sub_80008E8(void) { - gUnknown_0203CF5C.value = 0; + gUnknown_0203CF5C = NULL; } void DoSoftReset(void) -- cgit v1.2.3 From 73bf7791f8b3989d599c8e625a49ee7304979ee5 Mon Sep 17 00:00:00 2001 From: YamaArashi Date: Fri, 17 Feb 2017 10:56:19 -0800 Subject: use i/o register constants --- src/main.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/main.c b/src/main.c index 18cccfe08..cfc6ac6a9 100644 --- a/src/main.c +++ b/src/main.c @@ -202,10 +202,9 @@ u16 GetTrainerId(void) void EnableVCountIntrAtLine150(void) { - u16 gpuReg = GetGpuReg(0x4) & 0xFF | 0x9600; - - SetGpuReg(4, gpuReg | 0x20); - EnableInterrupts(0x4); // please use IRQ_MASK_VCOUNT + u16 gpuReg = (GetGpuReg(REG_OFFSET_DISPSTAT) & 0xFF) | (150 << 8); + SetGpuReg(REG_OFFSET_DISPSTAT, gpuReg | DISPSTAT_VCOUNT_INTR); + EnableInterrupts(INTR_FLAG_VCOUNT); } void InitKeys(void) -- cgit v1.2.3 From 83ae14e2b9e2af7ce3eb01383fe3466357ac30b1 Mon Sep 17 00:00:00 2001 From: YamaArashi Date: Fri, 17 Feb 2017 10:58:42 -0800 Subject: use constant in WaitForVBlank() --- src/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/main.c b/src/main.c index cfc6ac6a9..a88c378eb 100644 --- a/src/main.c +++ b/src/main.c @@ -386,7 +386,7 @@ static void WaitForVBlank(void) { gMain.intrCheck &= ~INTR_FLAG_VBLANK; - while(!(gMain.intrCheck & 0x1)) + while (!(gMain.intrCheck & INTR_FLAG_VBLANK)) ; } -- cgit v1.2.3