#include "global.h" #include "script.h" #include "event_data.h" #include "mevent.h" #include "util.h" #include "constants/map_scripts.h" #define RAM_SCRIPT_MAGIC 51 extern const u8* gUnknown_020375C0; // ewram bss static u8 sScriptContext1Status; static u32 sUnusedVariable1; static struct ScriptContext sScriptContext1; static u32 sUnusedVariable2; static struct ScriptContext sScriptContext2; static bool8 sScriptContext2Enabled; extern ScrCmdFunc gScriptCmdTable[]; extern ScrCmdFunc gScriptCmdTableEnd[]; extern void *gNullScriptPtr; void InitScriptContext(struct ScriptContext *ctx, void *cmdTable, void *cmdTableEnd) { s32 i; ctx->mode = 0; ctx->scriptPtr = 0; ctx->stackDepth = 0; ctx->nativePtr = 0; ctx->cmdTable = cmdTable; ctx->cmdTableEnd = cmdTableEnd; for (i = 0; i < 4; i++) ctx->data[i] = 0; for (i = 0; i < 20; i++) ctx->stack[i] = 0; } u8 SetupBytecodeScript(struct ScriptContext *ctx, const u8 *ptr) { ctx->scriptPtr = ptr; ctx->mode = 1; return 1; } void SetupNativeScript(struct ScriptContext *ctx, bool8 (*ptr)(void)) { ctx->mode = 2; ctx->nativePtr = ptr; } void StopScript(struct ScriptContext *ctx) { ctx->mode = 0; ctx->scriptPtr = 0; } bool8 RunScriptCommand(struct ScriptContext *ctx) { if (ctx->mode == 0) return FALSE; switch (ctx->mode) { case 0: return FALSE; case 2: if (ctx->nativePtr) { if (ctx->nativePtr() == TRUE) ctx->mode = 1; return TRUE; } ctx->mode = 1; case 1: while (1) { u8 cmdCode; ScrCmdFunc *func; if (!ctx->scriptPtr) { ctx->mode = 0; return FALSE; } if (ctx->scriptPtr == gNullScriptPtr) { while (1) asm("svc 2"); // HALT } cmdCode = *(ctx->scriptPtr); ctx->scriptPtr++; func = &ctx->cmdTable[cmdCode]; if (func >= ctx->cmdTableEnd) { ctx->mode = 0; return FALSE; } if ((*func)(ctx) == 1) return TRUE; } } return TRUE; } u8 ScriptPush(struct ScriptContext *ctx, const u8 *ptr) { if (ctx->stackDepth + 1 >= 20) { return 1; } else { ctx->stack[ctx->stackDepth] = ptr; ctx->stackDepth++; return 0; } } const u8 *ScriptPop(struct ScriptContext *ctx) { if (ctx->stackDepth == 0) return NULL; ctx->stackDepth--; return ctx->stack[ctx->stackDepth]; } void ScriptJump(struct ScriptContext *ctx, const u8 *ptr) { ctx->scriptPtr = ptr; } void ScriptCall(struct ScriptContext *ctx, const u8 *ptr) { ScriptPush(ctx, ctx->scriptPtr); ctx->scriptPtr = ptr; } void ScriptReturn(struct ScriptContext *ctx) { ctx->scriptPtr = ScriptPop(ctx); } u16 ScriptReadHalfword(struct ScriptContext *ctx) { u16 value = *(ctx->scriptPtr++); value |= *(ctx->scriptPtr++) << 8; return value; } u32 ScriptReadWord(struct ScriptContext *ctx) { u32 value0 = *(ctx->scriptPtr++); u32 value1 = *(ctx->scriptPtr++); u32 value2 = *(ctx->scriptPtr++); u32 value3 = *(ctx->scriptPtr++); return (((((value3 << 8) + value2) << 8) + value1) << 8) + value0; } void ScriptContext2_Enable(void) { sScriptContext2Enabled = TRUE; } void ScriptContext2_Disable(void) { sScriptContext2Enabled = FALSE; } bool8 ScriptContext2_IsEnabled(void) { return sScriptContext2Enabled; } bool8 ScriptContext1_IsScriptSetUp(void) { if (sScriptContext1Status == 0) return TRUE; else return FALSE; } void ScriptContext1_Init(void) { InitScriptContext(&sScriptContext1, gScriptCmdTable, gScriptCmdTableEnd); sScriptContext1Status = 2; } bool8 ScriptContext2_RunScript(void) { if (sScriptContext1Status == 2) return 0; if (sScriptContext1Status == 1) return 0; ScriptContext2_Enable(); if (!RunScriptCommand(&sScriptContext1)) { sScriptContext1Status = 2; ScriptContext2_Disable(); return 0; } return 1; } void ScriptContext1_SetupScript(const u8 *ptr) { InitScriptContext(&sScriptContext1, gScriptCmdTable, gScriptCmdTableEnd); SetupBytecodeScript(&sScriptContext1, ptr); ScriptContext2_Enable(); sScriptContext1Status = 0; } void ScriptContext1_Stop(void) { sScriptContext1Status = 1; } void EnableBothScriptContexts(void) { sScriptContext1Status = 0; ScriptContext2_Enable(); } void ScriptContext2_RunNewScript(const u8 *ptr) { InitScriptContext(&sScriptContext2, &gScriptCmdTable, &gScriptCmdTableEnd); SetupBytecodeScript(&sScriptContext2, ptr); while (RunScriptCommand(&sScriptContext2) == TRUE); } u8 *MapHeaderGetScriptTable(u8 tag) { const u8 *mapScripts = gMapHeader.mapScripts; if (!mapScripts) return NULL; while (1) { if (!*mapScripts) return NULL; if (*mapScripts == tag) { mapScripts++; return (u8 *)(mapScripts[0] + (mapScripts[1] << 8) + (mapScripts[2] << 16) + (mapScripts[3] << 24)); } mapScripts += 5; } } void MapHeaderRunScriptType(u8 tag) { u8 *ptr = MapHeaderGetScriptTable(tag); if (ptr) ScriptContext2_RunNewScript(ptr); } u8 *MapHeaderCheckScriptTable(u8 tag) { u8 *ptr = MapHeaderGetScriptTable(tag); if (!ptr) return NULL; while (1) { u16 varIndex1; u16 varIndex2; varIndex1 = ptr[0] | (ptr[1] << 8); if (!varIndex1) return NULL; ptr += 2; varIndex2 = ptr[0] | (ptr[1] << 8); ptr += 2; if (VarGet(varIndex1) == VarGet(varIndex2)) return (u8 *)(ptr[0] + (ptr[1] << 8) + (ptr[2] << 16) + (ptr[3] << 24)); ptr += 4; } } void RunOnLoadMapScript(void) { MapHeaderRunScriptType(MAP_SCRIPT_ON_LOAD); } void RunOnTransitionMapScript(void) { MapHeaderRunScriptType(MAP_SCRIPT_ON_TRANSITION); } void RunOnResumeMapScript(void) { MapHeaderRunScriptType(MAP_SCRIPT_ON_RESUME); } void RunOnReturnToFieldMapScript(void) { MapHeaderRunScriptType(MAP_SCRIPT_ON_RETURN_TO_FIELD); } void RunOnDiveWarpMapScript(void) { MapHeaderRunScriptType(MAP_SCRIPT_ON_DIVE_WARP); } bool8 TryRunOnFrameMapScript(void) { u8 *ptr = MapHeaderCheckScriptTable(MAP_SCRIPT_ON_FRAME_TABLE); if (!ptr) return FALSE; ScriptContext1_SetupScript(ptr); return TRUE; } void TryRunOnWarpIntoMapScript(void) { u8 *ptr = MapHeaderCheckScriptTable(MAP_SCRIPT_ON_WARP_INTO_MAP_TABLE); if (ptr) ScriptContext2_RunNewScript(ptr); } u32 CalculateRamScriptChecksum(void) { return CalcCRC16WithTable((u8*)(&gSaveBlock1Ptr->ramScript.data), sizeof(gSaveBlock1Ptr->ramScript.data)); } void ClearRamScript(void) { CpuFill32(0, &gSaveBlock1Ptr->ramScript, sizeof(struct RamScript)); } bool8 InitRamScript(const u8 *script, u16 scriptSize, u8 mapGroup, u8 mapNum, u8 objectId) { struct RamScriptData *scriptData = &gSaveBlock1Ptr->ramScript.data; ClearRamScript(); if (scriptSize > sizeof(scriptData->script)) return FALSE; scriptData->magic = RAM_SCRIPT_MAGIC; scriptData->mapGroup = mapGroup; scriptData->mapNum = mapNum; scriptData->objectId = objectId; memcpy(scriptData->script, script, scriptSize); gSaveBlock1Ptr->ramScript.checksum = CalculateRamScriptChecksum(); return TRUE; } const u8 *GetRamScript(u8 objectId, const u8 *script) { struct RamScriptData *scriptData = &gSaveBlock1Ptr->ramScript.data; gUnknown_020375C0 = NULL; if (scriptData->magic != RAM_SCRIPT_MAGIC) return script; if (scriptData->mapGroup != gSaveBlock1Ptr->location.mapGroup) return script; if (scriptData->mapNum != gSaveBlock1Ptr->location.mapNum) return script; if (scriptData->objectId != objectId) return script; if (CalculateRamScriptChecksum() != gSaveBlock1Ptr->ramScript.checksum) { ClearRamScript(); return script; } else { gUnknown_020375C0 = script; return scriptData->script; } } bool32 ValidateSavedRamScript(void) { struct RamScriptData *scriptData = &gSaveBlock1Ptr->ramScript.data; if (scriptData->magic != RAM_SCRIPT_MAGIC) return FALSE; if (scriptData->mapGroup != 0xFF) return FALSE; if (scriptData->mapNum != 0xFF) return FALSE; if (scriptData->objectId != 0xFF) return FALSE; if (CalculateRamScriptChecksum() != gSaveBlock1Ptr->ramScript.checksum) return FALSE; return TRUE; } u8 *GetSavedRamScriptIfValid(void) { struct RamScriptData *scriptData = &gSaveBlock1Ptr->ramScript.data; if (!ValidateReceivedWonderCard()) return NULL; if (scriptData->magic != RAM_SCRIPT_MAGIC) return NULL; if (scriptData->mapGroup != 0xFF) return NULL; if (scriptData->mapNum != 0xFF) return NULL; if (scriptData->objectId != 0xFF) return NULL; if (CalculateRamScriptChecksum() != gSaveBlock1Ptr->ramScript.checksum) { ClearRamScript(); return NULL; } else { return scriptData->script; } } void InitRamScript_NoObjectEvent(u8 *script, u16 scriptSize) { if (scriptSize > sizeof(gSaveBlock1Ptr->ramScript.data.script)) scriptSize = sizeof(gSaveBlock1Ptr->ramScript.data.script); InitRamScript(script, scriptSize, 0xFF, 0xFF, 0xFF); }