mirror of
				https://github.com/coop-deluxe/sm64coopdx.git
				synced 2025-10-30 08:01:01 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			434 lines
		
	
	
	
		
			14 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			434 lines
		
	
	
	
		
			14 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
#include "dynos.cpp.h"
 | 
						|
extern "C" {
 | 
						|
#include "game/segment2.h"
 | 
						|
#include "game/save_file.h"
 | 
						|
#include "levels/scripts.h"
 | 
						|
#include "pc/lua/utils/smlua_level_utils.h"
 | 
						|
#include "game/area.h"
 | 
						|
#include "game/level_update.h"
 | 
						|
}
 | 
						|
 | 
						|
//
 | 
						|
// Const
 | 
						|
//
 | 
						|
 | 
						|
extern "C" {
 | 
						|
extern const BehaviorScript *sWarpBhvSpawnTable[];
 | 
						|
#include "engine/level_script.h"
 | 
						|
}
 | 
						|
 | 
						|
#define DYNOS_LEVEL_MOD_INDEX_VANILLA (-1)
 | 
						|
 | 
						|
#define DYNOS_LEVEL_MARIO_POS_WARP_ID (-1)
 | 
						|
 | 
						|
extern void *gDynosLevelScriptsOriginal[LEVEL_COUNT];
 | 
						|
 | 
						|
void DynOS_Level_ParseScript(const void *aScript, s32 (*aPreprocessFunction)(u8, void *));
 | 
						|
 | 
						|
//
 | 
						|
// Data
 | 
						|
//
 | 
						|
 | 
						|
struct DynosWarp {
 | 
						|
/* 0 */ s16 mArea = 0;
 | 
						|
/* 1 */ s16 mId = 0;
 | 
						|
/* 2 */ s16 mType = -1;
 | 
						|
/* 3 */ s16 mPosX = 0;
 | 
						|
/* 4 */ s16 mPosY = 0;
 | 
						|
/* 5 */ s16 mPosZ = 0;
 | 
						|
/* 6 */ s16 mAngle = 0;
 | 
						|
/* 7 */ s16 mDestLevel = 0;
 | 
						|
/* 8 */ s16 mDestArea = 0;
 | 
						|
/* 9 */ s16 mDestId = 0;
 | 
						|
};
 | 
						|
 | 
						|
struct DynosLevelScript {
 | 
						|
    void *mLevelScript;
 | 
						|
    s32 mModIndex;
 | 
						|
};
 | 
						|
 | 
						|
static DynosLevelScript sDynosLevelScripts[LEVEL_COUNT] = { { NULL, DYNOS_LEVEL_MOD_INDEX_VANILLA } };
 | 
						|
static Array<DynosWarp> sDynosLevelWarps[LEVEL_COUNT] = { Array<DynosWarp>() };
 | 
						|
static Collision *sDynosLevelCollision[LEVEL_COUNT][MAX_AREAS] = { NULL };
 | 
						|
 | 
						|
u64 DynOS_Level_CmdGet(void *aCmd, u64 aOffset) {
 | 
						|
    u64 _Offset = (((aOffset) & 3llu) | (((aOffset) & ~3llu) << (sizeof(void *) >> 3llu)));
 | 
						|
    return *((u64 *) (u64(aCmd) + _Offset));
 | 
						|
}
 | 
						|
 | 
						|
LvlCmd *DynOS_Level_CmdNext(LvlCmd *aCmd) {
 | 
						|
    u64 aCmdSize = aCmd->mSize;
 | 
						|
    u64 _Offset = (((aCmdSize) & 3llu) | (((aCmdSize) & ~3llu) << (sizeof(void *) >> 3llu)));
 | 
						|
    return (LvlCmd*) (u64(aCmd) + _Offset);
 | 
						|
}
 | 
						|
 | 
						|
//
 | 
						|
// Init
 | 
						|
//
 | 
						|
 | 
						|
static s32 sDynosCurrentLevelNum;
 | 
						|
static u8 sDynosAreaIndex = 0;
 | 
						|
 | 
						|
inline static DynosWarp *DynOS_Level_GetWarpStruct(s8 aId) {
 | 
						|
    for (s32 i = 0; i != sDynosLevelWarps[sDynosCurrentLevelNum].Count(); ++i) {
 | 
						|
        if (sDynosLevelWarps[sDynosCurrentLevelNum][i].mArea == sDynosAreaIndex &&
 | 
						|
            sDynosLevelWarps[sDynosCurrentLevelNum][i].mId == aId) {
 | 
						|
            return &sDynosLevelWarps[sDynosCurrentLevelNum][i];
 | 
						|
        }
 | 
						|
    }
 | 
						|
    DynosWarp _Warp;
 | 
						|
    _Warp.mArea = sDynosAreaIndex;
 | 
						|
    _Warp.mId = aId;
 | 
						|
    sDynosLevelWarps[sDynosCurrentLevelNum].Add(_Warp);
 | 
						|
    return &sDynosLevelWarps[sDynosCurrentLevelNum][sDynosLevelWarps[sDynosCurrentLevelNum].Count() - 1];
 | 
						|
};
 | 
						|
 | 
						|
static s32 DynOS_Level_PreprocessScript(u8 aType, void *aCmd) {
 | 
						|
    switch (aType) {
 | 
						|
 | 
						|
        // AREA
 | 
						|
        case 0x1F: {
 | 
						|
            sDynosAreaIndex = (u8) DynOS_Level_CmdGet(aCmd, 2);
 | 
						|
        } break;
 | 
						|
 | 
						|
        // OBJECT
 | 
						|
        case 0x24: {
 | 
						|
            const BehaviorScript *bhv = (const BehaviorScript *) DynOS_Level_CmdGet(aCmd, 20);
 | 
						|
            for (s32 i = 0; i < 20; ++i) {
 | 
						|
                if (sWarpBhvSpawnTable[i] == bhv) {
 | 
						|
                    DynosWarp *_Warp = DynOS_Level_GetWarpStruct(((((u32) DynOS_Level_CmdGet(aCmd, 16)) >> 16) & 0xFF));
 | 
						|
                    if (_Warp->mType == -1) {
 | 
						|
                        _Warp->mType = i;
 | 
						|
                        _Warp->mPosX = (s16) DynOS_Level_CmdGet(aCmd, 4);
 | 
						|
                        _Warp->mPosY = (s16) DynOS_Level_CmdGet(aCmd, 6);
 | 
						|
                        _Warp->mPosZ = (s16) DynOS_Level_CmdGet(aCmd, 8);
 | 
						|
                        _Warp->mAngle = ((s16) DynOS_Level_CmdGet(aCmd, 12) * 0x8000) / 180;
 | 
						|
                    }
 | 
						|
                    break;
 | 
						|
                }
 | 
						|
            }
 | 
						|
        } break;
 | 
						|
 | 
						|
        // WARP_NODE or PAINTING_WARP_NODE
 | 
						|
        case 0x26:
 | 
						|
        case 0x27: {
 | 
						|
            DynosWarp *_Warp = DynOS_Level_GetWarpStruct((u8) DynOS_Level_CmdGet(aCmd, 2));
 | 
						|
            if (_Warp->mDestLevel == 0) {
 | 
						|
                _Warp->mDestLevel = (u8) DynOS_Level_CmdGet(aCmd, 3);
 | 
						|
                _Warp->mDestArea = (u8) DynOS_Level_CmdGet(aCmd, 4);
 | 
						|
                _Warp->mDestId = (u8) DynOS_Level_CmdGet(aCmd, 5);
 | 
						|
            }
 | 
						|
        } break;
 | 
						|
 | 
						|
        // MARIO_POS
 | 
						|
        case 0x2B: {
 | 
						|
            DynosWarp *_Warp = DynOS_Level_GetWarpStruct(DYNOS_LEVEL_MARIO_POS_WARP_ID);
 | 
						|
            _Warp->mArea = (s16) DynOS_Level_CmdGet(aCmd, 2);
 | 
						|
            _Warp->mAngle = ((s16) DynOS_Level_CmdGet(aCmd, 4) * 0x8000) / 180 - 0x8000;
 | 
						|
            _Warp->mPosX = (s16) DynOS_Level_CmdGet(aCmd, 6);
 | 
						|
            _Warp->mPosY = (s16) DynOS_Level_CmdGet(aCmd, 8);
 | 
						|
            _Warp->mPosZ = (s16) DynOS_Level_CmdGet(aCmd, 10);
 | 
						|
            _Warp->mType = MARIO_SPAWN_IDLE - 1;
 | 
						|
            _Warp->mDestLevel = sDynosCurrentLevelNum;
 | 
						|
            _Warp->mDestArea = _Warp->mArea;
 | 
						|
            _Warp->mDestId = DYNOS_LEVEL_MARIO_POS_WARP_ID;
 | 
						|
        } break;
 | 
						|
 | 
						|
        // SLEEP or SLEEP_BEFORE_EXIT
 | 
						|
        case 0x03:
 | 
						|
        case 0x04:
 | 
						|
            return 3;
 | 
						|
 | 
						|
        // TERRAIN
 | 
						|
        case 0x2E: {
 | 
						|
            sDynosLevelCollision[sDynosCurrentLevelNum][sDynosAreaIndex] = (Collision*) DynOS_Level_CmdGet(aCmd, 4);
 | 
						|
        } break;
 | 
						|
    }
 | 
						|
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
// Runs only once
 | 
						|
void DynOS_Level_Init() {
 | 
						|
    static bool sInited = false;
 | 
						|
    if (!sInited) {
 | 
						|
 | 
						|
        // Level warps
 | 
						|
        for (sDynosCurrentLevelNum = 0; sDynosCurrentLevelNum < LEVEL_COUNT; ++sDynosCurrentLevelNum) {
 | 
						|
            sDynosLevelScripts[sDynosCurrentLevelNum].mLevelScript = gDynosLevelScriptsOriginal[sDynosCurrentLevelNum];
 | 
						|
            sDynosLevelScripts[sDynosCurrentLevelNum].mModIndex = DYNOS_LEVEL_MOD_INDEX_VANILLA;
 | 
						|
            if (sDynosLevelScripts[sDynosCurrentLevelNum].mLevelScript) {
 | 
						|
                DynOS_Level_ParseScript(sDynosLevelScripts[sDynosCurrentLevelNum].mLevelScript, DynOS_Level_PreprocessScript);
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        // Done
 | 
						|
        sInited = true;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
//
 | 
						|
// Common
 | 
						|
//
 | 
						|
 | 
						|
s8 DynOS_Level_GetCourse(s32 aLevel) {
 | 
						|
    return get_level_course_num(aLevel);
 | 
						|
}
 | 
						|
 | 
						|
void DynOS_Level_Override(void* originalScript, void* newScript, s32 modIndex) {
 | 
						|
    for (s32 i = 0; i < LEVEL_COUNT; i++) {
 | 
						|
        if (sDynosLevelScripts[i].mLevelScript == originalScript) {
 | 
						|
            sDynosCurrentLevelNum = i;
 | 
						|
            sDynosLevelWarps[i].Clear();
 | 
						|
            DynOS_Level_ParseScript(newScript, DynOS_Level_PreprocessScript);
 | 
						|
            sDynosLevelScripts[i].mLevelScript = newScript;
 | 
						|
            sDynosLevelScripts[i].mModIndex = modIndex;
 | 
						|
            return;
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
void DynOS_Level_Unoverride() {
 | 
						|
    for (s32 i = 0; i < LEVEL_COUNT; i++) {
 | 
						|
        sDynosCurrentLevelNum = i;
 | 
						|
        sDynosLevelWarps[i].Clear();
 | 
						|
        sDynosLevelScripts[i].mLevelScript = gDynosLevelScriptsOriginal[i];
 | 
						|
        sDynosLevelScripts[i].mModIndex = DYNOS_LEVEL_MOD_INDEX_VANILLA;
 | 
						|
        DynOS_Level_ParseScript(sDynosLevelScripts[i].mLevelScript, DynOS_Level_PreprocessScript);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
const void *DynOS_Level_GetScript(s32 aLevel) {
 | 
						|
    if (aLevel >= CUSTOM_LEVEL_NUM_START) {
 | 
						|
        struct CustomLevelInfo* info = smlua_level_util_get_info(aLevel);
 | 
						|
        if (!info || !info->script) { return NULL; }
 | 
						|
        return info->script;
 | 
						|
    }
 | 
						|
 | 
						|
    DynOS_Level_Init();
 | 
						|
    return sDynosLevelScripts[aLevel].mLevelScript;
 | 
						|
}
 | 
						|
 | 
						|
s32 DynOS_Level_GetModIndex(s32 aLevel) {
 | 
						|
    if (aLevel >= CUSTOM_LEVEL_NUM_START) {
 | 
						|
        struct CustomLevelInfo* info = smlua_level_util_get_info(aLevel);
 | 
						|
        if (!info || !info->script) { return DYNOS_LEVEL_MOD_INDEX_VANILLA; }
 | 
						|
        return info->modIndex;
 | 
						|
    }
 | 
						|
 | 
						|
    DynOS_Level_Init();
 | 
						|
    return sDynosLevelScripts[aLevel].mModIndex;
 | 
						|
}
 | 
						|
 | 
						|
bool DynOS_Level_IsVanillaLevel(s32 aLevel) {
 | 
						|
    DynOS_Level_Init();
 | 
						|
 | 
						|
    if (aLevel >= LEVEL_MIN && aLevel < LEVEL_COUNT) {
 | 
						|
        return sDynosLevelScripts[aLevel].mLevelScript == gDynosLevelScriptsOriginal[aLevel];
 | 
						|
    }
 | 
						|
    return false;
 | 
						|
}
 | 
						|
 | 
						|
Collision *DynOS_Level_GetCollision(u32 aLevel, u16 aArea) {
 | 
						|
    if (aLevel >= LEVEL_COUNT) return NULL;
 | 
						|
    if (aArea >= MAX_AREAS) return NULL;
 | 
						|
    DynOS_Level_Init();
 | 
						|
    return sDynosLevelCollision[aLevel][aArea];
 | 
						|
}
 | 
						|
 | 
						|
//
 | 
						|
// Level Script Preprocessing
 | 
						|
// - Ifs are always true
 | 
						|
// - Skips are always false
 | 
						|
// - Loops break after the first loop
 | 
						|
//
 | 
						|
 | 
						|
struct Stack {
 | 
						|
    u64 mData[32];
 | 
						|
    s32 mBaseIndex;
 | 
						|
    s32 mTopIndex;
 | 
						|
};
 | 
						|
 | 
						|
template <typename T>
 | 
						|
static void StackPush(Stack& aStack, const T &aValue) {
 | 
						|
    if (aStack.mTopIndex >= 0) {
 | 
						|
        aStack.mData[aStack.mTopIndex] = u64(aValue);
 | 
						|
        aStack.mTopIndex++;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
template <typename T>
 | 
						|
static T StackPop(Stack& aStack) {
 | 
						|
    if (aStack.mTopIndex <= 0) {
 | 
						|
        return (T) 0;
 | 
						|
    }
 | 
						|
    aStack.mTopIndex--;
 | 
						|
    return (T) aStack.mData[aStack.mTopIndex];
 | 
						|
}
 | 
						|
 | 
						|
static LvlCmd *DynOS_Level_CmdExecute(Stack &aStack, LvlCmd *aCmd) {
 | 
						|
    StackPush(aStack, DynOS_Level_CmdNext(aCmd));
 | 
						|
    StackPush(aStack, aStack.mBaseIndex);
 | 
						|
    aStack.mBaseIndex = aStack.mTopIndex;
 | 
						|
    return (LvlCmd *) DynOS_Level_CmdGet(aCmd, 12);
 | 
						|
}
 | 
						|
 | 
						|
static LvlCmd *DynOS_Level_CmdExitAndExecute(Stack &aStack, LvlCmd *aCmd) {
 | 
						|
    aStack.mTopIndex = aStack.mBaseIndex;
 | 
						|
    return (LvlCmd *) DynOS_Level_CmdGet(aCmd, 12);
 | 
						|
}
 | 
						|
 | 
						|
static LvlCmd *DynOS_Level_CmdExit(Stack &aStack, LvlCmd *aCmd) {
 | 
						|
    aStack.mTopIndex = aStack.mBaseIndex;
 | 
						|
    aStack.mBaseIndex = StackPop<s32>(aStack);
 | 
						|
    return StackPop<LvlCmd *>(aStack);
 | 
						|
}
 | 
						|
 | 
						|
static LvlCmd *DynOS_Level_CmdJump(Stack &aStack, LvlCmd *aCmd) {
 | 
						|
    return (LvlCmd *) DynOS_Level_CmdGet(aCmd, 4);
 | 
						|
}
 | 
						|
 | 
						|
static LvlCmd *DynOS_Level_CmdJumpLink(Stack &aStack, LvlCmd *aCmd) {
 | 
						|
    StackPush(aStack, DynOS_Level_CmdNext(aCmd));
 | 
						|
    return (LvlCmd *) DynOS_Level_CmdGet(aCmd, 4);
 | 
						|
}
 | 
						|
 | 
						|
static LvlCmd *DynOS_Level_CmdReturn(Stack &aStack, UNUSED LvlCmd *aCmd) {
 | 
						|
    return StackPop<LvlCmd *>(aStack);
 | 
						|
}
 | 
						|
 | 
						|
static LvlCmd *DynOS_Level_CmdJumpLinkPushArg(Stack &aStack, LvlCmd *aCmd) {
 | 
						|
    StackPush(aStack, DynOS_Level_CmdNext(aCmd));
 | 
						|
    StackPush(aStack, DynOS_Level_CmdGet(aCmd, 2));
 | 
						|
    return DynOS_Level_CmdNext(aCmd);
 | 
						|
}
 | 
						|
 | 
						|
static LvlCmd *DynOS_Level_CmdJumpRepeat(Stack &aStack, LvlCmd *aCmd) {
 | 
						|
    aStack.mTopIndex -= 2;
 | 
						|
    return DynOS_Level_CmdNext(aCmd);
 | 
						|
}
 | 
						|
 | 
						|
static LvlCmd *DynOS_Level_CmdLoopBegin(Stack &aStack, LvlCmd *aCmd) {
 | 
						|
    StackPush(aStack, DynOS_Level_CmdNext(aCmd));
 | 
						|
    StackPush(aStack, 0);
 | 
						|
    return DynOS_Level_CmdNext(aCmd);
 | 
						|
}
 | 
						|
 | 
						|
static LvlCmd *DynOS_Level_CmdLoopUntil(Stack &aStack, LvlCmd *aCmd) {
 | 
						|
    aStack.mTopIndex -= 2;
 | 
						|
    return DynOS_Level_CmdNext(aCmd);
 | 
						|
}
 | 
						|
 | 
						|
static LvlCmd *DynOS_Level_CmdJumpIf(Stack &aStack, LvlCmd *aCmd) {
 | 
						|
    StackPush(aStack, DynOS_Level_CmdNext(aCmd)); /* Not an error, that's intentional */
 | 
						|
    return (LvlCmd *) DynOS_Level_CmdGet(aCmd, 8);
 | 
						|
}
 | 
						|
 | 
						|
static LvlCmd *DynOS_Level_CmdJumpLinkIf(Stack &aStack, LvlCmd *aCmd) {
 | 
						|
    StackPush(aStack, DynOS_Level_CmdNext(aCmd));
 | 
						|
    return (LvlCmd *) DynOS_Level_CmdGet(aCmd, 8);
 | 
						|
}
 | 
						|
 | 
						|
static LvlCmd *DynOS_Level_CmdJumpArea(Stack &aStack, LvlCmd *aCmd, s32 (*aPreprocessFunction)(u8, void *)) {
 | 
						|
    DynOS_Level_ParseScript((const void *) DynOS_Level_CmdGet(aCmd, 8), aPreprocessFunction);
 | 
						|
    return DynOS_Level_CmdNext(aCmd);
 | 
						|
}
 | 
						|
 | 
						|
void DynOS_Level_ParseScript(const void *aScript, s32 (*aPreprocessFunction)(u8, void *)) {
 | 
						|
    Stack _Stack;
 | 
						|
    _Stack.mBaseIndex = -1;
 | 
						|
    _Stack.mTopIndex = 0;
 | 
						|
    for (LvlCmd *_Cmd = (LvlCmd *) aScript; _Cmd != NULL;) {
 | 
						|
        u8 _CmdType = (_Cmd->mType & 0xFF);
 | 
						|
        s32 _Action = aPreprocessFunction(_CmdType, (void *) _Cmd);
 | 
						|
        switch (_Action) {
 | 
						|
            case 0:
 | 
						|
                switch (_CmdType) {
 | 
						|
                    case 0x00: _Cmd = DynOS_Level_CmdExecute(_Stack, _Cmd);         break;
 | 
						|
                    case 0x01: _Cmd = DynOS_Level_CmdExitAndExecute(_Stack, _Cmd);  break;
 | 
						|
                    case 0x02: _Cmd = DynOS_Level_CmdExit(_Stack, _Cmd);            break;
 | 
						|
                    case 0x05: _Cmd = DynOS_Level_CmdJump(_Stack, _Cmd);            break;
 | 
						|
                    case 0x06: _Cmd = DynOS_Level_CmdJumpLink(_Stack, _Cmd);        break;
 | 
						|
                    case 0x07: _Cmd = DynOS_Level_CmdReturn(_Stack, _Cmd);          break;
 | 
						|
                    case 0x08: _Cmd = DynOS_Level_CmdJumpLinkPushArg(_Stack, _Cmd); break;
 | 
						|
                    case 0x09: _Cmd = DynOS_Level_CmdJumpRepeat(_Stack, _Cmd);      break;
 | 
						|
                    case 0x0A: _Cmd = DynOS_Level_CmdLoopBegin(_Stack, _Cmd);       break;
 | 
						|
                    case 0x0B: _Cmd = DynOS_Level_CmdLoopUntil(_Stack, _Cmd);       break;
 | 
						|
                    case 0x0C: _Cmd = DynOS_Level_CmdJumpIf(_Stack, _Cmd);          break;
 | 
						|
                    case 0x0D: _Cmd = DynOS_Level_CmdJumpLinkIf(_Stack, _Cmd);      break;
 | 
						|
 | 
						|
                    // coop
 | 
						|
                    case 0x42: _Cmd = DynOS_Level_CmdJumpArea(_Stack, _Cmd, aPreprocessFunction); break;
 | 
						|
 | 
						|
                    default: _Cmd = DynOS_Level_CmdNext(_Cmd); break;
 | 
						|
                } break;
 | 
						|
 | 
						|
            case 1:
 | 
						|
                _Cmd = DynOS_Level_CmdNext(_Cmd);
 | 
						|
                break;
 | 
						|
 | 
						|
            case 2:
 | 
						|
                _Cmd = DynOS_Level_CmdReturn(_Stack, _Cmd);
 | 
						|
                break;
 | 
						|
 | 
						|
            case 3:
 | 
						|
                return;
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
//
 | 
						|
// Level Script Utilities
 | 
						|
//
 | 
						|
 | 
						|
s16 *DynOS_Level_GetWarp(s32 aLevel, s32 aArea, s8 aWarpId) {
 | 
						|
    if (aLevel >= CUSTOM_LEVEL_NUM_START) {
 | 
						|
        struct CustomLevelInfo* info = smlua_level_util_get_info(aLevel);
 | 
						|
        if (!info || !info->script) { return NULL; }
 | 
						|
        sDynosCurrentLevelNum = 1;
 | 
						|
        DynOS_Level_ParseScript(info->script, DynOS_Level_PreprocessScript);
 | 
						|
        for (const auto &_Warp : sDynosLevelWarps[1]) {
 | 
						|
            if (_Warp.mArea == aArea && _Warp.mId == aWarpId) {
 | 
						|
                return (s16 *) &_Warp;
 | 
						|
            }
 | 
						|
        }
 | 
						|
        return NULL;
 | 
						|
    }
 | 
						|
 | 
						|
    DynOS_Level_Init();
 | 
						|
    if (aLevel >= 0 && aLevel < LEVEL_COUNT) {
 | 
						|
        for (const auto &_Warp : sDynosLevelWarps[aLevel]) {
 | 
						|
            if (_Warp.mArea == aArea && _Warp.mId == aWarpId) {
 | 
						|
                return (s16 *) &_Warp;
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
    return NULL;
 | 
						|
}
 | 
						|
 | 
						|
s16 *DynOS_Level_GetWarpEntry(s32 aLevel, s32 aArea) {
 | 
						|
    DynOS_Level_Init();
 | 
						|
 | 
						|
    // override vanilla castle warps
 | 
						|
    if (DynOS_Level_GetCourse(aLevel) == COURSE_NONE && aLevel >= 0 && aLevel < LEVEL_COUNT) {
 | 
						|
        extern const LevelScript level_castle_grounds_entry[];
 | 
						|
        extern const LevelScript level_castle_inside_entry[];
 | 
						|
        extern const LevelScript level_castle_courtyard_entry[];
 | 
						|
        if (sDynosLevelScripts[aLevel].mLevelScript == level_castle_inside_entry) {
 | 
						|
            return DynOS_Level_GetWarp(aLevel, aArea, (aArea == 3) ? 0x00 : 0x01);
 | 
						|
        } else if (sDynosLevelScripts[aLevel].mLevelScript == level_castle_grounds_entry) {
 | 
						|
            return DynOS_Level_GetWarp(aLevel, aArea, DYNOS_LEVEL_MARIO_POS_WARP_ID);
 | 
						|
        } else if (sDynosLevelScripts[aLevel].mLevelScript == level_castle_courtyard_entry) {
 | 
						|
            return DynOS_Level_GetWarp(aLevel, aArea, 0x01);
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    return DynOS_Level_GetWarp(aLevel, aArea, 0x0A);
 | 
						|
}
 | 
						|
 | 
						|
s16 *DynOS_Level_GetWarpDeath(s32 aLevel, s32 aArea) {
 | 
						|
    DynOS_Level_Init();
 | 
						|
    s16 *_Warp = DynOS_Level_GetWarp(aLevel, aArea, 0xF1);
 | 
						|
    if (!_Warp) _Warp = DynOS_Level_GetWarp(aLevel, aArea, 0xF3);
 | 
						|
    return _Warp;
 | 
						|
}
 |