mirror of
https://github.com/coop-deluxe/sm64coopdx.git
synced 2024-11-21 11:35:11 +00:00
Added DynOS v1.1 without the dynamic options
- Added support for coop-specific actors - Added support for coop-specific geo functions - Added support for coop-specific model functions
This commit is contained in:
parent
5e0981824a
commit
b3ed387711
25 changed files with 5744 additions and 10 deletions
3
Makefile
3
Makefile
|
@ -543,6 +543,9 @@ DEP_FILES := $(O_FILES:.o=.d) $(ULTRA_O_FILES:.o=.d) $(GODDARD_O_FILES:.o=.d) $(
|
|||
# Segment elf files
|
||||
SEG_FILES := $(SEGMENT_ELF_FILES) $(ACTOR_ELF_FILES) $(LEVEL_ELF_FILES)
|
||||
|
||||
# Dynos
|
||||
include dynos.mk
|
||||
|
||||
##################### Compiler Options #######################
|
||||
INCLUDE_CFLAGS := -I include -I $(BUILD_DIR) -I $(BUILD_DIR)/include -I src -I . $(EXTRA_INCLUDES)
|
||||
ENDIAN_BITWIDTH := $(BUILD_DIR)/endian-and-bitwidth
|
||||
|
|
18
data/dynos.c.h
Normal file
18
data/dynos.c.h
Normal file
|
@ -0,0 +1,18 @@
|
|||
#ifndef DYNOS_C_H
|
||||
#define DYNOS_C_H
|
||||
#ifndef __cplusplus
|
||||
|
||||
#include "dynos.h"
|
||||
|
||||
void *dynos_update_cmd (void *cmd);
|
||||
void dynos_update_gfx ();
|
||||
void dynos_update_opt (void *pad);
|
||||
s32 dynos_gfx_import_texture (void **output, void *ptr, s32 tile, void *grapi, void **hashmap, void *pool, s32 *poolpos, s32 poolsize);
|
||||
void dynos_gfx_swap_animations(void *ptr);
|
||||
|
||||
#ifdef COOP
|
||||
bool dynos_warp_to_level(s32 aLevel, s32 aArea, s32 aAct);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
#endif
|
701
data/dynos.cpp.h
Normal file
701
data/dynos.cpp.h
Normal file
|
@ -0,0 +1,701 @@
|
|||
#ifndef DYNOS_CPP_H
|
||||
#define DYNOS_CPP_H
|
||||
#ifdef __cplusplus
|
||||
|
||||
#include "dynos.h"
|
||||
extern "C" {
|
||||
#include "engine/math_util.h"
|
||||
}
|
||||
|
||||
#define FUNCTION_CODE (u32) 0x434E5546
|
||||
#define POINTER_CODE (u32) 0x52544E50
|
||||
|
||||
//
|
||||
// Enums
|
||||
//
|
||||
|
||||
enum {
|
||||
DATA_TYPE_NONE = 0,
|
||||
DATA_TYPE_LIGHT,
|
||||
DATA_TYPE_TEXTURE,
|
||||
DATA_TYPE_VERTEX,
|
||||
DATA_TYPE_DISPLAY_LIST,
|
||||
DATA_TYPE_GEO_LAYOUT,
|
||||
DATA_TYPE_ANIMATION_VALUE,
|
||||
DATA_TYPE_ANIMATION_INDEX,
|
||||
DATA_TYPE_ANIMATION,
|
||||
DATA_TYPE_ANIMATION_TABLE,
|
||||
DATA_TYPE_GFXDYNCMD,
|
||||
DATA_TYPE_UNUSED,
|
||||
};
|
||||
|
||||
enum {
|
||||
DOPT_NONE = 0,
|
||||
|
||||
DOPT_TOGGLE,
|
||||
DOPT_CHOICE,
|
||||
DOPT_SCROLL,
|
||||
DOPT_BIND,
|
||||
DOPT_BUTTON,
|
||||
DOPT_SUBMENU,
|
||||
|
||||
// These ones are used by the Warp to Level built-in submenu
|
||||
DOPT_CHOICELEVEL,
|
||||
DOPT_CHOICEAREA,
|
||||
DOPT_CHOICESTAR,
|
||||
DOPT_CHOICEPARAM,
|
||||
};
|
||||
|
||||
//
|
||||
// DynOS Array
|
||||
// A vector-like array, implemented to be processed really fast, but cannot handle C++ complex classes like std::string
|
||||
//
|
||||
|
||||
template <typename T>
|
||||
class Array {
|
||||
public:
|
||||
inline Array() : mBuffer(NULL), mCount(0), mCapacity(0) {
|
||||
}
|
||||
|
||||
inline Array(const std::initializer_list<T> &aList) : mBuffer(NULL), mCount(0), mCapacity(0) {
|
||||
Resize(aList.size());
|
||||
memcpy(mBuffer, aList.begin(), mCount * sizeof(T));
|
||||
}
|
||||
|
||||
inline Array(const T *aBegin, const T *aEnd) : mBuffer(NULL), mCount(0), mCapacity(0) {
|
||||
Resize(aEnd - aBegin);
|
||||
memcpy(mBuffer, aBegin, mCount * sizeof(T));
|
||||
}
|
||||
|
||||
inline Array(const Array &aOther) : mBuffer(NULL), mCount(0), mCapacity(0) {
|
||||
Resize(aOther.mCount);
|
||||
memcpy(mBuffer, aOther.mBuffer, mCount * sizeof(T));
|
||||
}
|
||||
|
||||
inline void operator=(const Array &aOther) {
|
||||
Resize(aOther.mCount);
|
||||
memcpy(mBuffer, aOther.mBuffer, mCount * sizeof(T));
|
||||
}
|
||||
|
||||
inline ~Array() {
|
||||
Clear();
|
||||
}
|
||||
|
||||
public:
|
||||
void Resize(s32 aCount) {
|
||||
if (aCount > mCapacity) {
|
||||
mCapacity = MAX(aCount, MAX(16, mCapacity * 2));
|
||||
T *_Buffer = (T *) calloc(mCapacity, sizeof(T));
|
||||
if (mBuffer) {
|
||||
memcpy(_Buffer, mBuffer, mCount * sizeof(T));
|
||||
free(mBuffer);
|
||||
}
|
||||
mBuffer = _Buffer;
|
||||
}
|
||||
mCount = aCount;
|
||||
}
|
||||
|
||||
void Add(const T& aItem) {
|
||||
Resize(mCount + 1);
|
||||
mBuffer[mCount - 1] = aItem;
|
||||
}
|
||||
|
||||
void Remove(s32 aIndex) {
|
||||
memmove(mBuffer + aIndex, mBuffer + aIndex + 1, (mCount - aIndex - 1) * sizeof(T));
|
||||
mCount--;
|
||||
}
|
||||
|
||||
void Pop() {
|
||||
mCount--;
|
||||
}
|
||||
|
||||
void RemoveAll() {
|
||||
mCount = 0;
|
||||
}
|
||||
|
||||
void Clear() {
|
||||
if (mBuffer) free(mBuffer);
|
||||
mBuffer = NULL;
|
||||
mCount = 0;
|
||||
mCapacity = 0;
|
||||
}
|
||||
|
||||
s32 Find(const T& aItem) const {
|
||||
for (s32 i = 0; i != mCount; ++i) {
|
||||
if (mBuffer[i] == aItem) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
template <typename Predicate>
|
||||
s32 FindIf(Predicate aPredicate) const {
|
||||
for (s32 i = 0; i != mCount; ++i) {
|
||||
if (aPredicate(mBuffer[i])) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public:
|
||||
inline const T *begin() const { return mBuffer; }
|
||||
inline const T *end() const { return mBuffer + mCount; }
|
||||
inline T *begin() { return mBuffer; }
|
||||
inline T *end() { return mBuffer + mCount; }
|
||||
|
||||
inline const T &operator[](s32 aIndex) const { return mBuffer[aIndex]; }
|
||||
inline T &operator[](s32 aIndex) { return mBuffer[aIndex]; }
|
||||
|
||||
inline s32 Count() const { return mCount; }
|
||||
inline bool Empty() const { return mCount == 0; }
|
||||
|
||||
public:
|
||||
void Read(FILE *aFile) {
|
||||
s32 _Length = 0; fread(&_Length, sizeof(s32), 1, aFile);
|
||||
Resize(_Length);
|
||||
fread(mBuffer, sizeof(T), _Length, aFile);
|
||||
}
|
||||
|
||||
void Write(FILE *aFile) const {
|
||||
fwrite(&mCount, sizeof(s32), 1, aFile);
|
||||
fwrite(mBuffer, sizeof(T), mCount, aFile);
|
||||
}
|
||||
|
||||
private:
|
||||
T *mBuffer;
|
||||
s32 mCount;
|
||||
s32 mCapacity;
|
||||
};
|
||||
|
||||
//
|
||||
// DynOS String
|
||||
// A fixed-size string that doesn't require heap memory allocation
|
||||
//
|
||||
|
||||
#define STRING_SIZE 127
|
||||
class String {
|
||||
public:
|
||||
inline String() : mCount(0) {
|
||||
mBuffer[0] = 0;
|
||||
}
|
||||
|
||||
inline String(const char *aString) : mCount(0) {
|
||||
if (aString) {
|
||||
u64 _Length = strlen(aString);
|
||||
mCount = MIN(_Length, STRING_SIZE - 1);
|
||||
memcpy(mBuffer, aString, _Length);
|
||||
}
|
||||
mBuffer[mCount] = 0;
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
inline String(const char *aFmt, Args... aArgs) : mCount(0) {
|
||||
snprintf(mBuffer, STRING_SIZE, aFmt, aArgs...);
|
||||
mCount = (u8) strlen(mBuffer);
|
||||
mBuffer[mCount] = 0;
|
||||
}
|
||||
|
||||
inline String(const String &aOther) : mCount(0) {
|
||||
mCount = aOther.mCount;
|
||||
memcpy(mBuffer, aOther.mBuffer, mCount);
|
||||
mBuffer[mCount] = 0;
|
||||
}
|
||||
|
||||
inline void operator=(const String &aOther) {
|
||||
mCount = aOther.mCount;
|
||||
memcpy(mBuffer, aOther.mBuffer, mCount);
|
||||
mBuffer[mCount] = 0;
|
||||
}
|
||||
|
||||
public:
|
||||
void Add(char aChar) {
|
||||
if (mCount == STRING_SIZE - 1) return;
|
||||
mBuffer[mCount++] = aChar;
|
||||
mBuffer[mCount] = 0;
|
||||
}
|
||||
|
||||
void Remove(s32 aIndex) {
|
||||
memmove(mBuffer + aIndex, mBuffer + aIndex + 1, (mCount-- - aIndex - 1));
|
||||
mBuffer[mCount] = 0;
|
||||
}
|
||||
|
||||
void RemoveAll() {
|
||||
mCount = 0;
|
||||
mBuffer[0] = 0;
|
||||
}
|
||||
|
||||
void Clear() {
|
||||
mCount = 0;
|
||||
mBuffer[0] = 0;
|
||||
}
|
||||
|
||||
s32 Find(char aChar, s32 aStart = 0) const {
|
||||
for (u8 i = (u8) aStart; i < mCount; ++i) {
|
||||
if (mBuffer[i] == aChar) {
|
||||
return (s32) i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
s32 Find(const char *aString, s32 aStart = 0) const {
|
||||
const char *_Ptr = strstr(mBuffer + aStart, aString);
|
||||
if (_Ptr) return (s32) (_Ptr - mBuffer);
|
||||
return -1;
|
||||
}
|
||||
|
||||
s32 FindLast(char aChar) const {
|
||||
for (u8 i = mCount; i != 0; --i) {
|
||||
if (mBuffer[i - 1] == aChar) {
|
||||
return (s32) (i - 1);
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
String SubString(s32 aStart, s32 aCount = STRING_SIZE - 1) const {
|
||||
if (aStart >= mCount) return String();
|
||||
if (aCount < 0) aCount = STRING_SIZE - 1;
|
||||
aCount = MIN(aCount, mCount - aStart);
|
||||
String _String;
|
||||
_String.mCount = aCount;
|
||||
memcpy(_String.mBuffer, mBuffer + aStart, aCount);
|
||||
_String.mBuffer[aCount] = 0;
|
||||
return _String;
|
||||
}
|
||||
|
||||
public:
|
||||
inline const char *begin() const { return mBuffer; }
|
||||
inline const char *end() const { return mBuffer + mCount; }
|
||||
inline char *begin() { return mBuffer; }
|
||||
inline char *end() { return mBuffer + mCount; }
|
||||
|
||||
inline const char &operator[](s32 aIndex) const { return mBuffer[aIndex]; }
|
||||
inline char &operator[](s32 aIndex) { return mBuffer[aIndex]; }
|
||||
|
||||
inline s32 Length() const { return (s32) mCount; }
|
||||
inline bool Empty() const { return mCount == 0; }
|
||||
|
||||
public:
|
||||
bool operator==(const char *aString) const {
|
||||
if (strlen(aString) != mCount) return false;
|
||||
for (u8 i = 0; i != mCount; ++i) {
|
||||
if (aString[i] != mBuffer[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool operator==(const String &aOther) const {
|
||||
if (aOther.mCount != mCount) return false;
|
||||
for (u8 i = 0; i != mCount; ++i) {
|
||||
if (aOther.mBuffer[i] != mBuffer[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool operator!=(const char *aString) const {
|
||||
if (strlen(aString) != mCount) return true;
|
||||
for (u8 i = 0; i != mCount; ++i) {
|
||||
if (aString[i] != mBuffer[i]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool operator!=(const String &aOther) const {
|
||||
if (aOther.mCount != mCount) return true;
|
||||
for (u8 i = 0; i != mCount; ++i) {
|
||||
if (aOther.mBuffer[i] != mBuffer[i]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public:
|
||||
void Read(FILE *aFile) {
|
||||
fread(&mCount, sizeof(u8), 1, aFile);
|
||||
fread(mBuffer, sizeof(char), mCount, aFile);
|
||||
mBuffer[mCount] = 0;
|
||||
}
|
||||
|
||||
void Write(FILE *aFile) const {
|
||||
fwrite(&mCount, sizeof(u8), 1, aFile);
|
||||
fwrite(mBuffer, sizeof(char), mCount, aFile);
|
||||
}
|
||||
|
||||
s32 ParseInt() const {
|
||||
s32 i = 0;
|
||||
if (mBuffer[1] == 'x') {
|
||||
sscanf(mBuffer + 2, "%x", &i);
|
||||
} else {
|
||||
sscanf(mBuffer, "%d", &i);
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
f32 ParseFloat() const {
|
||||
f32 f = 0.f;
|
||||
sscanf(mBuffer, "%f", &f);
|
||||
return f;
|
||||
}
|
||||
|
||||
private:
|
||||
char mBuffer[STRING_SIZE];
|
||||
u8 mCount;
|
||||
};
|
||||
static_assert(sizeof(String) == (STRING_SIZE + 1), "sizeof(String) must be (STRING_SIZE + 1)");
|
||||
|
||||
//
|
||||
// Types
|
||||
//
|
||||
|
||||
template <typename U, typename V>
|
||||
using Pair = std::pair<U, V>;
|
||||
|
||||
typedef std::string SysPath;
|
||||
|
||||
class NoCopy {
|
||||
protected:
|
||||
NoCopy() {}
|
||||
~NoCopy() {}
|
||||
private:
|
||||
NoCopy(const NoCopy &) = delete;
|
||||
void operator=(const NoCopy &) = delete;
|
||||
};
|
||||
|
||||
struct TexData : NoCopy {
|
||||
Array<u8> mPngData;
|
||||
Array<u8> mRawData;
|
||||
s32 mRawWidth = -1;
|
||||
s32 mRawHeight = -1;
|
||||
s32 mRawFormat = -1;
|
||||
s32 mRawSize = -1;
|
||||
bool mUploaded = false;
|
||||
};
|
||||
|
||||
struct AnimData : NoCopy {
|
||||
s16 mFlags = 0;
|
||||
s16 mUnk02 = 0;
|
||||
s16 mUnk04 = 0;
|
||||
s16 mUnk06 = 0;
|
||||
s16 mUnk08 = 0;
|
||||
Pair<String, s16> mUnk0A;
|
||||
Pair<String, Array<s16>> mValues;
|
||||
Pair<String, Array<u16>> mIndex;
|
||||
u32 mLength = 0;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct DataNode : NoCopy {
|
||||
String mName;
|
||||
T* mData = NULL;
|
||||
u32 mSize = 0;
|
||||
Array<String> mTokens;
|
||||
u64 mModelIdentifier = 0;
|
||||
u64 mLoadIndex = 0;
|
||||
};
|
||||
template <typename T>
|
||||
using DataNodes = Array<DataNode<T>*>;
|
||||
|
||||
struct GfxContext {
|
||||
DataNode<TexData>* mCurrentTexture = NULL;
|
||||
DataNode<TexData>* mCurrentPalette = NULL;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
using AnimBuffer = Pair<String, Array<T>>;
|
||||
struct GfxData : NoCopy {
|
||||
|
||||
// Model data
|
||||
DataNodes<Lights1> mLights;
|
||||
DataNodes<TexData> mTextures;
|
||||
DataNodes<Vtx> mVertices;
|
||||
DataNodes<Gfx> mDisplayLists;
|
||||
DataNodes<GeoLayout> mGeoLayouts;
|
||||
|
||||
// Animation data
|
||||
Array<AnimBuffer<s16> *> mAnimValues;
|
||||
Array<AnimBuffer<u16> *> mAnimIndices;
|
||||
DataNodes<AnimData> mAnimations;
|
||||
Array<Pair<String, void *>> mAnimationTable;
|
||||
|
||||
// Current
|
||||
u64 mLoadIndex = 0;
|
||||
s32 mErrorCount = 0;
|
||||
u32 mModelIdentifier = 0;
|
||||
SysPath mPackFolder;
|
||||
Array<void *> mPointerList;
|
||||
GfxContext mGfxContext;
|
||||
Array<GfxContext> mGeoNodeStack;
|
||||
};
|
||||
|
||||
struct ActorGfx {
|
||||
GfxData *mGfxData = NULL;
|
||||
GraphNode *mGraphNode = NULL;
|
||||
s32 mPackIndex = 0;
|
||||
};
|
||||
|
||||
struct PackData {
|
||||
SysPath mPath;
|
||||
};
|
||||
|
||||
typedef Pair<String, const u8 *> Label;
|
||||
struct DynosOption : NoCopy {
|
||||
String mName;
|
||||
String mConfigName; // Name used in the config file
|
||||
Label mLabel;
|
||||
Label mTitle; // Full caps label, displayed with colored font
|
||||
DynosOption *mPrev;
|
||||
DynosOption *mNext;
|
||||
DynosOption *mParent;
|
||||
bool mDynos; // true from create, false from convert
|
||||
u8 mType;
|
||||
|
||||
// TOGGLE
|
||||
struct Toggle : NoCopy {
|
||||
bool *mTog;
|
||||
} mToggle;
|
||||
|
||||
// CHOICE
|
||||
struct Choice : NoCopy {
|
||||
Array<Label> mChoices;
|
||||
s32 *mIndex;
|
||||
} mChoice;
|
||||
|
||||
// SCROLL
|
||||
struct Scroll : NoCopy {
|
||||
s32 mMin;
|
||||
s32 mMax;
|
||||
s32 mStep;
|
||||
s32 *mValue;
|
||||
} mScroll;
|
||||
|
||||
// BIND
|
||||
struct Bind : NoCopy {
|
||||
u32 mMask;
|
||||
u32 *mBinds;
|
||||
s32 mIndex;
|
||||
} mBind;
|
||||
|
||||
// BUTTON
|
||||
struct Button : NoCopy {
|
||||
String mFuncName;
|
||||
} mButton;
|
||||
|
||||
// SUBMENU
|
||||
struct Submenu : NoCopy {
|
||||
DynosOption *mChild;
|
||||
bool mEmpty;
|
||||
} mSubMenu;
|
||||
};
|
||||
typedef bool (*DynosLoopFunc)(DynosOption *, void *);
|
||||
|
||||
//
|
||||
// Utils
|
||||
//
|
||||
|
||||
template <typename T>
|
||||
T* New(u64 aCount = 1llu) {
|
||||
T *_Ptr = (T *) calloc(aCount, sizeof(T));
|
||||
for (u64 i = 0; i != aCount; ++i) {
|
||||
new (_Ptr + i) T(); // Calls the constructor of type T at address (_Ptr + i)
|
||||
}
|
||||
return _Ptr;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void Delete(T *& aPtr) {
|
||||
if (aPtr) {
|
||||
aPtr->~T();
|
||||
free(aPtr);
|
||||
}
|
||||
aPtr = NULL;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T *CopyBytes(const T *aPtr, u64 aSize) {
|
||||
T *_Ptr = (T *) calloc(1, aSize);
|
||||
memcpy(_Ptr, aPtr, aSize);
|
||||
return _Ptr;
|
||||
}
|
||||
|
||||
template <typename T = void>
|
||||
Array<String> Split(const char *aBuffer, const String &aDelimiters, const String &aEndCharacters = {}, bool aHandleDoubleQuotedStrings = false) {
|
||||
Array<String> _Tokens;
|
||||
String _Token;
|
||||
bool _TreatSpaceAsChar = false;
|
||||
u64 _Length = strlen(aBuffer);
|
||||
for (u64 i = 0; i <= _Length; ++i) {
|
||||
if (i == _Length || aDelimiters.Find(aBuffer[i]) != -1) {
|
||||
if (aBuffer[i] == ' ' && _TreatSpaceAsChar) {
|
||||
_Token.Add(aBuffer[i]);
|
||||
} else {
|
||||
if (!_Token.Empty()) {
|
||||
_Tokens.Add(_Token);
|
||||
_Token.Clear();
|
||||
}
|
||||
if (aEndCharacters.Find(aBuffer[i]) != -1) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (aBuffer[i] == '\"' && aHandleDoubleQuotedStrings) {
|
||||
_TreatSpaceAsChar = !_TreatSpaceAsChar;
|
||||
} else {
|
||||
_Token.Add(aBuffer[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return _Tokens;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T ReadBytes(FILE* aFile) {
|
||||
T _Item = { 0 };
|
||||
fread(&_Item, sizeof(T), 1, aFile);
|
||||
return _Item;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void WriteBytes(FILE* aFile, const T& aItem) {
|
||||
fwrite(&aItem, sizeof(T), 1, aFile);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
void PrintNoNewLine(const char *aFmt, Args... aArgs) {
|
||||
printf(aFmt, aArgs...);
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
void Print(const char *aFmt, Args... aArgs) {
|
||||
printf(aFmt, aArgs...);
|
||||
printf("\r\n");
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
#define PrintError(...) { \
|
||||
if (aGfxData->mErrorCount == 0) Print(" ERROR!"); \
|
||||
Print(__VA_ARGS__); \
|
||||
aGfxData->mErrorCount++; \
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
SysPath fstring(const char *aFmt, Args... aArgs) {
|
||||
char buffer[1024];
|
||||
snprintf(buffer, 1024, aFmt, aArgs...);
|
||||
return SysPath(buffer);
|
||||
}
|
||||
|
||||
// Wraps the static into a function, to call the constructor on first use
|
||||
#define STATIC_STORAGE(type, name) \
|
||||
static type &__##name() { \
|
||||
static type s##name; \
|
||||
return s##name; \
|
||||
}
|
||||
|
||||
//
|
||||
// Main
|
||||
//
|
||||
|
||||
void DynOS_UpdateOpt(void *aPad);
|
||||
void *DynOS_UpdateCmd(void *aCmd);
|
||||
void DynOS_UpdateGfx();
|
||||
bool DynOS_IsTransitionActive();
|
||||
void DynOS_ReturnToMainMenu();
|
||||
|
||||
//
|
||||
// Opt
|
||||
//
|
||||
|
||||
#ifndef COOP
|
||||
s32 DynOS_Opt_GetValue(const String &aName);
|
||||
void DynOS_Opt_SetValue(const String &aName, s32 aValue);
|
||||
void DynOS_Opt_AddAction(const String &aFuncName, bool (*aFuncPtr)(const char *), bool aOverwrite);
|
||||
void DynOS_Opt_Init();
|
||||
void DynOS_Opt_InitVanilla(DynosOption *&aOptionsMenu);
|
||||
void DynOS_Opt_Update(OSContPad *aPad);
|
||||
bool DynOS_Opt_ControllerUpdate(DynosOption *aOpt, void *aData);
|
||||
s32 DynOS_Opt_ControllerGetKeyPressed();
|
||||
void DynOS_Opt_LoadConfig(DynosOption *aMenu);
|
||||
void DynOS_Opt_SaveConfig(DynosOption *aMenu);
|
||||
void DynOS_Opt_DrawMenu(DynosOption *aCurrentOption, DynosOption *aCurrentMenu, DynosOption *aOptionsMenu, DynosOption *aDynosMenu);
|
||||
void DynOS_Opt_DrawPrompt(DynosOption *aCurrentMenu, DynosOption *aOptionsMenu, DynosOption *aDynosMenu);
|
||||
#endif
|
||||
|
||||
//
|
||||
// Gfx
|
||||
//
|
||||
|
||||
u8 *DynOS_Gfx_TextureConvertToRGBA32(const u8 *aData, u64 aLength, s32 aFormat, s32 aSize, const u8 *aPalette);
|
||||
bool DynOS_Gfx_ImportTexture(void **aOutput, void *aPtr, s32 aTile, void *aGfxRApi, void **aHashMap, void *aPool, u32 *aPoolPos, u32 aPoolSize);
|
||||
Array<ActorGfx> &DynOS_Gfx_GetActorList();
|
||||
Array<PackData *> &DynOS_Gfx_GetPacks();
|
||||
Array<String> DynOS_Gfx_Init();
|
||||
void DynOS_Gfx_Update();
|
||||
void DynOS_Gfx_SwapAnimations(void *aPtr);
|
||||
bool DynOS_Gfx_WriteBinary(const SysPath &aOutputFilename, GfxData *aGfxData);
|
||||
GfxData *DynOS_Gfx_LoadFromBinary(const SysPath &aPackFolder, const char *aActorName);
|
||||
void DynOS_Gfx_Free(GfxData *aGfxData);
|
||||
void DynOS_Gfx_GeneratePack(const SysPath &aPackFolder);
|
||||
|
||||
//
|
||||
// String
|
||||
//
|
||||
|
||||
u8 *DynOS_String_Convert(const char *aString, bool aHeapAlloc);
|
||||
u8 *DynOS_String_Decapitalize(u8 *aStr64);
|
||||
s32 DynOS_String_Length(const u8 *aStr64);
|
||||
s32 DynOS_String_WidthChar64(u8 aChar64);
|
||||
s32 DynOS_String_Width(const u8 *aStr64);
|
||||
|
||||
//
|
||||
// Geo
|
||||
//
|
||||
|
||||
s32 DynOS_Geo_GetActorCount();
|
||||
const char *DynOS_Geo_GetActorName(s32 aIndex);
|
||||
const void *DynOS_Geo_GetActorLayout(s32 aIndex);
|
||||
s32 DynOS_Geo_GetActorIndex(const void *aGeoLayout);
|
||||
void *DynOS_Geo_GetFunctionPointerFromName(const String &aName);
|
||||
void *DynOS_Geo_GetFunctionPointerFromIndex(s32 aIndex);
|
||||
s32 DynOS_Geo_GetFunctionIndex(const void *aPtr);
|
||||
void *DynOS_Geo_GetGraphNode(const void *aGeoLayout, bool aKeepInMemory);
|
||||
|
||||
//
|
||||
// Levels
|
||||
//
|
||||
|
||||
s32 DynOS_Level_GetCount();
|
||||
const s32 *DynOS_Level_GetList();
|
||||
s32 DynOS_Level_GetCourse(s32 aLevel);
|
||||
const void *DynOS_Level_GetScript(s32 aLevel);
|
||||
const u8 *DynOS_Level_GetName(s32 aLevel, bool aDecaps, bool aAddCourseNumber);
|
||||
const u8 *DynOS_Level_GetActName(s32 aLevel, s32 aAct, bool aDecaps, bool aAddStarNumber);
|
||||
const u8 *DynOS_Level_GetAreaName(s32 aLevel, s32 aArea, bool aDecaps);
|
||||
s16 *DynOS_Level_GetWarp(s32 aLevel, s32 aArea, u8 aWarpId);
|
||||
s16 *DynOS_Level_GetWarpEntry(s32 aLevel, s32 aArea);
|
||||
s16 *DynOS_Level_GetWarpDeath(s32 aLevel, s32 aArea);
|
||||
|
||||
//
|
||||
// Warps
|
||||
//
|
||||
|
||||
void *DynOS_Warp_Update(void *aCmd, bool aIsLevelInitDone);
|
||||
bool DynOS_Warp_ToLevel(s32 aLevel, s32 aArea, s32 aAct);
|
||||
bool DynOS_Warp_RestartLevel();
|
||||
bool DynOS_Warp_ExitLevel(s32 aDelay);
|
||||
bool DynOS_Warp_ToCastle(s32 aLevel);
|
||||
void DynOS_Warp_SetParam(s32 aLevel, s32 aIndex);
|
||||
const char *DynOS_Warp_GetParamName(s32 aLevel, s32 aIndex);
|
||||
|
||||
#endif
|
||||
#endif
|
38
data/dynos.h
Normal file
38
data/dynos.h
Normal file
|
@ -0,0 +1,38 @@
|
|||
#ifndef DYNOS_H
|
||||
#define DYNOS_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <math.h>
|
||||
#include <limits.h>
|
||||
#include <dirent.h>
|
||||
#include <SDL2/SDL.h>
|
||||
#ifdef __cplusplus
|
||||
#include <new>
|
||||
#include <utility>
|
||||
#include <string>
|
||||
extern "C" {
|
||||
#endif
|
||||
#include "config.h"
|
||||
#include "pc/fs/fs.h"
|
||||
#include "audio_defines.h"
|
||||
#undef STB_IMAGE_IMPLEMENTATION
|
||||
#include "stb/stb_image.h"
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#define DYNOS_VERSION "1.0"
|
||||
#define DYNOS_EXE_FOLDER sys_exe_path()
|
||||
#define DYNOS_USER_FOLDER sys_user_path()
|
||||
#define DYNOS_RES_FOLDER "dynos"
|
||||
#define DYNOS_PACKS_FOLDER DYNOS_RES_FOLDER "/packs"
|
||||
#define DYNOS_CONFIG_FILENAME "DynOS." DYNOS_VERSION ".config.txt"
|
||||
#define DYNOS_AT_STARTUP __attribute__((constructor))
|
||||
#define DYNOS_AT_EXIT __attribute__((destructor))
|
||||
|
||||
#endif
|
30
data/dynos_c.cpp
Normal file
30
data/dynos_c.cpp
Normal file
|
@ -0,0 +1,30 @@
|
|||
#include "dynos.cpp.h"
|
||||
extern "C" {
|
||||
|
||||
void *dynos_update_cmd(void *cmd) {
|
||||
return DynOS_UpdateCmd(cmd);
|
||||
}
|
||||
|
||||
void dynos_update_gfx() {
|
||||
return DynOS_UpdateGfx();
|
||||
}
|
||||
|
||||
void dynos_update_opt(void *pad) {
|
||||
return DynOS_UpdateOpt(pad);
|
||||
}
|
||||
|
||||
s32 dynos_gfx_import_texture(void **output, void *ptr, s32 tile, void *grapi, void **hashmap, void *pool, s32 *poolpos, s32 poolsize) {
|
||||
return DynOS_Gfx_ImportTexture(output, ptr, tile, grapi, hashmap, pool, (u32 *) poolpos, (u32) poolsize);
|
||||
}
|
||||
|
||||
void dynos_gfx_swap_animations(void *ptr) {
|
||||
return DynOS_Gfx_SwapAnimations(ptr);
|
||||
}
|
||||
|
||||
#ifdef COOP
|
||||
bool dynos_warp_to_level(s32 aLevel, s32 aArea, s32 aAct) {
|
||||
return DynOS_Warp_ToLevel(aLevel, aArea, aAct);
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
63
data/dynos_gfx_init.cpp
Normal file
63
data/dynos_gfx_init.cpp
Normal file
|
@ -0,0 +1,63 @@
|
|||
#include "dynos.cpp.h"
|
||||
|
||||
Array<ActorGfx> &DynOS_Gfx_GetActorList() {
|
||||
static Array<ActorGfx> sActorGfxList;
|
||||
return sActorGfxList;
|
||||
}
|
||||
|
||||
Array<PackData *> &DynOS_Gfx_GetPacks() {
|
||||
static Array<PackData *> sPacks;
|
||||
return sPacks;
|
||||
}
|
||||
|
||||
Array<String> DynOS_Gfx_Init() {
|
||||
|
||||
// Alloc and init the actors gfx list
|
||||
Array<ActorGfx> &pActorGfxList = DynOS_Gfx_GetActorList();
|
||||
pActorGfxList.Resize(DynOS_Geo_GetActorCount());
|
||||
for (s32 i = 0; i != DynOS_Geo_GetActorCount(); ++i) {
|
||||
pActorGfxList[i].mPackIndex = -1;
|
||||
pActorGfxList[i].mGfxData = NULL;
|
||||
pActorGfxList[i].mGraphNode = (GraphNode *) DynOS_Geo_GetGraphNode(DynOS_Geo_GetActorLayout(i), false);
|
||||
}
|
||||
|
||||
// Scan the DynOS packs folder
|
||||
Array<PackData *> &pDynosPacks = DynOS_Gfx_GetPacks();
|
||||
SysPath _DynosPacksFolder = fstring("%s/%s", DYNOS_EXE_FOLDER, DYNOS_PACKS_FOLDER);
|
||||
DIR *_DynosPacksDir = opendir(_DynosPacksFolder.c_str());
|
||||
if (_DynosPacksDir) {
|
||||
struct dirent *_DynosPacksEnt = NULL;
|
||||
while ((_DynosPacksEnt = readdir(_DynosPacksDir)) != NULL) {
|
||||
|
||||
// Skip . and ..
|
||||
if (SysPath(_DynosPacksEnt->d_name) == ".") continue;
|
||||
if (SysPath(_DynosPacksEnt->d_name) == "..") continue;
|
||||
|
||||
// If pack folder exists, add it to the pack list
|
||||
SysPath _PackFolder = fstring("%s/%s", _DynosPacksFolder.c_str(), _DynosPacksEnt->d_name);
|
||||
if (fs_sys_dir_exists(_PackFolder.c_str())) {
|
||||
PackData *_Pack = New<PackData>();
|
||||
|
||||
// Scan folder for subfolders to convert into .bin files
|
||||
_Pack->mPath = _PackFolder;
|
||||
DynOS_Gfx_GeneratePack(_PackFolder);
|
||||
|
||||
// Add pack to pack list
|
||||
pDynosPacks.Add(_Pack);
|
||||
}
|
||||
}
|
||||
closedir(_DynosPacksDir);
|
||||
}
|
||||
|
||||
// Return a list of pack names
|
||||
Array<String> _PackNames;
|
||||
for (const auto& _Pack : pDynosPacks) {
|
||||
u64 _DirSep1 = _Pack->mPath.find_last_of('\\');
|
||||
u64 _DirSep2 = _Pack->mPath.find_last_of('/');
|
||||
if (_DirSep1++ == SysPath::npos) _DirSep1 = 0;
|
||||
if (_DirSep2++ == SysPath::npos) _DirSep2 = 0;
|
||||
SysPath _DirName = _Pack->mPath.substr(MAX(_DirSep1, _DirSep2));
|
||||
_PackNames.Add(_DirName.c_str());
|
||||
}
|
||||
return _PackNames;
|
||||
}
|
313
data/dynos_gfx_load.cpp
Normal file
313
data/dynos_gfx_load.cpp
Normal file
|
@ -0,0 +1,313 @@
|
|||
#include "dynos.cpp.h"
|
||||
|
||||
//
|
||||
// Pointers
|
||||
//
|
||||
|
||||
static void *GetPointerFromData(GfxData *aGfxData, const String &aPtrName, u32 aPtrData) {
|
||||
|
||||
// Lights
|
||||
for (auto& _Node : aGfxData->mLights) {
|
||||
if (_Node->mName == aPtrName) {
|
||||
if (aPtrData == 1) {
|
||||
return (void *) &_Node->mData->l[0];
|
||||
}
|
||||
if (aPtrData == 2) {
|
||||
return (void *) &_Node->mData->a;
|
||||
}
|
||||
sys_fatal("Unknown Light type: %u", aPtrData);
|
||||
}
|
||||
}
|
||||
|
||||
// Textures
|
||||
for (auto& _Node : aGfxData->mTextures) {
|
||||
if (_Node->mName == aPtrName) {
|
||||
return (void *) _Node;
|
||||
}
|
||||
}
|
||||
|
||||
// Display lists
|
||||
for (auto &_Node : aGfxData->mDisplayLists) {
|
||||
if (_Node->mName == aPtrName) {
|
||||
return (void *) _Node->mData;
|
||||
}
|
||||
}
|
||||
|
||||
// Geo layouts
|
||||
for (auto &_Node : aGfxData->mGeoLayouts) {
|
||||
if (_Node->mName == aPtrName) {
|
||||
return (void *) _Node->mData;
|
||||
}
|
||||
}
|
||||
|
||||
// Vertices
|
||||
for (auto &_Node : aGfxData->mVertices) {
|
||||
if (_Node->mName == aPtrName) {
|
||||
return (void *) (_Node->mData + aPtrData);
|
||||
}
|
||||
}
|
||||
|
||||
// Error
|
||||
sys_fatal("Pointer not found: %s", aPtrName.begin());
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void *ReadPointer(FILE *aFile, GfxData *aGfxData, u32 aValue) {
|
||||
|
||||
// FUNC
|
||||
if (aValue == FUNCTION_CODE) {
|
||||
s32 _GeoFunctionIndex = ReadBytes<s32>(aFile);
|
||||
return DynOS_Geo_GetFunctionPointerFromIndex(_GeoFunctionIndex);
|
||||
}
|
||||
|
||||
// PNTR
|
||||
if (aValue == POINTER_CODE) {
|
||||
String _PtrName; _PtrName.Read(aFile);
|
||||
u32 _PtrData = ReadBytes<u32>(aFile);
|
||||
return GetPointerFromData(aGfxData, _PtrName, _PtrData);
|
||||
}
|
||||
|
||||
// Not a pointer
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//
|
||||
// Read binary
|
||||
//
|
||||
|
||||
static void LoadLightData(FILE *aFile, GfxData *aGfxData) {
|
||||
DataNode<Lights1> *_Node = New<DataNode<Lights1>>();
|
||||
|
||||
// Name
|
||||
_Node->mName.Read(aFile);
|
||||
|
||||
// Data
|
||||
_Node->mData = New<Lights1>();
|
||||
*_Node->mData = ReadBytes<Lights1>(aFile);
|
||||
|
||||
// Append
|
||||
aGfxData->mLights.Add(_Node);
|
||||
}
|
||||
|
||||
static void LoadTextureData(FILE *aFile, GfxData *aGfxData) {
|
||||
DataNode<TexData> *_Node = New<DataNode<TexData>>();
|
||||
|
||||
// Name
|
||||
_Node->mName.Read(aFile);
|
||||
|
||||
// Data
|
||||
_Node->mData = New<TexData>();
|
||||
_Node->mData->mUploaded = false;
|
||||
_Node->mData->mPngData.Read(aFile);
|
||||
if (!_Node->mData->mPngData.Empty()) {
|
||||
u8 *_RawData = stbi_load_from_memory(_Node->mData->mPngData.begin(), _Node->mData->mPngData.Count(), &_Node->mData->mRawWidth, &_Node->mData->mRawHeight, NULL, 4);
|
||||
_Node->mData->mRawFormat = G_IM_FMT_RGBA;
|
||||
_Node->mData->mRawSize = G_IM_SIZ_32b;
|
||||
_Node->mData->mRawData = Array<u8>(_RawData, _RawData + (_Node->mData->mRawWidth * _Node->mData->mRawHeight * 4));
|
||||
free(_RawData);
|
||||
} else { // Probably a palette
|
||||
_Node->mData->mRawData = Array<u8>();
|
||||
_Node->mData->mRawWidth = 0;
|
||||
_Node->mData->mRawHeight = 0;
|
||||
_Node->mData->mRawFormat = 0;
|
||||
_Node->mData->mRawSize = 0;
|
||||
}
|
||||
|
||||
// Append
|
||||
aGfxData->mTextures.Add(_Node);
|
||||
}
|
||||
|
||||
static void LoadVertexData(FILE *aFile, GfxData *aGfxData) {
|
||||
DataNode<Vtx> *_Node = New<DataNode<Vtx>>();
|
||||
|
||||
// Name
|
||||
_Node->mName.Read(aFile);
|
||||
|
||||
// Data
|
||||
_Node->mSize = ReadBytes<u32>(aFile);
|
||||
_Node->mData = New<Vtx>(_Node->mSize);
|
||||
for (u32 i = 0; i != _Node->mSize; ++i) {
|
||||
_Node->mData[i].n.ob[0] = ReadBytes<s16>(aFile);
|
||||
_Node->mData[i].n.ob[1] = ReadBytes<s16>(aFile);
|
||||
_Node->mData[i].n.ob[2] = ReadBytes<s16>(aFile);
|
||||
_Node->mData[i].n.flag = ReadBytes<s16>(aFile);
|
||||
_Node->mData[i].n.tc[0] = ReadBytes<s16>(aFile);
|
||||
_Node->mData[i].n.tc[1] = ReadBytes<s16>(aFile);
|
||||
_Node->mData[i].n.n[0] = ReadBytes<s8> (aFile);
|
||||
_Node->mData[i].n.n[1] = ReadBytes<s8> (aFile);
|
||||
_Node->mData[i].n.n[2] = ReadBytes<s8> (aFile);
|
||||
_Node->mData[i].n.a = ReadBytes<u8>(aFile);
|
||||
}
|
||||
|
||||
// Append
|
||||
aGfxData->mVertices.Add(_Node);
|
||||
}
|
||||
|
||||
static void LoadDisplayListData(FILE *aFile, GfxData *aGfxData) {
|
||||
DataNode<Gfx> *_Node = New<DataNode<Gfx>>();
|
||||
|
||||
// Name
|
||||
_Node->mName.Read(aFile);
|
||||
|
||||
// Data
|
||||
_Node->mSize = ReadBytes<u32>(aFile);
|
||||
_Node->mData = New<Gfx>(_Node->mSize);
|
||||
for (u32 i = 0; i != _Node->mSize; ++i) {
|
||||
u32 _WordsW0 = ReadBytes<u32>(aFile);
|
||||
u32 _WordsW1 = ReadBytes<u32>(aFile);
|
||||
void *_Ptr = ReadPointer(aFile, aGfxData, _WordsW1);
|
||||
if (_Ptr) {
|
||||
_Node->mData[i].words.w0 = (uintptr_t) _WordsW0;
|
||||
_Node->mData[i].words.w1 = (uintptr_t) _Ptr;
|
||||
} else {
|
||||
_Node->mData[i].words.w0 = (uintptr_t) _WordsW0;
|
||||
_Node->mData[i].words.w1 = (uintptr_t) _WordsW1;
|
||||
}
|
||||
}
|
||||
|
||||
// Append
|
||||
aGfxData->mDisplayLists.Add(_Node);
|
||||
}
|
||||
|
||||
static void LoadGeoLayoutData(FILE *aFile, GfxData *aGfxData) {
|
||||
DataNode<GeoLayout> *_Node = New<DataNode<GeoLayout>>();
|
||||
|
||||
// Name
|
||||
_Node->mName.Read(aFile);
|
||||
|
||||
// Data
|
||||
_Node->mSize = ReadBytes<u32>(aFile);
|
||||
_Node->mData = New<GeoLayout>(_Node->mSize);
|
||||
for (u32 i = 0; i != _Node->mSize; ++i) {
|
||||
u32 _Value = ReadBytes<u32>(aFile);
|
||||
void *_Ptr = ReadPointer(aFile, aGfxData, _Value);
|
||||
if (_Ptr) {
|
||||
_Node->mData[i] = (uintptr_t) _Ptr;
|
||||
} else {
|
||||
_Node->mData[i] = (uintptr_t) _Value;
|
||||
}
|
||||
}
|
||||
|
||||
// Append
|
||||
aGfxData->mGeoLayouts.Add(_Node);
|
||||
}
|
||||
|
||||
// For retro-compatibility
|
||||
static void LoadGfxDynCmd(FILE *aFile, GfxData *aGfxData) {
|
||||
Gfx *_Data = NULL;
|
||||
String _DisplayListName; _DisplayListName.Read(aFile);
|
||||
for (auto& _DisplayList : aGfxData->mDisplayLists) {
|
||||
if (_DisplayList->mName == _DisplayListName) {
|
||||
_Data = _DisplayList->mData;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!_Data) {
|
||||
sys_fatal("Display list not found: %s", _DisplayListName.begin());
|
||||
}
|
||||
ReadBytes<u32>(aFile);
|
||||
ReadBytes<u8>(aFile);
|
||||
}
|
||||
|
||||
static void LoadAnimationData(FILE *aFile, GfxData *aGfxData) {
|
||||
DataNode<AnimData> *_Node = New<DataNode<AnimData>>();
|
||||
|
||||
// Name
|
||||
_Node->mName.Read(aFile);
|
||||
|
||||
// Data
|
||||
_Node->mData = New<AnimData>();
|
||||
_Node->mData->mFlags = ReadBytes<s16>(aFile);
|
||||
_Node->mData->mUnk02 = ReadBytes<s16>(aFile);
|
||||
_Node->mData->mUnk04 = ReadBytes<s16>(aFile);
|
||||
_Node->mData->mUnk06 = ReadBytes<s16>(aFile);
|
||||
_Node->mData->mUnk08 = ReadBytes<s16>(aFile);
|
||||
_Node->mData->mUnk0A.second = ReadBytes<s16>(aFile);
|
||||
_Node->mData->mLength = ReadBytes<u32>(aFile);
|
||||
_Node->mData->mValues.second.Read(aFile);
|
||||
_Node->mData->mIndex.second.Read(aFile);
|
||||
|
||||
// Append
|
||||
aGfxData->mAnimations.Add(_Node);
|
||||
}
|
||||
|
||||
static void LoadAnimationTable(FILE *aFile, GfxData *aGfxData) {
|
||||
void *_AnimationPtr = NULL;
|
||||
|
||||
// Data
|
||||
String _AnimationName; _AnimationName.Read(aFile);
|
||||
if (_AnimationName != "NULL") {
|
||||
for (auto &_AnimData : aGfxData->mAnimations) {
|
||||
if (_AnimData->mName == _AnimationName) {
|
||||
_AnimationPtr = (void *) _AnimData->mData;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!_AnimationPtr) {
|
||||
sys_fatal("Animation not found: %s", _AnimationName.begin());
|
||||
}
|
||||
}
|
||||
|
||||
// Append
|
||||
aGfxData->mAnimationTable.Add({ "", _AnimationPtr });
|
||||
}
|
||||
|
||||
//
|
||||
// Load from binary
|
||||
//
|
||||
|
||||
GfxData *DynOS_Gfx_LoadFromBinary(const SysPath &aPackFolder, const char *aActorName) {
|
||||
struct DynosGfxDataCache { SysPath mPackFolder; Array<Pair<const char *, GfxData *>> mGfxData; };
|
||||
static Array<DynosGfxDataCache *> sDynosGfxDataCache;
|
||||
|
||||
// Look for pack in cache
|
||||
DynosGfxDataCache *_Pack = NULL;
|
||||
for (s32 i = 0; i != sDynosGfxDataCache.Count(); ++i) {
|
||||
if (sDynosGfxDataCache[i]->mPackFolder == aPackFolder) {
|
||||
_Pack = sDynosGfxDataCache[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Look for actor in pack
|
||||
if (_Pack) {
|
||||
for (s32 i = 0; i != _Pack->mGfxData.Count(); ++i) {
|
||||
if (_Pack->mGfxData[i].first == aActorName) { // Perfectly valid, aActorName comes from static RO data, so its address never changes during execution
|
||||
return _Pack->mGfxData[i].second;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Load data from binary file
|
||||
GfxData *_GfxData = NULL;
|
||||
SysPath _Filename = fstring("%s/%s.bin", aPackFolder.begin(), aActorName);
|
||||
FILE *_File = fopen(_Filename.c_str(), "rb");
|
||||
if (_File) {
|
||||
_GfxData = New<GfxData>();
|
||||
for (bool _Done = false; !_Done;) {
|
||||
switch (ReadBytes<u8>(_File)) {
|
||||
case DATA_TYPE_LIGHT: LoadLightData (_File, _GfxData); break;
|
||||
case DATA_TYPE_TEXTURE: LoadTextureData (_File, _GfxData); break;
|
||||
case DATA_TYPE_VERTEX: LoadVertexData (_File, _GfxData); break;
|
||||
case DATA_TYPE_DISPLAY_LIST: LoadDisplayListData(_File, _GfxData); break;
|
||||
case DATA_TYPE_GEO_LAYOUT: LoadGeoLayoutData (_File, _GfxData); break;
|
||||
case DATA_TYPE_ANIMATION: LoadAnimationData (_File, _GfxData); break;
|
||||
case DATA_TYPE_ANIMATION_TABLE: LoadAnimationTable (_File, _GfxData); break;
|
||||
case DATA_TYPE_GFXDYNCMD: LoadGfxDynCmd (_File, _GfxData); break;
|
||||
default: _Done = true; break;
|
||||
}
|
||||
}
|
||||
fclose(_File);
|
||||
}
|
||||
|
||||
// Add data to cache, even if not loaded
|
||||
if (_Pack) {
|
||||
_Pack->mGfxData.Add({ aActorName, _GfxData });
|
||||
} else {
|
||||
_Pack = New<DynosGfxDataCache>();
|
||||
_Pack->mPackFolder = aPackFolder;
|
||||
_Pack->mGfxData.Add({ aActorName, _GfxData });
|
||||
sDynosGfxDataCache.Add(_Pack);
|
||||
}
|
||||
return _GfxData;
|
||||
}
|
1887
data/dynos_gfx_read.cpp
Normal file
1887
data/dynos_gfx_read.cpp
Normal file
File diff suppressed because it is too large
Load diff
285
data/dynos_gfx_texture.cpp
Normal file
285
data/dynos_gfx_texture.cpp
Normal file
|
@ -0,0 +1,285 @@
|
|||
#include "dynos.cpp.h"
|
||||
extern "C" {
|
||||
#include "pc/gfx/gfx_rendering_api.h"
|
||||
}
|
||||
|
||||
//
|
||||
// Conversion
|
||||
//
|
||||
|
||||
#define SCALE_5_8(VAL_) (((VAL_) * 0xFF) / 0x1F)
|
||||
#define SCALE_8_5(VAL_) ((((VAL_) + 4) * 0x1F) / 0xFF)
|
||||
#define SCALE_4_8(VAL_) ((VAL_) * 0x11)
|
||||
#define SCALE_8_4(VAL_) ((VAL_) / 0x11)
|
||||
#define SCALE_3_8(VAL_) ((VAL_) * 0x24)
|
||||
#define SCALE_8_3(VAL_) ((VAL_) / 0x24)
|
||||
|
||||
static u8 *RGBA16_RGBA32(const u8 *aData, u64 aLength) {
|
||||
u8 *_Buffer = New<u8>(aLength * 2);
|
||||
u8 *pBuffer = _Buffer;
|
||||
for (u64 i = 0; i != aLength; i += 2) {
|
||||
u16 _Col = (aData[i + 0] << 8) | aData[i + 1];
|
||||
u8 _Red = (_Col >> 11) & 0x1F;
|
||||
u8 _Grn = (_Col >> 6) & 0x1F;
|
||||
u8 _Blu = (_Col >> 1) & 0x1F;
|
||||
u8 _Alp = (_Col >> 0) & 0x01;
|
||||
*(pBuffer++) = (SCALE_5_8(_Red));
|
||||
*(pBuffer++) = (SCALE_5_8(_Grn));
|
||||
*(pBuffer++) = (SCALE_5_8(_Blu));
|
||||
*(pBuffer++) = (0xFF * (_Alp));
|
||||
}
|
||||
return _Buffer;
|
||||
}
|
||||
|
||||
static u8 *RGBA32_RGBA32(const u8 *aData, u64 aLength) {
|
||||
u8 *_Buffer = New<u8>(aLength * 1);
|
||||
memcpy(_Buffer, aData, aLength);
|
||||
return _Buffer;
|
||||
}
|
||||
|
||||
static u8 *IA4_RGBA32(const u8 *aData, u64 aLength) {
|
||||
u8 *_Buffer = New<u8>(aLength * 8);
|
||||
u8 *pBuffer = _Buffer;
|
||||
for (u64 i = 0; i != aLength; ++i) {
|
||||
u8 _Half0 = (aData[i] >> 4) & 0xF;
|
||||
*(pBuffer++) = (SCALE_3_8(_Half0 >> 1));
|
||||
*(pBuffer++) = (SCALE_3_8(_Half0 >> 1));
|
||||
*(pBuffer++) = (SCALE_3_8(_Half0 >> 1));
|
||||
*(pBuffer++) = (0xFF * (_Half0 & 1));
|
||||
|
||||
u8 _Half1 = (aData[i] >> 0) & 0xF;
|
||||
*(pBuffer++) = (SCALE_3_8(_Half1 >> 1));
|
||||
*(pBuffer++) = (SCALE_3_8(_Half1 >> 1));
|
||||
*(pBuffer++) = (SCALE_3_8(_Half1 >> 1));
|
||||
*(pBuffer++) = (0xFF * (_Half1 & 1));
|
||||
}
|
||||
return _Buffer;
|
||||
}
|
||||
|
||||
static u8 *IA8_RGBA32(const u8 *aData, u64 aLength) {
|
||||
u8 *_Buffer = New<u8>(aLength * 4);
|
||||
u8 *pBuffer = _Buffer;
|
||||
for (u64 i = 0; i != aLength; ++i) {
|
||||
u8 _Col = (aData[i] >> 4) & 0xF;
|
||||
u8 _Alp = (aData[i] >> 0) & 0xF;
|
||||
*(pBuffer++) = (SCALE_4_8(_Col));
|
||||
*(pBuffer++) = (SCALE_4_8(_Col));
|
||||
*(pBuffer++) = (SCALE_4_8(_Col));
|
||||
*(pBuffer++) = (SCALE_4_8(_Alp));
|
||||
}
|
||||
return _Buffer;
|
||||
}
|
||||
|
||||
static u8 *IA16_RGBA32(const u8 *aData, u64 aLength) {
|
||||
u8 *_Buffer = New<u8>(aLength * 2);
|
||||
u8 *pBuffer = _Buffer;
|
||||
for (u64 i = 0; i != aLength; i += 2) {
|
||||
u8 _Col = aData[i + 0];
|
||||
u8 _Alp = aData[i + 1];
|
||||
*(pBuffer++) = (_Col);
|
||||
*(pBuffer++) = (_Col);
|
||||
*(pBuffer++) = (_Col);
|
||||
*(pBuffer++) = (_Alp);
|
||||
}
|
||||
return _Buffer;
|
||||
}
|
||||
|
||||
static u8 *CI4_RGBA32(const u8 *aData, u64 aLength, const u8 *aPalette) {
|
||||
u8 *_Buffer = New<u8>(aLength * 8);
|
||||
u8 *pBuffer = _Buffer;
|
||||
for (u64 i = 0; i != aLength; ++i) {
|
||||
u8 _Idx0 = (aData[i] >> 4) & 0xF;
|
||||
u16 _Col0 = (aPalette[_Idx0 * 2 + 0] << 8) | aPalette[_Idx0 * 2 + 1];
|
||||
u8 _Red0 = (_Col0 >> 11) & 0x1F;
|
||||
u8 _Grn0 = (_Col0 >> 6) & 0x1F;
|
||||
u8 _Blu0 = (_Col0 >> 1) & 0x1F;
|
||||
u8 _Alp0 = (_Col0 >> 0) & 0x01;
|
||||
*(pBuffer++) = (SCALE_5_8(_Red0));
|
||||
*(pBuffer++) = (SCALE_5_8(_Grn0));
|
||||
*(pBuffer++) = (SCALE_5_8(_Blu0));
|
||||
*(pBuffer++) = (0xFF * (_Alp0));
|
||||
|
||||
u8 _Idx1 = (aData[i] >> 0) & 0xF;
|
||||
u16 _Col1 = (aPalette[_Idx1 * 2 + 0] << 8) | aPalette[_Idx1 * 2 + 1];
|
||||
u8 _Red1 = (_Col1 >> 11) & 0x1F;
|
||||
u8 _Grn1 = (_Col1 >> 6) & 0x1F;
|
||||
u8 _Blu1 = (_Col1 >> 1) & 0x1F;
|
||||
u8 _Alp1 = (_Col1 >> 0) & 0x01;
|
||||
*(pBuffer++) = (SCALE_5_8(_Red1));
|
||||
*(pBuffer++) = (SCALE_5_8(_Grn1));
|
||||
*(pBuffer++) = (SCALE_5_8(_Blu1));
|
||||
*(pBuffer++) = (0xFF * (_Alp1));
|
||||
}
|
||||
return _Buffer;
|
||||
}
|
||||
|
||||
static u8 *CI8_RGBA32(const u8 *aData, u64 aLength, const u8 *aPalette) {
|
||||
u8 *_Buffer = New<u8>(aLength * 4);
|
||||
u8 *pBuffer = _Buffer;
|
||||
for (u64 i = 0; i != aLength; ++i) {
|
||||
u8 _Idx = aData[i];
|
||||
u16 _Col = (aPalette[_Idx * 2 + 0] << 8) | aPalette[_Idx * 2 + 1];
|
||||
u8 _Red = (_Col >> 11) & 0x1F;
|
||||
u8 _Grn = (_Col >> 6) & 0x1F;
|
||||
u8 _Blu = (_Col >> 1) & 0x1F;
|
||||
u8 _Alp = (_Col >> 0) & 0x01;
|
||||
*(pBuffer++) = (SCALE_5_8(_Red));
|
||||
*(pBuffer++) = (SCALE_5_8(_Grn));
|
||||
*(pBuffer++) = (SCALE_5_8(_Blu));
|
||||
*(pBuffer++) = (0xFF * (_Alp));
|
||||
}
|
||||
return _Buffer;
|
||||
}
|
||||
|
||||
static u8 *I4_RGBA32(const u8 *aData, u64 aLength) {
|
||||
u8 *_Buffer = New<u8>(aLength * 8);
|
||||
u8 *pBuffer = _Buffer;
|
||||
for (u64 i = 0; i != aLength; ++i) {
|
||||
u8 _Half0 = (aData[i] >> 4) & 0xF;
|
||||
*(pBuffer++) = (SCALE_4_8(_Half0));
|
||||
*(pBuffer++) = (SCALE_4_8(_Half0));
|
||||
*(pBuffer++) = (SCALE_4_8(_Half0));
|
||||
*(pBuffer++) = (255);
|
||||
|
||||
u8 _Half1 = (aData[i] >> 0) & 0xF;
|
||||
*(pBuffer++) = (SCALE_4_8(_Half1));
|
||||
*(pBuffer++) = (SCALE_4_8(_Half1));
|
||||
*(pBuffer++) = (SCALE_4_8(_Half1));
|
||||
*(pBuffer++) = (255);
|
||||
}
|
||||
return _Buffer;
|
||||
}
|
||||
|
||||
static u8 *I8_RGBA32(const u8 *aData, u64 aLength) {
|
||||
u8 *_Buffer = New<u8>(aLength * 4);
|
||||
u8 *pBuffer = _Buffer;
|
||||
for (u64 i = 0; i != aLength; ++i) {
|
||||
*(pBuffer++) = (aData[i]);
|
||||
*(pBuffer++) = (aData[i]);
|
||||
*(pBuffer++) = (aData[i]);
|
||||
*(pBuffer++) = (255);
|
||||
}
|
||||
return _Buffer;
|
||||
}
|
||||
|
||||
u8 *DynOS_Gfx_TextureConvertToRGBA32(const u8 *aData, u64 aLength, s32 aFormat, s32 aSize, const u8 *aPalette) {
|
||||
switch ((aFormat << 8) | aSize ) {
|
||||
case ((G_IM_FMT_RGBA << 8) | G_IM_SIZ_16b): return RGBA16_RGBA32(aData, aLength);
|
||||
case ((G_IM_FMT_RGBA << 8) | G_IM_SIZ_32b): return RGBA32_RGBA32(aData, aLength);
|
||||
case ((G_IM_FMT_IA << 8) | G_IM_SIZ_4b ): return IA4_RGBA32 (aData, aLength);
|
||||
case ((G_IM_FMT_IA << 8) | G_IM_SIZ_8b ): return IA8_RGBA32 (aData, aLength);
|
||||
case ((G_IM_FMT_IA << 8) | G_IM_SIZ_16b): return IA16_RGBA32 (aData, aLength);
|
||||
case ((G_IM_FMT_CI << 8) | G_IM_SIZ_4b ): return CI4_RGBA32 (aData, aLength, aPalette);
|
||||
case ((G_IM_FMT_CI << 8) | G_IM_SIZ_8b ): return CI8_RGBA32 (aData, aLength, aPalette);
|
||||
case ((G_IM_FMT_I << 8) | G_IM_SIZ_4b ): return I4_RGBA32 (aData, aLength);
|
||||
case ((G_IM_FMT_I << 8) | G_IM_SIZ_8b ): return I8_RGBA32 (aData, aLength);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//
|
||||
// Upload
|
||||
//
|
||||
|
||||
typedef struct GfxRenderingAPI GRAPI;
|
||||
static void DynOS_Gfx_UploadTexture(DataNode<TexData> *aNode, GRAPI *aGfxRApi, s32 aTile, s32 aTexId) {
|
||||
aGfxRApi->select_texture(aTile, aTexId);
|
||||
aGfxRApi->upload_texture(aNode->mData->mRawData.begin(), aNode->mData->mRawWidth, aNode->mData->mRawHeight);
|
||||
aNode->mData->mUploaded = true;
|
||||
}
|
||||
|
||||
//
|
||||
// Cache
|
||||
//
|
||||
|
||||
struct THN {
|
||||
struct THN *mNext;
|
||||
const void *mAddr; // Contains the pointer to the DataNode<TexData> struct, NOT the actual texture data
|
||||
u8 mFmt, mSiz;
|
||||
s32 mTexId;
|
||||
u8 mCms, mCmt;
|
||||
bool mLInf;
|
||||
};
|
||||
|
||||
static bool DynOS_Gfx_CacheTexture(THN **aOutput, DataNode<TexData> *aNode, s32 aTile, GRAPI *aGfxRApi, THN **aHashMap, THN *aPool, u32 *aPoolPos, u32 aPoolSize) {
|
||||
|
||||
// Find texture in cache
|
||||
uintptr_t _Hash = ((uintptr_t) aNode) & ((aPoolSize * 2) - 1);
|
||||
THN **_Node = &(aHashMap[_Hash]);
|
||||
while ((*_Node) != NULL && ((*_Node) - aPool) < (*aPoolPos)) {
|
||||
if ((*_Node)->mAddr == (const void *) aNode) {
|
||||
aGfxRApi->select_texture(aTile, (*_Node)->mTexId);
|
||||
if (!aNode->mData->mUploaded) {
|
||||
DynOS_Gfx_UploadTexture(aNode, aGfxRApi, aTile, (*_Node)->mTexId);
|
||||
}
|
||||
(*aOutput) = (*_Node);
|
||||
return true;
|
||||
}
|
||||
_Node = &(*_Node)->mNext;
|
||||
}
|
||||
|
||||
// If cache is full, clear cache
|
||||
if ((*aPoolPos) == aPoolSize) {
|
||||
(*aPoolPos) = 0;
|
||||
_Node = &aHashMap[_Hash];
|
||||
}
|
||||
|
||||
// Add new texture to cache
|
||||
(*_Node) = &aPool[(*aPoolPos)++];
|
||||
if (!(*_Node)->mAddr) {
|
||||
(*_Node)->mTexId = aGfxRApi->new_texture();
|
||||
}
|
||||
aGfxRApi->select_texture(aTile, (*_Node)->mTexId);
|
||||
aGfxRApi->set_sampler_parameters(aTile, false, 0, 0);
|
||||
(*_Node)->mCms = 0;
|
||||
(*_Node)->mCmt = 0;
|
||||
(*_Node)->mLInf = false;
|
||||
(*_Node)->mNext = NULL;
|
||||
(*_Node)->mAddr = aNode;
|
||||
(*_Node)->mFmt = G_IM_FMT_RGBA;
|
||||
(*_Node)->mSiz = G_IM_SIZ_32b;
|
||||
(*aOutput) = (*_Node);
|
||||
return false;
|
||||
}
|
||||
|
||||
//
|
||||
// Import
|
||||
//
|
||||
|
||||
static DataNode<TexData> *DynOS_Gfx_RetrieveNode(void *aPtr) {
|
||||
Array<ActorGfx> &pActorGfxList = DynOS_Gfx_GetActorList();
|
||||
for (auto& _ActorGfx : pActorGfxList) {
|
||||
if (_ActorGfx.mGfxData) {
|
||||
for (auto &_Node : _ActorGfx.mGfxData->mTextures) {
|
||||
if ((void*) _Node == aPtr) {
|
||||
return _Node;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static bool DynOS_Gfx_ImportTexture_Typed(THN **aOutput, void *aPtr, s32 aTile, GRAPI *aGfxRApi, THN **aHashMap, THN *aPool, u32 *aPoolPos, u32 aPoolSize) {
|
||||
DataNode<TexData> *_Node = DynOS_Gfx_RetrieveNode(aPtr);
|
||||
if (_Node) {
|
||||
if (!DynOS_Gfx_CacheTexture(aOutput, _Node, aTile, aGfxRApi, aHashMap, aPool, aPoolPos, aPoolSize)) {
|
||||
DynOS_Gfx_UploadTexture(_Node, aGfxRApi, aTile, (*aOutput)->mTexId);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DynOS_Gfx_ImportTexture(void **aOutput, void *aPtr, s32 aTile, void *aGfxRApi, void **aHashMap, void *aPool, u32 *aPoolPos, u32 aPoolSize) {
|
||||
return DynOS_Gfx_ImportTexture_Typed(
|
||||
(THN **) aOutput,
|
||||
(void *) aPtr,
|
||||
(s32) aTile,
|
||||
(GRAPI *) aGfxRApi,
|
||||
(THN **) aHashMap,
|
||||
(THN *) aPool,
|
||||
(u32 *) aPoolPos,
|
||||
(u32) aPoolSize
|
||||
);
|
||||
}
|
161
data/dynos_gfx_update.cpp
Normal file
161
data/dynos_gfx_update.cpp
Normal file
|
@ -0,0 +1,161 @@
|
|||
#include "dynos.cpp.h"
|
||||
extern "C" {
|
||||
#include "object_fields.h"
|
||||
#include "game/level_update.h"
|
||||
#include "game/object_list_processor.h"
|
||||
}
|
||||
|
||||
//
|
||||
// Update animations
|
||||
//
|
||||
|
||||
// Retrieve the current Mario's animation index
|
||||
static s32 RetrieveCurrentMarioAnimationIndex() {
|
||||
struct MarioAnimDmaRelatedThing *_AnimDmaTable = gMarioState->animation->animDmaTable;
|
||||
for (s32 i = 0; i != (s32) _AnimDmaTable->count; ++i) {
|
||||
void *_AnimAddr = _AnimDmaTable->srcAddr + _AnimDmaTable->anim[i].offset;
|
||||
if (_AnimAddr == gMarioState->animation->currentAnimAddr) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Retrieve the current animation index
|
||||
// As we don't know the length of the table, let's hope that we'll always find the animation...
|
||||
static s32 RetrieveCurrentAnimationIndex(struct Object *aObject) {
|
||||
if (!aObject->oAnimations || !aObject->header.gfx.animInfo.curAnim) {
|
||||
return -1;
|
||||
}
|
||||
for (s32 i = 0; aObject->oAnimations[i] != NULL; ++i) {
|
||||
if (aObject->oAnimations[i] == aObject->header.gfx.animInfo.curAnim) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Must be called twice, before and after geo_set_animation_globals
|
||||
void DynOS_Gfx_SwapAnimations(void *aPtr) {
|
||||
static Animation *pDefaultAnimation = NULL;
|
||||
static Animation sGfxDataAnimation;
|
||||
|
||||
// Does the object has a model?
|
||||
struct Object *_Object = (struct Object *) aPtr;
|
||||
if (!_Object->header.gfx.sharedChild) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Swap the current animation with the one from the Gfx data
|
||||
if (!pDefaultAnimation) {
|
||||
pDefaultAnimation = _Object->header.gfx.animInfo.curAnim;
|
||||
|
||||
// Actor index
|
||||
s32 _ActorIndex = DynOS_Geo_GetActorIndex(_Object->header.gfx.sharedChild->georef);
|
||||
if (_ActorIndex == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Gfx data
|
||||
GfxData *_GfxData = DynOS_Gfx_GetActorList()[_ActorIndex].mGfxData;
|
||||
if (!_GfxData) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Animation table
|
||||
if (_GfxData->mAnimationTable.Empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Animation index
|
||||
s32 _AnimIndex = (_Object == gMarioObject ? RetrieveCurrentMarioAnimationIndex() : RetrieveCurrentAnimationIndex(_Object));
|
||||
if (_AnimIndex == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Animation data
|
||||
const AnimData *_AnimData = (const AnimData *) _GfxData->mAnimationTable[_AnimIndex].second;
|
||||
if (_AnimData) {
|
||||
sGfxDataAnimation.flags = _AnimData->mFlags;
|
||||
sGfxDataAnimation.animYTransDivisor = _AnimData->mUnk02;
|
||||
sGfxDataAnimation.startFrame = _AnimData->mUnk04;
|
||||
sGfxDataAnimation.loopStart = _AnimData->mUnk06;
|
||||
sGfxDataAnimation.loopEnd = _AnimData->mUnk08;
|
||||
sGfxDataAnimation.unusedBoneCount = _AnimData->mUnk0A.second;
|
||||
sGfxDataAnimation.values = _AnimData->mValues.second.begin();
|
||||
sGfxDataAnimation.index = _AnimData->mIndex.second.begin();
|
||||
sGfxDataAnimation.length = _AnimData->mLength;
|
||||
_Object->header.gfx.animInfo.curAnim = &sGfxDataAnimation;
|
||||
}
|
||||
|
||||
// Restore the default animation
|
||||
} else {
|
||||
_Object->header.gfx.animInfo.curAnim = pDefaultAnimation;
|
||||
pDefaultAnimation = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Update models
|
||||
//
|
||||
|
||||
void DynOS_Gfx_Update() {
|
||||
if (gObjectLists) {
|
||||
|
||||
// Check packs
|
||||
Array<bool> _Enabled;
|
||||
const Array<PackData *> &pDynosPacks = DynOS_Gfx_GetPacks();
|
||||
for (s32 i = 0; i != pDynosPacks.Count(); ++i) {
|
||||
#ifdef COOP
|
||||
_Enabled.Add(true);
|
||||
#else
|
||||
_Enabled.Add(DynOS_Opt_GetValue(String("dynos_pack_%d", i)));
|
||||
#endif
|
||||
}
|
||||
|
||||
// Loop through all object lists
|
||||
for (s32 list : { OBJ_LIST_PLAYER, OBJ_LIST_DESTRUCTIVE, OBJ_LIST_GENACTOR, OBJ_LIST_PUSHABLE, OBJ_LIST_LEVEL, OBJ_LIST_DEFAULT, OBJ_LIST_SURFACE, OBJ_LIST_POLELIKE, OBJ_LIST_UNIMPORTANT }) {
|
||||
struct Object *_Head = (struct Object *) &gObjectLists[list];
|
||||
for (struct Object *_Object = (struct Object *) _Head->header.next; _Object != _Head; _Object = (struct Object *) _Object->header.next) {
|
||||
if (_Object->header.gfx.sharedChild) {
|
||||
|
||||
// Actor index
|
||||
s32 _ActorIndex = DynOS_Geo_GetActorIndex(_Object->header.gfx.sharedChild->georef);
|
||||
if (_ActorIndex != -1) {
|
||||
|
||||
// Replace the object's model and animations
|
||||
ActorGfx *_ActorGfx = &DynOS_Gfx_GetActorList()[_ActorIndex];
|
||||
for (s32 i = 0; i != pDynosPacks.Count(); ++i) {
|
||||
|
||||
// If enabled and no pack is selected
|
||||
// load the pack's model and replace the default actor's model
|
||||
if (_Enabled[i] && _ActorGfx->mPackIndex == -1) {
|
||||
|
||||
// Load Gfx data from binary
|
||||
GfxData *_GfxData = DynOS_Gfx_LoadFromBinary(pDynosPacks[i]->mPath, DynOS_Geo_GetActorName(_ActorIndex));
|
||||
if (_GfxData) {
|
||||
_ActorGfx->mPackIndex = i;
|
||||
_ActorGfx->mGfxData = _GfxData;
|
||||
_ActorGfx->mGraphNode = (GraphNode *) DynOS_Geo_GetGraphNode((*(_GfxData->mGeoLayouts.end() - 1))->mData, true);
|
||||
_ActorGfx->mGraphNode->georef = DynOS_Geo_GetActorLayout(_ActorIndex);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If disabled and this pack is the one selected
|
||||
// replace the actor's model by the default one
|
||||
else if (!_Enabled[i] && _ActorGfx->mPackIndex == i) {
|
||||
_ActorGfx->mPackIndex = -1;
|
||||
_ActorGfx->mGfxData = NULL;
|
||||
_ActorGfx->mGraphNode = (GraphNode *) DynOS_Geo_GetGraphNode(DynOS_Geo_GetActorLayout(_ActorIndex), true);
|
||||
}
|
||||
}
|
||||
|
||||
// Update object
|
||||
_Object->header.gfx.sharedChild = _ActorGfx->mGraphNode;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
318
data/dynos_gfx_write.cpp
Normal file
318
data/dynos_gfx_write.cpp
Normal file
|
@ -0,0 +1,318 @@
|
|||
#include "dynos.cpp.h"
|
||||
|
||||
//
|
||||
// Pointers
|
||||
//
|
||||
|
||||
typedef Pair<String, u32> PointerData;
|
||||
static PointerData GetDataFromPointer(const void* aPtr, GfxData* aGfxData) {
|
||||
|
||||
// Lights
|
||||
for (auto& _Node : aGfxData->mLights) {
|
||||
if (&_Node->mData->l[0] == aPtr) { // Light *, not Lights1 *
|
||||
return { _Node->mName, 1 };
|
||||
}
|
||||
if (&_Node->mData->a == aPtr) { // Ambient *, not Lights1 *
|
||||
return { _Node->mName, 2 };
|
||||
}
|
||||
}
|
||||
|
||||
// Textures
|
||||
for (auto& _Node : aGfxData->mTextures) {
|
||||
if (_Node == aPtr) {
|
||||
return { _Node->mName, 0 };
|
||||
}
|
||||
}
|
||||
|
||||
// Display lists
|
||||
for (auto& _Node : aGfxData->mDisplayLists) {
|
||||
if (_Node == aPtr) {
|
||||
return { _Node->mName, 0 };
|
||||
}
|
||||
}
|
||||
|
||||
// Geo layouts
|
||||
for (auto& _Node : aGfxData->mGeoLayouts) {
|
||||
if (_Node->mData == aPtr) {
|
||||
return { _Node->mName, 0 };
|
||||
}
|
||||
}
|
||||
|
||||
// Vertices
|
||||
String _VtxArrayName = "";
|
||||
uintptr_t _VtxArrayStart = 0;
|
||||
for (auto& _Node : aGfxData->mVertices) {
|
||||
if (_Node->mData == aPtr) {
|
||||
return { _Node->mName, 0 };
|
||||
}
|
||||
if ((uintptr_t)_Node->mData <= (uintptr_t)aPtr &&
|
||||
(uintptr_t)_Node->mData >= _VtxArrayStart) {
|
||||
_VtxArrayName = _Node->mName;
|
||||
_VtxArrayStart = (uintptr_t)_Node->mData;
|
||||
}
|
||||
}
|
||||
return { _VtxArrayName, (u32)((const Vtx*)aPtr - (const Vtx*)_VtxArrayStart) };
|
||||
}
|
||||
|
||||
static void WritePointer(FILE* aFile, const void* aPtr, GfxData* aGfxData) {
|
||||
|
||||
// NULL
|
||||
if (!aPtr) {
|
||||
WriteBytes<u32>(aFile, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
// Geo function
|
||||
s32 _GeoFunctionIndex = DynOS_Geo_GetFunctionIndex(aPtr);
|
||||
if (_GeoFunctionIndex != -1) {
|
||||
WriteBytes<u32>(aFile, FUNCTION_CODE);
|
||||
WriteBytes<s32>(aFile, _GeoFunctionIndex);
|
||||
return;
|
||||
}
|
||||
|
||||
// Pointer
|
||||
PointerData _PtrData = GetDataFromPointer(aPtr, aGfxData);
|
||||
WriteBytes<u32>(aFile, POINTER_CODE);
|
||||
_PtrData.first.Write(aFile);
|
||||
WriteBytes<u32>(aFile, _PtrData.second);
|
||||
}
|
||||
|
||||
//
|
||||
// Lights
|
||||
//
|
||||
|
||||
static void WriteLightData(FILE* aFile, GfxData* aGfxData, DataNode<Lights1> *aNode) {
|
||||
if (!aNode->mData) return;
|
||||
|
||||
// Header
|
||||
WriteBytes<u8>(aFile, DATA_TYPE_LIGHT);
|
||||
aNode->mName.Write(aFile);
|
||||
|
||||
// Data
|
||||
WriteBytes<Lights1>(aFile, *aNode->mData);
|
||||
}
|
||||
|
||||
//
|
||||
// Textures
|
||||
//
|
||||
|
||||
static void WriteTextureData(FILE* aFile, GfxData* aGfxData, DataNode<TexData> *aNode) {
|
||||
if (!aNode->mData) return;
|
||||
|
||||
// Header
|
||||
WriteBytes<u8>(aFile, DATA_TYPE_TEXTURE);
|
||||
aNode->mName.Write(aFile);
|
||||
|
||||
// Data
|
||||
aNode->mData->mPngData.Write(aFile);
|
||||
}
|
||||
|
||||
//
|
||||
// Vertices
|
||||
//
|
||||
|
||||
static void WriteVertexData(FILE* aFile, GfxData* aGfxData, DataNode<Vtx> *aNode) {
|
||||
if (!aNode->mData) return;
|
||||
|
||||
// Header
|
||||
WriteBytes<u8>(aFile, DATA_TYPE_VERTEX);
|
||||
aNode->mName.Write(aFile);
|
||||
|
||||
// Data
|
||||
WriteBytes<u32>(aFile, aNode->mSize);
|
||||
for (u32 i = 0; i != aNode->mSize; ++i) {
|
||||
WriteBytes<s16>(aFile, aNode->mData[i].n.ob[0]);
|
||||
WriteBytes<s16>(aFile, aNode->mData[i].n.ob[1]);
|
||||
WriteBytes<s16>(aFile, aNode->mData[i].n.ob[2]);
|
||||
WriteBytes<s16>(aFile, aNode->mData[i].n.flag);
|
||||
WriteBytes<s16>(aFile, aNode->mData[i].n.tc[0]);
|
||||
WriteBytes<s16>(aFile, aNode->mData[i].n.tc[1]);
|
||||
WriteBytes<s8> (aFile, aNode->mData[i].n.n[0]);
|
||||
WriteBytes<s8> (aFile, aNode->mData[i].n.n[1]);
|
||||
WriteBytes<s8> (aFile, aNode->mData[i].n.n[2]);
|
||||
WriteBytes<u8> (aFile, aNode->mData[i].n.a);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Display lists
|
||||
//
|
||||
|
||||
static void WriteDisplayListData(FILE *aFile, GfxData *aGfxData, DataNode<Gfx> *aNode) {
|
||||
if (!aNode->mData) return;
|
||||
|
||||
// Header
|
||||
WriteBytes<u8>(aFile, DATA_TYPE_DISPLAY_LIST);
|
||||
aNode->mName.Write(aFile);
|
||||
|
||||
// Data
|
||||
WriteBytes<u32>(aFile, aNode->mSize);
|
||||
for (u32 i = 0; i != aNode->mSize; ++i) {
|
||||
Gfx *_Head = &aNode->mData[i];
|
||||
if (aGfxData->mPointerList.Find((void *) _Head) != -1) {
|
||||
WriteBytes<u32>(aFile, _Head->words.w0);
|
||||
WritePointer(aFile, (const void *) _Head->words.w1, aGfxData);
|
||||
} else {
|
||||
WriteBytes<u32>(aFile, _Head->words.w0);
|
||||
WriteBytes<u32>(aFile, _Head->words.w1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Geo layouts
|
||||
//
|
||||
|
||||
static void WriteGeoLayoutData(FILE *aFile, GfxData *aGfxData, DataNode<GeoLayout> *aNode) {
|
||||
if (!aNode->mData) return;
|
||||
|
||||
// Header
|
||||
WriteBytes<u8>(aFile, DATA_TYPE_GEO_LAYOUT);
|
||||
aNode->mName.Write(aFile);
|
||||
|
||||
// Data
|
||||
WriteBytes<u32>(aFile, aNode->mSize);
|
||||
for (u32 i = 0; i != aNode->mSize; ++i) {
|
||||
GeoLayout *_Head = &aNode->mData[i];
|
||||
if (aGfxData->mPointerList.Find((void *) _Head) != -1) {
|
||||
WritePointer(aFile, (const void *) (*_Head), aGfxData);
|
||||
} else {
|
||||
WriteBytes<u32>(aFile, *((u32 *) _Head));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Animation data
|
||||
//
|
||||
|
||||
static void WriteAnimationData(FILE* aFile, GfxData* aGfxData) {
|
||||
for (auto& _Node : aGfxData->mAnimations) {
|
||||
|
||||
// Value buffer
|
||||
s32 _ValueBufferIdx = aGfxData->mAnimValues.FindIf([&_Node](const AnimBuffer<s16> *aAnimBuffer) { return aAnimBuffer->first == _Node->mData->mValues.first; });
|
||||
if (_ValueBufferIdx == -1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Index buffer
|
||||
s32 _IndexBufferIdx = aGfxData->mAnimIndices.FindIf([&_Node](const AnimBuffer<u16> *aAnimBuffer) { return aAnimBuffer->first == _Node->mData->mIndex.first; });
|
||||
if (_IndexBufferIdx == -1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Unk0A buffer
|
||||
s32 _Unk0ABufferIdx = aGfxData->mAnimIndices.FindIf([&_Node](const AnimBuffer<u16> *aAnimBuffer) { return aAnimBuffer->first == _Node->mData->mUnk0A.first; });
|
||||
if (_Unk0ABufferIdx == -1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Header
|
||||
WriteBytes<u8>(aFile, DATA_TYPE_ANIMATION);
|
||||
_Node->mName.Write(aFile);
|
||||
|
||||
// Data
|
||||
WriteBytes<s16>(aFile, _Node->mData->mFlags);
|
||||
WriteBytes<s16>(aFile, _Node->mData->mUnk02);
|
||||
WriteBytes<s16>(aFile, _Node->mData->mUnk04);
|
||||
WriteBytes<s16>(aFile, _Node->mData->mUnk06);
|
||||
WriteBytes<s16>(aFile, _Node->mData->mUnk08);
|
||||
WriteBytes<s16>(aFile, (aGfxData->mAnimIndices[_Unk0ABufferIdx]->second.Count() / 6) - 1);
|
||||
WriteBytes<u32>(aFile, _Node->mData->mLength);
|
||||
aGfxData->mAnimValues[_ValueBufferIdx]->second.Write(aFile);
|
||||
aGfxData->mAnimIndices[_IndexBufferIdx]->second.Write(aFile);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Animation table
|
||||
//
|
||||
|
||||
static void WriteAnimationTable(FILE* aFile, GfxData* aGfxData) {
|
||||
for (auto& _AnimName : aGfxData->mAnimationTable) {
|
||||
|
||||
// Header
|
||||
WriteBytes<u8>(aFile, DATA_TYPE_ANIMATION_TABLE);
|
||||
|
||||
// Data
|
||||
_AnimName.first.Write(aFile);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Write
|
||||
//
|
||||
|
||||
bool DynOS_Gfx_WriteBinary(const SysPath &aOutputFilename, GfxData *aGfxData) {
|
||||
FILE *_File = fopen(aOutputFilename.c_str(), "wb");
|
||||
if (!_File) {
|
||||
PrintError(" ERROR: Unable to create file \"%s\"", aOutputFilename.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
for (u64 i = 0; i != aGfxData->mLoadIndex; ++i) {
|
||||
for (auto &_Node : aGfxData->mLights) {
|
||||
if (_Node->mLoadIndex == i) {
|
||||
WriteLightData(_File, aGfxData, _Node);
|
||||
}
|
||||
}
|
||||
for (auto &_Node : aGfxData->mTextures) {
|
||||
if (_Node->mLoadIndex == i) {
|
||||
WriteTextureData(_File, aGfxData, _Node);
|
||||
}
|
||||
}
|
||||
for (auto &_Node : aGfxData->mVertices) {
|
||||
if (_Node->mLoadIndex == i) {
|
||||
WriteVertexData(_File, aGfxData, _Node);
|
||||
}
|
||||
}
|
||||
for (auto &_Node : aGfxData->mDisplayLists) {
|
||||
if (_Node->mLoadIndex == i) {
|
||||
WriteDisplayListData(_File, aGfxData, _Node);
|
||||
}
|
||||
}
|
||||
for (auto &_Node : aGfxData->mGeoLayouts) {
|
||||
if (_Node->mLoadIndex == i) {
|
||||
WriteGeoLayoutData(_File, aGfxData, _Node);
|
||||
}
|
||||
}
|
||||
}
|
||||
WriteAnimationData(_File, aGfxData);
|
||||
WriteAnimationTable(_File, aGfxData);
|
||||
fclose(_File);
|
||||
return true;
|
||||
}
|
||||
|
||||
//
|
||||
// Free
|
||||
//
|
||||
|
||||
void DynOS_Gfx_Free(GfxData* aGfxData) {
|
||||
if (aGfxData) {
|
||||
for (auto& _Node : aGfxData->mLights) {
|
||||
Delete(_Node->mData);
|
||||
Delete(_Node);
|
||||
}
|
||||
for (auto& _Node : aGfxData->mTextures) {
|
||||
Delete(_Node->mData);
|
||||
Delete(_Node);
|
||||
}
|
||||
for (auto& _Node : aGfxData->mVertices) {
|
||||
Delete(_Node->mData);
|
||||
Delete(_Node);
|
||||
}
|
||||
for (auto& _Node : aGfxData->mDisplayLists) {
|
||||
Delete(_Node->mData);
|
||||
Delete(_Node);
|
||||
}
|
||||
for (auto& _Node : aGfxData->mGeoLayouts) {
|
||||
Delete(_Node->mData);
|
||||
Delete(_Node);
|
||||
}
|
||||
for (auto& _Node : aGfxData->mAnimations) {
|
||||
Delete(_Node->mData);
|
||||
Delete(_Node);
|
||||
}
|
||||
Delete(aGfxData);
|
||||
}
|
||||
}
|
825
data/dynos_level.cpp
Normal file
825
data/dynos_level.cpp
Normal file
|
@ -0,0 +1,825 @@
|
|||
#include "dynos.cpp.h"
|
||||
extern "C" {
|
||||
#include "game/segment2.h"
|
||||
#include "game/save_file.h"
|
||||
#include "levels/scripts.h"
|
||||
}
|
||||
|
||||
//
|
||||
// Const
|
||||
//
|
||||
|
||||
extern "C" {
|
||||
extern const BehaviorScript *sWarpBhvSpawnTable[];
|
||||
}
|
||||
|
||||
#define DYNOS_LEVEL_TEXT_EMPTY ""
|
||||
#define DYNOS_LEVEL_TEXT_CASTLE "CASTLE"
|
||||
#define DYNOS_LEVEL_TEXT_BOWSER_1 "BOWSER 1"
|
||||
#define DYNOS_LEVEL_TEXT_BOWSER_2 "BOWSER 2"
|
||||
#define DYNOS_LEVEL_TEXT_BOWSER_3 "BOWSER 3"
|
||||
#define DYNOS_LEVEL_TEXT_100_COINS_STAR "100 COINS STAR"
|
||||
#define DYNOS_LEVEL_TEXT_RED_COINS_STAR "RED COINS STAR"
|
||||
#define DYNOS_LEVEL_TEXT_ONE_SECRET_STAR "ONE OF THE CASTLE'S SECRET STARS!"
|
||||
|
||||
static void SetConvertedTextToBuffer(u8 *aBuffer, const char *aText) {
|
||||
u8 *_ConvertedText = DynOS_String_Convert(aText, false);
|
||||
memcpy(aBuffer, _ConvertedText, DynOS_String_Length(_ConvertedText) + 1);
|
||||
}
|
||||
|
||||
//
|
||||
// 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;
|
||||
};
|
||||
|
||||
static void *sDynosLevelScripts[LEVEL_COUNT] = { NULL };
|
||||
static Array<DynosWarp> sDynosLevelWarps[LEVEL_COUNT] = { Array<DynosWarp>() };
|
||||
static Array<s32> sDynosLevelList = Array<s32>(); // Ordered by Course Id, COURSE_NONE excluded
|
||||
|
||||
static u64 DynOS_Level_CmdGet(void *aCmd, u64 aOffset) {
|
||||
u64 _Offset = (((aOffset) & 3llu) | (((aOffset) & ~3llu) << (sizeof(void *) >> 3llu)));
|
||||
return *((u64 *) (u64(aCmd) + _Offset));
|
||||
}
|
||||
|
||||
static void *DynOS_Level_CmdNext(void *aCmd, u64 aCmdSize) {
|
||||
u64 _Offset = (((aCmdSize) & 3llu) | (((aCmdSize) & ~3llu) << (sizeof(void *) >> 3llu)));
|
||||
return (void *) (u64(aCmd) + _Offset);
|
||||
}
|
||||
|
||||
static void DynOS_Level_ParseScript(const void *aScript, s32 (*aPreprocessFunction)(u8, void *));
|
||||
|
||||
//
|
||||
// Init
|
||||
//
|
||||
|
||||
static s32 DynOS_Level_PreprocessMasterScript(u8 aType, void *aCmd) {
|
||||
static bool sDynosScriptExecLevelTable = false;
|
||||
static s32 sDynosLevelNum = -1;
|
||||
|
||||
if (!sDynosScriptExecLevelTable) {
|
||||
|
||||
// JUMP_LINK
|
||||
if (aType == 0x06) {
|
||||
sDynosScriptExecLevelTable = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
// JUMP_IF
|
||||
if (aType == 0x0C) {
|
||||
sDynosLevelNum = (s32) DynOS_Level_CmdGet(aCmd, 0x04);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// EXECUTE
|
||||
if (aType == 0x00) {
|
||||
void *_Script = (void *) DynOS_Level_CmdGet(aCmd, 0x0C);
|
||||
if (sDynosLevelNum >= 0 && sDynosLevelNum < LEVEL_COUNT && !sDynosLevelScripts[sDynosLevelNum]) {
|
||||
sDynosLevelScripts[sDynosLevelNum] = _Script;
|
||||
}
|
||||
sDynosLevelNum = -1;
|
||||
return 2;
|
||||
}
|
||||
|
||||
// EXIT
|
||||
if (aType == 0x02) {
|
||||
return 3;
|
||||
}
|
||||
|
||||
// SLEEP
|
||||
if (aType == 0x03) {
|
||||
return 3;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static s32 sDynosCurrentLevelNum;
|
||||
static s32 DynOS_Level_PreprocessScript(u8 aType, void *aCmd) {
|
||||
static u8 sDynosAreaIndex = 0;
|
||||
static auto _GetWarpStruct = [](u8 aArea, u8 aId) -> DynosWarp * {
|
||||
for (s32 i = 0; i != sDynosLevelWarps[sDynosCurrentLevelNum].Count(); ++i) {
|
||||
if (sDynosLevelWarps[sDynosCurrentLevelNum][i].mArea == aArea &&
|
||||
sDynosLevelWarps[sDynosCurrentLevelNum][i].mId == aId) {
|
||||
return &sDynosLevelWarps[sDynosCurrentLevelNum][i];
|
||||
}
|
||||
}
|
||||
DynosWarp _Warp;
|
||||
_Warp.mArea = aArea;
|
||||
_Warp.mId = aId;
|
||||
sDynosLevelWarps[sDynosCurrentLevelNum].Add(_Warp);
|
||||
return &sDynosLevelWarps[sDynosCurrentLevelNum][sDynosLevelWarps[sDynosCurrentLevelNum].Count() - 1];
|
||||
};
|
||||
|
||||
// AREA
|
||||
if (aType == 0x1F) {
|
||||
sDynosAreaIndex = (u8) DynOS_Level_CmdGet(aCmd, 2);
|
||||
}
|
||||
|
||||
// OBJECT
|
||||
else if (aType == 0x24) {
|
||||
const BehaviorScript *bhv = (const BehaviorScript *) DynOS_Level_CmdGet(aCmd, 20);
|
||||
for (s32 i = 0; i < 20; ++i) {
|
||||
if (sWarpBhvSpawnTable[i] == bhv) {
|
||||
DynosWarp *_Warp = _GetWarpStruct(sDynosAreaIndex, ((((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)((((s32)((s16) DynOS_Level_CmdGet(aCmd, 12))) * 0x8000) / 180);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// WARP_NODE
|
||||
else if (aType == 0x26) {
|
||||
DynosWarp *_Warp = _GetWarpStruct(sDynosAreaIndex, (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);
|
||||
}
|
||||
}
|
||||
|
||||
// PAINTING_WARP_NODE
|
||||
else if (aType == 0x27) {
|
||||
DynosWarp *_Warp = _GetWarpStruct(sDynosAreaIndex, (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);
|
||||
}
|
||||
}
|
||||
|
||||
// SLEEP
|
||||
// SLEEP_BEFORE_EXIT
|
||||
else if (aType == 0x03 || aType == 0x04) {
|
||||
return 3;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Runs only once
|
||||
static void DynOS_Level_Init() {
|
||||
static bool sInited = false;
|
||||
if (!sInited) {
|
||||
|
||||
// Level scripts
|
||||
DynOS_Level_ParseScript(level_main_scripts_entry, DynOS_Level_PreprocessMasterScript);
|
||||
|
||||
// Level warps
|
||||
for (sDynosCurrentLevelNum = 0; sDynosCurrentLevelNum != LEVEL_COUNT; ++sDynosCurrentLevelNum) {
|
||||
if (sDynosLevelScripts[sDynosCurrentLevelNum]) {
|
||||
DynOS_Level_ParseScript(sDynosLevelScripts[sDynosCurrentLevelNum], DynOS_Level_PreprocessScript);
|
||||
}
|
||||
}
|
||||
|
||||
// Level list ordered by course id
|
||||
for (s32 i = COURSE_MIN; i <= COURSE_MAX; ++i) {
|
||||
if (i == COURSE_CAKE_END) continue;
|
||||
for (s32 j = 1; j != LEVEL_COUNT; ++j) {
|
||||
if (gLevelToCourseNumTable[j - 1] == i) {
|
||||
sDynosLevelList.Add(j);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Done
|
||||
sInited = true;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Common
|
||||
//
|
||||
|
||||
s32 DynOS_Level_GetCount() {
|
||||
DynOS_Level_Init();
|
||||
return sDynosLevelList.Count();
|
||||
}
|
||||
|
||||
const s32 *DynOS_Level_GetList() {
|
||||
DynOS_Level_Init();
|
||||
return sDynosLevelList.begin();
|
||||
}
|
||||
|
||||
s32 DynOS_Level_GetCourse(s32 aLevel) {
|
||||
return (s32) gLevelToCourseNumTable[aLevel - 1];
|
||||
}
|
||||
|
||||
const void *DynOS_Level_GetScript(s32 aLevel) {
|
||||
DynOS_Level_Init();
|
||||
return sDynosLevelScripts[aLevel];
|
||||
}
|
||||
|
||||
//
|
||||
// Course name
|
||||
//
|
||||
|
||||
const u8 *DynOS_Level_GetName(s32 aLevel, bool aDecaps, bool aAddCourseNumber) {
|
||||
DynOS_Level_Init();
|
||||
static u8 sBuffer[256];
|
||||
memset(sBuffer, 0xFF, 256);
|
||||
s32 _Course = DynOS_Level_GetCourse(aLevel);
|
||||
|
||||
// Level name
|
||||
if (aLevel == LEVEL_BOWSER_1) {
|
||||
SetConvertedTextToBuffer(sBuffer, DYNOS_LEVEL_TEXT_BOWSER_1);
|
||||
} else if (aLevel == LEVEL_BOWSER_2) {
|
||||
SetConvertedTextToBuffer(sBuffer, DYNOS_LEVEL_TEXT_BOWSER_2);
|
||||
} else if (aLevel == LEVEL_BOWSER_3) {
|
||||
SetConvertedTextToBuffer(sBuffer, DYNOS_LEVEL_TEXT_BOWSER_3);
|
||||
} else if (_Course < COURSE_BOB) {
|
||||
SetConvertedTextToBuffer(sBuffer, DYNOS_LEVEL_TEXT_CASTLE);
|
||||
} else if (_Course >= COURSE_CAKE_END) {
|
||||
SetConvertedTextToBuffer(sBuffer, DYNOS_LEVEL_TEXT_CASTLE);
|
||||
} else {
|
||||
const u8 *_CourseName = ((const u8 **) seg2_course_name_table)[_Course - COURSE_BOB] + 3;
|
||||
memcpy(sBuffer, _CourseName, DynOS_String_Length(_CourseName));
|
||||
}
|
||||
|
||||
// Decaps
|
||||
if (aDecaps) {
|
||||
DynOS_String_Decapitalize(sBuffer);
|
||||
}
|
||||
|
||||
// Course number
|
||||
if (aAddCourseNumber && (_Course >= COURSE_BOB) && (_Course <= COURSE_STAGES_MAX)) {
|
||||
memmove(sBuffer + 5, sBuffer, DynOS_String_Length(sBuffer));
|
||||
sBuffer[0] = ((_Course / 10) == 0 ? 158 : (_Course / 10));
|
||||
sBuffer[1] = (_Course % 10);
|
||||
sBuffer[2] = 158;
|
||||
sBuffer[3] = 159;
|
||||
sBuffer[4] = 158;
|
||||
}
|
||||
|
||||
return sBuffer;
|
||||
}
|
||||
|
||||
//
|
||||
// Act/Star name
|
||||
//
|
||||
|
||||
const u8 *DynOS_Level_GetActName(s32 aLevel, s32 aAct, bool aDecaps, bool aAddStarNumber) {
|
||||
DynOS_Level_Init();
|
||||
static u8 sBuffer[256];
|
||||
memset(sBuffer, 0xFF, 256);
|
||||
s32 _Course = DynOS_Level_GetCourse(aLevel);
|
||||
|
||||
// Star name
|
||||
if (_Course < COURSE_BOB) {
|
||||
SetConvertedTextToBuffer(sBuffer, DYNOS_LEVEL_TEXT_ONE_SECRET_STAR);
|
||||
} else if (aLevel == LEVEL_BITDW) {
|
||||
SetConvertedTextToBuffer(sBuffer, DYNOS_LEVEL_TEXT_RED_COINS_STAR);
|
||||
} else if (aLevel == LEVEL_BITFS) {
|
||||
SetConvertedTextToBuffer(sBuffer, DYNOS_LEVEL_TEXT_RED_COINS_STAR);
|
||||
} else if (aLevel == LEVEL_BITS) {
|
||||
SetConvertedTextToBuffer(sBuffer, DYNOS_LEVEL_TEXT_RED_COINS_STAR);
|
||||
} else if (_Course > COURSE_STAGES_MAX) {
|
||||
SetConvertedTextToBuffer(sBuffer, DYNOS_LEVEL_TEXT_EMPTY);
|
||||
} else if (aAct >= 7) {
|
||||
SetConvertedTextToBuffer(sBuffer, DYNOS_LEVEL_TEXT_100_COINS_STAR);
|
||||
} else {
|
||||
const u8 *_ActName = ((const u8 **) seg2_act_name_table)[(_Course - COURSE_BOB) * 6 + (aAct - 1)];
|
||||
memcpy(sBuffer, _ActName, DynOS_String_Length(_ActName));
|
||||
}
|
||||
|
||||
// Decaps
|
||||
if (aDecaps) {
|
||||
DynOS_String_Decapitalize(sBuffer);
|
||||
}
|
||||
|
||||
// Star number
|
||||
if (aAddStarNumber && (_Course >= COURSE_BOB) && (_Course <= COURSE_STAGES_MAX)) {
|
||||
memmove(sBuffer + 5, sBuffer, DynOS_String_Length(sBuffer));
|
||||
sBuffer[0] = ((aAct / 10) == 0 ? 158 : (aAct / 10));
|
||||
sBuffer[1] = (aAct % 10);
|
||||
sBuffer[2] = 158;
|
||||
sBuffer[3] = 159;
|
||||
sBuffer[4] = 158;
|
||||
}
|
||||
|
||||
return sBuffer;
|
||||
}
|
||||
|
||||
const u8 *DynOS_Level_GetAreaName(s32 aLevel, s32 aArea, bool aDecaps) {
|
||||
DynOS_Level_Init();
|
||||
static const char *sAreaNamesPerLevel[][4] = {
|
||||
{ "", "", "", "" },
|
||||
{ "MAIN AREA", "NOT AVAILABLE", "NOT AVAILABLE", "NOT AVAILABLE" }, /* BoB */
|
||||
{ "MAIN AREA", "NOT AVAILABLE", "NOT AVAILABLE", "NOT AVAILABLE" }, /* WF */
|
||||
{ "MAIN AREA", "SUNKEN SHIP", "NOT AVAILABLE", "NOT AVAILABLE" }, /* JRB */
|
||||
{ "MAIN AREA", "COTTAGE SLIDE", "NOT AVAILABLE", "NOT AVAILABLE" }, /* CCM */
|
||||
{ "MAIN AREA", "NOT AVAILABLE", "NOT AVAILABLE", "NOT AVAILABLE" }, /* BBH */
|
||||
{ "MAIN AREA", "NOT AVAILABLE", "NOT AVAILABLE", "NOT AVAILABLE" }, /* HMC */
|
||||
{ "MAIN AREA", "VOLCANO", "NOT AVAILABLE", "NOT AVAILABLE" }, /* LLL */
|
||||
{ "MAIN AREA", "PYRAMID", "EYEROCK'S ROOM", "NOT AVAILABLE" }, /* SSL */
|
||||
{ "MAIN AREA", "DOCKS", "NOT AVAILABLE", "NOT AVAILABLE" }, /* DDD */
|
||||
{ "MAIN AREA", "IGLOO", "NOT AVAILABLE", "NOT AVAILABLE" }, /* SL */
|
||||
{ "MAIN AREA", "DOWNTOWN", "NOT AVAILABLE", "NOT AVAILABLE" }, /* WDW */
|
||||
{ "MAIN AREA", "SECRET SLIDE", "NOT AVAILABLE", "NOT AVAILABLE" }, /* TTM */
|
||||
{ "HUGE ISLAND", "TINY ISLAND", "WIGGLER'S ROOM", "NOT AVAILABLE" }, /* THI */
|
||||
{ "MAIN AREA", "NOT AVAILABLE", "NOT AVAILABLE", "NOT AVAILABLE" }, /* TTC */
|
||||
{ "MAIN AREA", "NOT AVAILABLE", "NOT AVAILABLE", "NOT AVAILABLE" }, /* RR */
|
||||
{ "MAIN AREA", "NOT AVAILABLE", "NOT AVAILABLE", "NOT AVAILABLE" }, /* BITDW */
|
||||
{ "BOWSER BATTLE", "NOT AVAILABLE", "NOT AVAILABLE", "NOT AVAILABLE" }, /* Bowser 1 */
|
||||
{ "MAIN AREA", "NOT AVAILABLE", "NOT AVAILABLE", "NOT AVAILABLE" }, /* BITFS */
|
||||
{ "BOWSER BATTLE", "NOT AVAILABLE", "NOT AVAILABLE", "NOT AVAILABLE" }, /* Bowser 2 */
|
||||
{ "MAIN AREA", "NOT AVAILABLE", "NOT AVAILABLE", "NOT AVAILABLE" }, /* BITS */
|
||||
{ "BOWSER BATTLE", "NOT AVAILABLE", "NOT AVAILABLE", "NOT AVAILABLE" }, /* Bowser 3 */
|
||||
{ "MAIN AREA", "NOT AVAILABLE", "NOT AVAILABLE", "NOT AVAILABLE" }, /* PSS */
|
||||
{ "MAIN AREA", "NOT AVAILABLE", "NOT AVAILABLE", "NOT AVAILABLE" }, /* TOTWC */
|
||||
{ "MAIN AREA", "NOT AVAILABLE", "NOT AVAILABLE", "NOT AVAILABLE" }, /* COTMC */
|
||||
{ "MAIN AREA", "NOT AVAILABLE", "NOT AVAILABLE", "NOT AVAILABLE" }, /* VCUTM */
|
||||
{ "MAIN AREA", "NOT AVAILABLE", "NOT AVAILABLE", "NOT AVAILABLE" }, /* WMOTR */
|
||||
{ "MAIN AREA", "NOT AVAILABLE", "NOT AVAILABLE", "NOT AVAILABLE" }, /* SA */
|
||||
{ "MAIN AREA", "NOT AVAILABLE", "NOT AVAILABLE", "NOT AVAILABLE" }, /* Castle grounds */
|
||||
{ "FIRST FLOOR", "SECOND FLOOR", "BASEMENT", "NOT AVAILABLE" }, /* Castle inside */
|
||||
{ "MAIN AREA", "NOT AVAILABLE", "NOT AVAILABLE", "NOT AVAILABLE" }, /* Castle courtyard */
|
||||
};
|
||||
static u8 sBuffer[256];
|
||||
memset(sBuffer, 0xFF, 256);
|
||||
|
||||
// Area name
|
||||
switch (aLevel) {
|
||||
case LEVEL_BOB: SetConvertedTextToBuffer(sBuffer, sAreaNamesPerLevel[1][MIN(MAX(aArea - 1, 0), 3)]); break;
|
||||
case LEVEL_WF: SetConvertedTextToBuffer(sBuffer, sAreaNamesPerLevel[2][MIN(MAX(aArea - 1, 0), 3)]); break;
|
||||
case LEVEL_JRB: SetConvertedTextToBuffer(sBuffer, sAreaNamesPerLevel[3][MIN(MAX(aArea - 1, 0), 3)]); break;
|
||||
case LEVEL_CCM: SetConvertedTextToBuffer(sBuffer, sAreaNamesPerLevel[4][MIN(MAX(aArea - 1, 0), 3)]); break;
|
||||
case LEVEL_BBH: SetConvertedTextToBuffer(sBuffer, sAreaNamesPerLevel[5][MIN(MAX(aArea - 1, 0), 3)]); break;
|
||||
case LEVEL_HMC: SetConvertedTextToBuffer(sBuffer, sAreaNamesPerLevel[6][MIN(MAX(aArea - 1, 0), 3)]); break;
|
||||
case LEVEL_LLL: SetConvertedTextToBuffer(sBuffer, sAreaNamesPerLevel[7][MIN(MAX(aArea - 1, 0), 3)]); break;
|
||||
case LEVEL_SSL: SetConvertedTextToBuffer(sBuffer, sAreaNamesPerLevel[8][MIN(MAX(aArea - 1, 0), 3)]); break;
|
||||
case LEVEL_DDD: SetConvertedTextToBuffer(sBuffer, sAreaNamesPerLevel[9][MIN(MAX(aArea - 1, 0), 3)]); break;
|
||||
case LEVEL_SL: SetConvertedTextToBuffer(sBuffer, sAreaNamesPerLevel[10][MIN(MAX(aArea - 1, 0), 3)]); break;
|
||||
case LEVEL_WDW: SetConvertedTextToBuffer(sBuffer, sAreaNamesPerLevel[11][MIN(MAX(aArea - 1, 0), 3)]); break;
|
||||
case LEVEL_TTM: SetConvertedTextToBuffer(sBuffer, sAreaNamesPerLevel[12][MIN(MAX(aArea - 1, 0), 3)]); break;
|
||||
case LEVEL_THI: SetConvertedTextToBuffer(sBuffer, sAreaNamesPerLevel[13][MIN(MAX(aArea - 1, 0), 3)]); break;
|
||||
case LEVEL_TTC: SetConvertedTextToBuffer(sBuffer, sAreaNamesPerLevel[14][MIN(MAX(aArea - 1, 0), 3)]); break;
|
||||
case LEVEL_RR: SetConvertedTextToBuffer(sBuffer, sAreaNamesPerLevel[15][MIN(MAX(aArea - 1, 0), 3)]); break;
|
||||
case LEVEL_BITDW: SetConvertedTextToBuffer(sBuffer, sAreaNamesPerLevel[16][MIN(MAX(aArea - 1, 0), 3)]); break;
|
||||
case LEVEL_BOWSER_1: SetConvertedTextToBuffer(sBuffer, sAreaNamesPerLevel[17][MIN(MAX(aArea - 1, 0), 3)]); break;
|
||||
case LEVEL_BITFS: SetConvertedTextToBuffer(sBuffer, sAreaNamesPerLevel[18][MIN(MAX(aArea - 1, 0), 3)]); break;
|
||||
case LEVEL_BOWSER_2: SetConvertedTextToBuffer(sBuffer, sAreaNamesPerLevel[19][MIN(MAX(aArea - 1, 0), 3)]); break;
|
||||
case LEVEL_BITS: SetConvertedTextToBuffer(sBuffer, sAreaNamesPerLevel[20][MIN(MAX(aArea - 1, 0), 3)]); break;
|
||||
case LEVEL_BOWSER_3: SetConvertedTextToBuffer(sBuffer, sAreaNamesPerLevel[21][MIN(MAX(aArea - 1, 0), 3)]); break;
|
||||
case LEVEL_PSS: SetConvertedTextToBuffer(sBuffer, sAreaNamesPerLevel[22][MIN(MAX(aArea - 1, 0), 3)]); break;
|
||||
case LEVEL_TOTWC: SetConvertedTextToBuffer(sBuffer, sAreaNamesPerLevel[23][MIN(MAX(aArea - 1, 0), 3)]); break;
|
||||
case LEVEL_COTMC: SetConvertedTextToBuffer(sBuffer, sAreaNamesPerLevel[24][MIN(MAX(aArea - 1, 0), 3)]); break;
|
||||
case LEVEL_VCUTM: SetConvertedTextToBuffer(sBuffer, sAreaNamesPerLevel[25][MIN(MAX(aArea - 1, 0), 3)]); break;
|
||||
case LEVEL_WMOTR: SetConvertedTextToBuffer(sBuffer, sAreaNamesPerLevel[26][MIN(MAX(aArea - 1, 0), 3)]); break;
|
||||
case LEVEL_SA: SetConvertedTextToBuffer(sBuffer, sAreaNamesPerLevel[27][MIN(MAX(aArea - 1, 0), 3)]); break;
|
||||
case LEVEL_CASTLE_GROUNDS: SetConvertedTextToBuffer(sBuffer, sAreaNamesPerLevel[28][MIN(MAX(aArea - 1, 0), 3)]); break;
|
||||
case LEVEL_CASTLE: SetConvertedTextToBuffer(sBuffer, sAreaNamesPerLevel[29][MIN(MAX(aArea - 1, 0), 3)]); break;
|
||||
case LEVEL_CASTLE_COURTYARD: SetConvertedTextToBuffer(sBuffer, sAreaNamesPerLevel[30][MIN(MAX(aArea - 1, 0), 3)]); break;
|
||||
default: SetConvertedTextToBuffer(sBuffer, sAreaNamesPerLevel[0][MIN(MAX(aArea - 1, 0), 3)]); break;
|
||||
}
|
||||
|
||||
// Decaps
|
||||
if (aDecaps) {
|
||||
DynOS_String_Decapitalize(sBuffer);
|
||||
}
|
||||
return sBuffer;
|
||||
}
|
||||
|
||||
//
|
||||
// Level Script Preprocessing
|
||||
// By default,
|
||||
// - Ifs are always true
|
||||
// - Skips are always false
|
||||
// - Loops break after the first loop
|
||||
//
|
||||
|
||||
struct LvlCmd {
|
||||
u8 mType;
|
||||
u8 mSize;
|
||||
};
|
||||
|
||||
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, aCmd->mSize));
|
||||
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_CmdSleep(Stack &aStack, LvlCmd *aCmd) {
|
||||
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
||||
}
|
||||
|
||||
static LvlCmd *DynOS_Level_CmdSleepBeforeExit(Stack &aStack, LvlCmd *aCmd) {
|
||||
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
||||
}
|
||||
|
||||
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, aCmd->mSize));
|
||||
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, aCmd->mSize));
|
||||
StackPush(aStack, DynOS_Level_CmdGet(aCmd, 2));
|
||||
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
||||
}
|
||||
|
||||
static LvlCmd *DynOS_Level_CmdJumpRepeat(Stack &aStack, LvlCmd *aCmd) {
|
||||
aStack.mTopIndex -= 2;
|
||||
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
||||
}
|
||||
|
||||
static LvlCmd *DynOS_Level_CmdLoopBegin(Stack &aStack, LvlCmd *aCmd) {
|
||||
StackPush(aStack, DynOS_Level_CmdNext(aCmd, aCmd->mSize));
|
||||
StackPush(aStack, 0);
|
||||
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
||||
}
|
||||
|
||||
static LvlCmd *DynOS_Level_CmdLoopUntil(Stack &aStack, LvlCmd *aCmd) {
|
||||
aStack.mTopIndex -= 2;
|
||||
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
||||
}
|
||||
|
||||
static LvlCmd *DynOS_Level_CmdJumpIf(Stack &aStack, LvlCmd *aCmd) {
|
||||
StackPush(aStack, DynOS_Level_CmdNext(aCmd, aCmd->mSize)); /* 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, aCmd->mSize));
|
||||
return (LvlCmd *) DynOS_Level_CmdGet(aCmd, 8);
|
||||
}
|
||||
|
||||
static LvlCmd *DynOS_Level_CmdSkipIf(Stack &aStack, LvlCmd *aCmd) {
|
||||
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
||||
}
|
||||
|
||||
static LvlCmd *DynOS_Level_CmdSkip(Stack &aStack, LvlCmd *aCmd) {
|
||||
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
||||
}
|
||||
|
||||
static LvlCmd *DynOS_Level_CmdSkipNop(Stack &aStack, LvlCmd *aCmd) {
|
||||
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
||||
}
|
||||
|
||||
static LvlCmd *DynOS_Level_CmdCall(Stack &aStack, LvlCmd *aCmd) {
|
||||
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
||||
}
|
||||
|
||||
static LvlCmd *DynOS_Level_CmdCallLoop(Stack &aStack, LvlCmd *aCmd) {
|
||||
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
||||
}
|
||||
|
||||
static LvlCmd *DynOS_Level_CmdSetRegister(Stack &aStack, LvlCmd *aCmd) {
|
||||
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
||||
}
|
||||
|
||||
static LvlCmd *DynOS_Level_CmdPushPool(Stack &aStack, LvlCmd *aCmd) {
|
||||
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
||||
}
|
||||
|
||||
static LvlCmd *DynOS_Level_CmdPopPool(Stack &aStack, LvlCmd *aCmd) {
|
||||
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
||||
}
|
||||
|
||||
static LvlCmd *DynOS_Level_CmdLoadFixed(Stack &aStack, LvlCmd *aCmd) {
|
||||
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
||||
}
|
||||
|
||||
static LvlCmd *DynOS_Level_CmdLoadRaw(Stack &aStack, LvlCmd *aCmd) {
|
||||
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
||||
}
|
||||
|
||||
static LvlCmd *DynOS_Level_CmdLoadMIO0(Stack &aStack, LvlCmd *aCmd) {
|
||||
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
||||
}
|
||||
|
||||
static LvlCmd *DynOS_Level_CmdLoadMarioHead(Stack &aStack, LvlCmd *aCmd) {
|
||||
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
||||
}
|
||||
|
||||
static LvlCmd *DynOS_Level_CmdLoadMIO0Texture(Stack &aStack, LvlCmd *aCmd) {
|
||||
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
||||
}
|
||||
|
||||
static LvlCmd *DynOS_Level_CmdInitLevel(Stack &aStack, LvlCmd *aCmd) {
|
||||
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
||||
}
|
||||
|
||||
static LvlCmd *DynOS_Level_CmdClearLevel(Stack &aStack, LvlCmd *aCmd) {
|
||||
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
||||
}
|
||||
|
||||
static LvlCmd *DynOS_Level_CmdAllocLevelPool(Stack &aStack, LvlCmd *aCmd) {
|
||||
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
||||
}
|
||||
|
||||
static LvlCmd *DynOS_Level_CmdFreeLevelPool(Stack &aStack, LvlCmd *aCmd) {
|
||||
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
||||
}
|
||||
|
||||
static LvlCmd *DynOS_Level_CmdBeginArea(Stack &aStack, LvlCmd *aCmd) {
|
||||
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
||||
}
|
||||
|
||||
static LvlCmd *DynOS_Level_CmdEndArea(Stack &aStack, LvlCmd *aCmd) {
|
||||
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
||||
}
|
||||
|
||||
static LvlCmd *DynOS_Level_CmdLoadModelFromDL(Stack &aStack, LvlCmd *aCmd) {
|
||||
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
||||
}
|
||||
|
||||
static LvlCmd *DynOS_Level_CmdLoadModelFromGeo(Stack &aStack, LvlCmd *aCmd) {
|
||||
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
||||
}
|
||||
|
||||
static LvlCmd *DynOS_Level_Cmd23(Stack &aStack, LvlCmd *aCmd) {
|
||||
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
||||
}
|
||||
|
||||
static LvlCmd *DynOS_Level_CmdMario(Stack &aStack, LvlCmd *aCmd) {
|
||||
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
||||
}
|
||||
|
||||
static LvlCmd *DynOS_Level_CmdObject(Stack &aStack, LvlCmd *aCmd) {
|
||||
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
||||
}
|
||||
|
||||
static LvlCmd *DynOS_Level_CmdWarpNode(Stack &aStack, LvlCmd *aCmd) {
|
||||
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
||||
}
|
||||
|
||||
static LvlCmd *DynOS_Level_CmdInstantWarp(Stack &aStack, LvlCmd *aCmd) {
|
||||
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
||||
}
|
||||
|
||||
static LvlCmd *DynOS_Level_CmdSetTerrainType(Stack &aStack, LvlCmd *aCmd) {
|
||||
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
||||
}
|
||||
|
||||
static LvlCmd *DynOS_Level_CmdPaintingWarpNode(Stack &aStack, LvlCmd *aCmd) {
|
||||
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
||||
}
|
||||
|
||||
static LvlCmd *DynOS_Level_Cmd3A(Stack &aStack, LvlCmd *aCmd) {
|
||||
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
||||
}
|
||||
|
||||
static LvlCmd *DynOS_Level_CmdSetWhirlpool(Stack &aStack, LvlCmd *aCmd) {
|
||||
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
||||
}
|
||||
|
||||
static LvlCmd *DynOS_Level_CmdSetBlackout(Stack &aStack, LvlCmd *aCmd) {
|
||||
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
||||
}
|
||||
|
||||
static LvlCmd *DynOS_Level_CmdSetGamma(Stack &aStack, LvlCmd *aCmd) {
|
||||
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
||||
}
|
||||
|
||||
static LvlCmd *DynOS_Level_CmdSetTerrain(Stack &aStack, LvlCmd *aCmd) {
|
||||
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
||||
}
|
||||
|
||||
static LvlCmd *DynOS_Level_CmdSetRooms(Stack &aStack, LvlCmd *aCmd) {
|
||||
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
||||
}
|
||||
|
||||
static LvlCmd *DynOS_Level_CmdMacroObjects(Stack &aStack, LvlCmd *aCmd) {
|
||||
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
||||
}
|
||||
|
||||
static LvlCmd *DynOS_Level_CmdLoadArea(Stack &aStack, LvlCmd *aCmd) {
|
||||
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
||||
}
|
||||
|
||||
static LvlCmd *DynOS_Level_CmdUnloadArea(Stack &aStack, LvlCmd *aCmd) {
|
||||
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
||||
}
|
||||
|
||||
static LvlCmd *DynOS_Level_CmdSetMarioStartPos(Stack &aStack, LvlCmd *aCmd) {
|
||||
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
||||
}
|
||||
|
||||
static LvlCmd *DynOS_Level_Cmd2C(Stack &aStack, LvlCmd *aCmd) {
|
||||
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
||||
}
|
||||
|
||||
static LvlCmd *DynOS_Level_Cmd2D(Stack &aStack, LvlCmd *aCmd) {
|
||||
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
||||
}
|
||||
|
||||
static LvlCmd *DynOS_Level_CmdSetTransition(Stack &aStack, LvlCmd *aCmd) {
|
||||
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
||||
}
|
||||
|
||||
static LvlCmd *DynOS_Level_CmdNop(Stack &aStack, LvlCmd *aCmd) {
|
||||
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
||||
}
|
||||
|
||||
static LvlCmd *DynOS_Level_CmdShowDialog(Stack &aStack, LvlCmd *aCmd) {
|
||||
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
||||
}
|
||||
|
||||
static LvlCmd *DynOS_Level_CmdSetBackgroundMusic(Stack &aStack, LvlCmd *aCmd) {
|
||||
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
||||
}
|
||||
|
||||
static LvlCmd *DynOS_Level_CmdSetMenuMusic(Stack &aStack, LvlCmd *aCmd) {
|
||||
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
||||
}
|
||||
|
||||
static LvlCmd *DynOS_Level_CmdStopMusic(Stack &aStack, LvlCmd *aCmd) {
|
||||
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
||||
}
|
||||
|
||||
static LvlCmd *DynOS_Level_CmdGetOrSet(Stack &aStack, LvlCmd *aCmd) {
|
||||
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
||||
}
|
||||
|
||||
static LvlCmd *DynOS_Level_CmdAdvanceDemo(Stack &aStack, LvlCmd *aCmd) {
|
||||
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
||||
}
|
||||
|
||||
static LvlCmd *DynOS_Level_CmdClearDemoPointer(Stack &aStack, LvlCmd *aCmd) {
|
||||
return (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
||||
}
|
||||
|
||||
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 (LvlCmd *) DynOS_Level_CmdNext(aCmd, aCmd->mSize);
|
||||
}
|
||||
|
||||
static 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 & 0x3F);
|
||||
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 0x03: _Cmd = DynOS_Level_CmdSleep(_Stack, _Cmd); break;
|
||||
case 0x04: _Cmd = DynOS_Level_CmdSleepBeforeExit(_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;
|
||||
case 0x0E: _Cmd = DynOS_Level_CmdSkipIf(_Stack, _Cmd); break;
|
||||
case 0x0F: _Cmd = DynOS_Level_CmdSkip(_Stack, _Cmd); break;
|
||||
case 0x10: _Cmd = DynOS_Level_CmdSkipNop(_Stack, _Cmd); break;
|
||||
case 0x11: _Cmd = DynOS_Level_CmdCall(_Stack, _Cmd); break;
|
||||
case 0x12: _Cmd = DynOS_Level_CmdCallLoop(_Stack, _Cmd); break;
|
||||
case 0x13: _Cmd = DynOS_Level_CmdSetRegister(_Stack, _Cmd); break;
|
||||
case 0x14: _Cmd = DynOS_Level_CmdPushPool(_Stack, _Cmd); break;
|
||||
case 0x15: _Cmd = DynOS_Level_CmdPopPool(_Stack, _Cmd); break;
|
||||
case 0x16: _Cmd = DynOS_Level_CmdLoadFixed(_Stack, _Cmd); break;
|
||||
case 0x17: _Cmd = DynOS_Level_CmdLoadRaw(_Stack, _Cmd); break;
|
||||
case 0x18: _Cmd = DynOS_Level_CmdLoadMIO0(_Stack, _Cmd); break;
|
||||
case 0x19: _Cmd = DynOS_Level_CmdLoadMarioHead(_Stack, _Cmd); break;
|
||||
case 0x1A: _Cmd = DynOS_Level_CmdLoadMIO0Texture(_Stack, _Cmd); break;
|
||||
case 0x1B: _Cmd = DynOS_Level_CmdInitLevel(_Stack, _Cmd); break;
|
||||
case 0x1C: _Cmd = DynOS_Level_CmdClearLevel(_Stack, _Cmd); break;
|
||||
case 0x1D: _Cmd = DynOS_Level_CmdAllocLevelPool(_Stack, _Cmd); break;
|
||||
case 0x1E: _Cmd = DynOS_Level_CmdFreeLevelPool(_Stack, _Cmd); break;
|
||||
case 0x1F: _Cmd = DynOS_Level_CmdBeginArea(_Stack, _Cmd); break;
|
||||
case 0x20: _Cmd = DynOS_Level_CmdEndArea(_Stack, _Cmd); break;
|
||||
case 0x21: _Cmd = DynOS_Level_CmdLoadModelFromDL(_Stack, _Cmd); break;
|
||||
case 0x22: _Cmd = DynOS_Level_CmdLoadModelFromGeo(_Stack, _Cmd); break;
|
||||
case 0x23: _Cmd = DynOS_Level_Cmd23(_Stack, _Cmd); break;
|
||||
case 0x24: _Cmd = DynOS_Level_CmdObject(_Stack, _Cmd); break;
|
||||
case 0x25: _Cmd = DynOS_Level_CmdMario(_Stack, _Cmd); break;
|
||||
case 0x26: _Cmd = DynOS_Level_CmdWarpNode(_Stack, _Cmd); break;
|
||||
case 0x27: _Cmd = DynOS_Level_CmdPaintingWarpNode(_Stack, _Cmd); break;
|
||||
case 0x28: _Cmd = DynOS_Level_CmdInstantWarp(_Stack, _Cmd); break;
|
||||
case 0x29: _Cmd = DynOS_Level_CmdLoadArea(_Stack, _Cmd); break;
|
||||
case 0x2A: _Cmd = DynOS_Level_CmdUnloadArea(_Stack, _Cmd); break;
|
||||
case 0x2B: _Cmd = DynOS_Level_CmdSetMarioStartPos(_Stack, _Cmd); break;
|
||||
case 0x2C: _Cmd = DynOS_Level_Cmd2C(_Stack, _Cmd); break;
|
||||
case 0x2D: _Cmd = DynOS_Level_Cmd2D(_Stack, _Cmd); break;
|
||||
case 0x2E: _Cmd = DynOS_Level_CmdSetTerrain(_Stack, _Cmd); break;
|
||||
case 0x2F: _Cmd = DynOS_Level_CmdSetRooms(_Stack, _Cmd); break;
|
||||
case 0x30: _Cmd = DynOS_Level_CmdShowDialog(_Stack, _Cmd); break;
|
||||
case 0x31: _Cmd = DynOS_Level_CmdSetTerrainType(_Stack, _Cmd); break;
|
||||
case 0x32: _Cmd = DynOS_Level_CmdNop(_Stack, _Cmd); break;
|
||||
case 0x33: _Cmd = DynOS_Level_CmdSetTransition(_Stack, _Cmd); break;
|
||||
case 0x34: _Cmd = DynOS_Level_CmdSetBlackout(_Stack, _Cmd); break;
|
||||
case 0x35: _Cmd = DynOS_Level_CmdSetGamma(_Stack, _Cmd); break;
|
||||
case 0x36: _Cmd = DynOS_Level_CmdSetBackgroundMusic(_Stack, _Cmd); break;
|
||||
case 0x37: _Cmd = DynOS_Level_CmdSetMenuMusic(_Stack, _Cmd); break;
|
||||
case 0x38: _Cmd = DynOS_Level_CmdStopMusic(_Stack, _Cmd); break;
|
||||
case 0x39: _Cmd = DynOS_Level_CmdMacroObjects(_Stack, _Cmd); break;
|
||||
case 0x3A: _Cmd = DynOS_Level_Cmd3A(_Stack, _Cmd); break;
|
||||
case 0x3B: _Cmd = DynOS_Level_CmdSetWhirlpool(_Stack, _Cmd); break;
|
||||
case 0x3C: _Cmd = DynOS_Level_CmdGetOrSet(_Stack, _Cmd); break;
|
||||
case 0x3D: _Cmd = DynOS_Level_CmdAdvanceDemo(_Stack, _Cmd); break;
|
||||
case 0x3E: _Cmd = DynOS_Level_CmdClearDemoPointer(_Stack, _Cmd); break;
|
||||
case 0x3F: _Cmd = DynOS_Level_CmdJumpArea(_Stack, _Cmd, aPreprocessFunction); break;
|
||||
} break;
|
||||
|
||||
case 1:
|
||||
_Cmd = (LvlCmd *) DynOS_Level_CmdNext(_Cmd, _Cmd->mSize);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
_Cmd = DynOS_Level_CmdReturn(_Stack, _Cmd);
|
||||
break;
|
||||
|
||||
case 3:
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Level Script Utilities
|
||||
//
|
||||
|
||||
s16 *DynOS_Level_GetWarp(s32 aLevel, s32 aArea, u8 aWarpId) {
|
||||
DynOS_Level_Init();
|
||||
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();
|
||||
if (aLevel == LEVEL_TTM && aArea > 2) return NULL;
|
||||
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;
|
||||
}
|
78
data/dynos_main.cpp
Normal file
78
data/dynos_main.cpp
Normal file
|
@ -0,0 +1,78 @@
|
|||
#include "dynos.cpp.h"
|
||||
extern "C" {
|
||||
#include "sm64.h"
|
||||
#include "level_commands.h"
|
||||
#include "game/level_update.h"
|
||||
#ifndef COOP
|
||||
#include "game/options_menu.h"
|
||||
#endif
|
||||
#include "game/object_list_processor.h"
|
||||
extern s16 gMenuMode;
|
||||
extern s8 gDialogBoxState;
|
||||
#ifdef OMM_DEFINES_H
|
||||
extern void omm_opt_init();
|
||||
#endif
|
||||
}
|
||||
|
||||
//
|
||||
// Main Menu
|
||||
//
|
||||
|
||||
void DynOS_ReturnToMainMenu() {
|
||||
#ifndef COOP
|
||||
optmenu_toggle();
|
||||
#endif
|
||||
level_set_transition(0, NULL);
|
||||
gDialogBoxState = 0;
|
||||
gMenuMode = -1;
|
||||
fade_into_special_warp(-2, 0);
|
||||
}
|
||||
|
||||
//
|
||||
// Init
|
||||
//
|
||||
|
||||
DYNOS_AT_STARTUP void DynOS_Init() {
|
||||
|
||||
#ifdef COOP
|
||||
Array<String> _Packs = DynOS_Gfx_Init();
|
||||
if (_Packs.Count() == 0) {
|
||||
return;
|
||||
}
|
||||
#else
|
||||
#ifdef OMM_DEFINES_H
|
||||
omm_opt_init();
|
||||
#endif
|
||||
DynOS_Opt_Init();
|
||||
#endif
|
||||
}
|
||||
|
||||
//
|
||||
// Update
|
||||
//
|
||||
|
||||
static bool sDynosIsLevelEntry = false;
|
||||
void DynOS_UpdateOpt(void *aPad) {
|
||||
if (sDynosIsLevelEntry) {
|
||||
DynOS_Warp_SetParam(gCurrLevelNum, -1);
|
||||
sDynosIsLevelEntry = false;
|
||||
}
|
||||
#ifndef COOP
|
||||
DynOS_Opt_Update((OSContPad *) aPad);
|
||||
#endif
|
||||
gPrevFrameObjectCount = 0;
|
||||
}
|
||||
|
||||
void *DynOS_UpdateCmd(void *aCmd) {
|
||||
static const uintptr_t sCmdLevelEntry[] = { CALL(0, lvl_init_or_update) };
|
||||
sDynosIsLevelEntry |= (memcmp(aCmd, sCmdLevelEntry, sizeof(sCmdLevelEntry)) == 0);
|
||||
return DynOS_Warp_Update(aCmd, sDynosIsLevelEntry);
|
||||
}
|
||||
|
||||
void DynOS_UpdateGfx() {
|
||||
DynOS_Gfx_Update();
|
||||
}
|
||||
|
||||
bool DynOS_IsTransitionActive() {
|
||||
return gWarpTransition.isActive;
|
||||
}
|
502
data/dynos_misc.cpp
Normal file
502
data/dynos_misc.cpp
Normal file
|
@ -0,0 +1,502 @@
|
|||
#include "dynos.cpp.h"
|
||||
extern "C" {
|
||||
#include "object_fields.h"
|
||||
#include "game/object_helpers.h"
|
||||
#include "game/segment2.h"
|
||||
#include "game/level_geo.h"
|
||||
#include "game/level_update.h"
|
||||
#include "game/moving_texture.h"
|
||||
#include "game/paintings.h"
|
||||
#include "game/geo_misc.h"
|
||||
#include "game/mario_misc.h"
|
||||
#include "game/mario_actions_cutscene.h"
|
||||
#include "game/screen_transition.h"
|
||||
#include "game/object_list_processor.h"
|
||||
#include "game/behavior_actions.h"
|
||||
#include "game/rendering_graph_node.h"
|
||||
#include "actors/common0.h"
|
||||
#include "actors/common1.h"
|
||||
#include "actors/group0.h"
|
||||
#include "actors/group1.h"
|
||||
#include "actors/group2.h"
|
||||
#include "actors/group3.h"
|
||||
#include "actors/group4.h"
|
||||
#include "actors/group5.h"
|
||||
#include "actors/group6.h"
|
||||
#include "actors/group7.h"
|
||||
#include "actors/group8.h"
|
||||
#include "actors/group9.h"
|
||||
#include "actors/group10.h"
|
||||
#include "actors/group11.h"
|
||||
#include "actors/group12.h"
|
||||
#include "actors/group13.h"
|
||||
#include "actors/group14.h"
|
||||
#include "actors/group15.h"
|
||||
#include "actors/group16.h"
|
||||
#include "actors/group17.h"
|
||||
#ifdef COOP
|
||||
#include "actors/custom0.h"
|
||||
#include "actors/zcustom0.h"
|
||||
#endif
|
||||
}
|
||||
|
||||
//
|
||||
// String
|
||||
//
|
||||
|
||||
static const struct { const char *mStr; u8 mChar64; s32 mWidth; } sSm64CharMap[] = {
|
||||
{ "0", 0x00, 7 }, { "1", 0x01, 7 }, { "2", 0x02, 7 }, { "3", 0x03, 7 }, { "4", 0x04, 7 }, { "5", 0x05, 7 },
|
||||
{ "6", 0x06, 7 }, { "7", 0x07, 7 }, { "8", 0x08, 7 }, { "9", 0x09, 7 }, { "A", 0x0A, 6 }, { "B", 0x0B, 6 },
|
||||
{ "C", 0x0C, 6 }, { "D", 0x0D, 6 }, { "E", 0x0E, 6 }, { "F", 0x0F, 6 }, { "G", 0x10, 6 }, { "H", 0x11, 6 },
|
||||
{ "I", 0x12, 5 }, { "J", 0x13, 6 }, { "K", 0x14, 6 }, { "L", 0x15, 5 }, { "M", 0x16, 8 }, { "N", 0x17, 8 },
|
||||
{ "O", 0x18, 6 }, { "P", 0x19, 6 }, { "Q", 0x1A, 6 }, { "R", 0x1B, 6 }, { "S", 0x1C, 6 }, { "T", 0x1D, 5 },
|
||||
{ "U", 0x1E, 6 }, { "V", 0x1F, 6 }, { "W", 0x20, 8 }, { "X", 0x21, 7 }, { "Y", 0x22, 6 }, { "Z", 0x23, 6 },
|
||||
{ "a", 0x24, 6 }, { "b", 0x25, 5 }, { "c", 0x26, 5 }, { "d", 0x27, 6 }, { "e", 0x28, 5 }, { "f", 0x29, 5 },
|
||||
{ "g", 0x2A, 6 }, { "h", 0x2B, 5 }, { "i", 0x2C, 4 }, { "j", 0x2D, 5 }, { "k", 0x2E, 5 }, { "l", 0x2F, 3 },
|
||||
{ "m", 0x30, 7 }, { "n", 0x31, 5 }, { "o", 0x32, 5 }, { "p", 0x33, 5 }, { "q", 0x34, 6 }, { "r", 0x35, 5 },
|
||||
{ "s", 0x36, 5 }, { "t", 0x37, 5 }, { "u", 0x38, 5 }, { "v", 0x39, 5 }, { "w", 0x3A, 7 }, { "x", 0x3B, 7 },
|
||||
{ "y", 0x3C, 5 }, { "z", 0x3D, 5 }, { "\'", 0x3E, 4 }, { ".", 0x3F, 4 }, { "^", 0x50, 8 }, { "|", 0x51, 8 },
|
||||
{ "<", 0x52, 8 }, { ">", 0x53, 8 }, { "[A]", 0x54, 7 }, { "[B]", 0x55, 7 }, { "[C]", 0x56, 6 }, { "[Z]", 0x57, 7 },
|
||||
{ "[R]", 0x58, 7 }, { ",", 0x6F, 4 }, { " ", 0x9E, 5 }, { "-", 0x9F, 6 }, { "/", 0xD0, 10 }, { "[%]", 0xE0, 7 },
|
||||
{ "(", 0xE1, 5 }, { ")(", 0xE2, 10 }, { ")", 0xE3, 5 }, { "+", 0xE4, 9 }, { "&", 0xE5, 8 }, { ":", 0xE6, 4 },
|
||||
{ "!", 0xF2, 5 }, { "%", 0xF3, 7 }, { "?", 0xF4, 7 }, { "~", 0xF7, 8 }, { "$", 0xF9, 8 }, { "@", 0xFA, 10 },
|
||||
{ "*", 0xFB, 6 }, { "=", 0xFD, 10 }, { "\n", 0xFE, 0 },
|
||||
};
|
||||
|
||||
static const char *DynOS_String_AddChar64(u8 *aStr64, const char *pStr, s32 &aIndex) {
|
||||
for (const auto &c : sSm64CharMap) {
|
||||
if (strstr(pStr, c.mStr) == pStr) {
|
||||
aStr64[aIndex++] = c.mChar64;
|
||||
return pStr + strlen(c.mStr);
|
||||
}
|
||||
}
|
||||
|
||||
// Put a space by default
|
||||
aStr64[aIndex++] = 0x9E;
|
||||
return pStr + 1;
|
||||
}
|
||||
|
||||
u8 *DynOS_String_Convert(const char *aString, bool aHeapAlloc) {
|
||||
|
||||
// Allocation
|
||||
static u8 sStringBuffer[8][2048];
|
||||
static u32 sStringBufferIndex = 0;
|
||||
u8 *_Str64;
|
||||
if (aHeapAlloc) {
|
||||
_Str64 = New<u8>(2048);
|
||||
} else {
|
||||
_Str64 = sStringBuffer[sStringBufferIndex];
|
||||
sStringBufferIndex = (sStringBufferIndex + 1) % 8;
|
||||
}
|
||||
|
||||
// Conversion
|
||||
memset(_Str64, 0xFF, 2048);
|
||||
const char *pStr = aString;
|
||||
for (s32 i = 0; *pStr != 0 && i < 2047;) {
|
||||
pStr = DynOS_String_AddChar64(_Str64, pStr, i);
|
||||
}
|
||||
return _Str64;
|
||||
}
|
||||
|
||||
u8 *DynOS_String_Decapitalize(u8 *aStr64) {
|
||||
bool _WasSpace = true;
|
||||
for (u8 *pStr64 = aStr64; *pStr64 != 0xFF; pStr64++) {
|
||||
if (*pStr64 >= 10 && *pStr64 <= 35) {
|
||||
if (_WasSpace) _WasSpace = false;
|
||||
else *pStr64 += 26;
|
||||
} else if (*pStr64 >= 63) {
|
||||
_WasSpace = true;
|
||||
}
|
||||
}
|
||||
return aStr64;
|
||||
}
|
||||
|
||||
s32 DynOS_String_Length(const u8 *aStr64) {
|
||||
s32 _Length = 0;
|
||||
for (; aStr64 && *aStr64 != 255; aStr64++, _Length++);
|
||||
return _Length;
|
||||
}
|
||||
|
||||
s32 DynOS_String_WidthChar64(u8 aChar64) {
|
||||
for (const auto &c : sSm64CharMap) {
|
||||
if (c.mChar64 == aChar64) {
|
||||
return c.mWidth;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
s32 DynOS_String_Width(const u8 *aStr64) {
|
||||
s32 _Width = 0;
|
||||
for (; *aStr64 != 0xFF; aStr64++) {
|
||||
_Width += DynOS_String_WidthChar64(*aStr64);
|
||||
}
|
||||
return _Width;
|
||||
}
|
||||
|
||||
//
|
||||
// Geo
|
||||
//
|
||||
|
||||
static void *geo_rotate_3d_coin(s32 callContext, void *node, UNUSED void *c) {
|
||||
if (callContext == GEO_CONTEXT_RENDER) {
|
||||
struct Object *obj = (struct Object *) gCurGraphNodeObject;
|
||||
struct GraphNodeRotation *rotNode = (struct GraphNodeRotation *) ((struct GraphNode *) node)->next;
|
||||
rotNode->rotation[0] = 0;
|
||||
rotNode->rotation[1] = obj->oAnimState;
|
||||
rotNode->rotation[2] = 0;
|
||||
obj->oAnimState += 0x0800;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//
|
||||
// Actors
|
||||
//
|
||||
|
||||
// &__Actors()
|
||||
#define define_actor(geo) (const void *) #geo, (const void *) geo
|
||||
static const void *sDynosActors[] = {
|
||||
define_actor(amp_geo),
|
||||
define_actor(birds_geo),
|
||||
define_actor(blargg_geo),
|
||||
define_actor(blue_coin_switch_geo),
|
||||
define_actor(black_bobomb_geo),
|
||||
define_actor(bobomb_buddy_geo),
|
||||
define_actor(boo_geo),
|
||||
define_actor(boo_castle_geo),
|
||||
define_actor(bookend_geo),
|
||||
define_actor(bookend_part_geo),
|
||||
define_actor(bowling_ball_geo),
|
||||
define_actor(bowling_ball_track_geo),
|
||||
define_actor(bowser_geo),
|
||||
define_actor(bowser2_geo),
|
||||
define_actor(bowser_bomb_geo),
|
||||
define_actor(bowser_flames_geo),
|
||||
define_actor(bowser_impact_smoke_geo),
|
||||
define_actor(bowser_1_yellow_sphere_geo),
|
||||
define_actor(invisible_bowser_accessory_geo),
|
||||
define_actor(bowser_key_geo),
|
||||
define_actor(bowser_key_cutscene_geo),
|
||||
define_actor(breakable_box_geo),
|
||||
define_actor(breakable_box_small_geo),
|
||||
define_actor(bub_geo),
|
||||
define_actor(bubba_geo),
|
||||
define_actor(bubble_geo),
|
||||
define_actor(bullet_bill_geo),
|
||||
define_actor(bully_geo),
|
||||
define_actor(bully_boss_geo),
|
||||
define_actor(burn_smoke_geo),
|
||||
define_actor(butterfly_geo),
|
||||
define_actor(cannon_barrel_geo),
|
||||
define_actor(cannon_base_geo),
|
||||
define_actor(cap_switch_geo),
|
||||
define_actor(cartoon_star_geo),
|
||||
define_actor(chain_chomp_geo),
|
||||
define_actor(checkerboard_platform_geo),
|
||||
define_actor(chilly_chief_geo),
|
||||
define_actor(chilly_chief_big_geo),
|
||||
define_actor(chuckya_geo),
|
||||
define_actor(clam_shell_geo),
|
||||
define_actor(yellow_coin_geo),
|
||||
define_actor(yellow_coin_no_shadow_geo),
|
||||
define_actor(blue_coin_geo),
|
||||
define_actor(blue_coin_no_shadow_geo),
|
||||
define_actor(red_coin_geo),
|
||||
define_actor(red_coin_no_shadow_geo),
|
||||
define_actor(dirt_animation_geo),
|
||||
define_actor(dorrie_geo),
|
||||
define_actor(cabin_door_geo),
|
||||
define_actor(castle_door_geo),
|
||||
define_actor(castle_door_0_star_geo),
|
||||
define_actor(castle_door_1_star_geo),
|
||||
define_actor(castle_door_3_stars_geo),
|
||||
define_actor(haunted_door_geo),
|
||||
define_actor(hazy_maze_door_geo),
|
||||
define_actor(metal_door_geo),
|
||||
define_actor(key_door_geo),
|
||||
define_actor(wooden_door_geo),
|
||||
define_actor(enemy_lakitu_geo),
|
||||
define_actor(exclamation_box_geo),
|
||||
define_actor(exclamation_box_outline_geo),
|
||||
define_actor(explosion_geo),
|
||||
define_actor(eyerok_left_hand_geo),
|
||||
define_actor(eyerok_right_hand_geo),
|
||||
define_actor(fish_geo),
|
||||
define_actor(cyan_fish_geo),
|
||||
define_actor(flyguy_geo),
|
||||
define_actor(red_flame_geo),
|
||||
define_actor(red_flame_shadow_geo),
|
||||
define_actor(blue_flame_geo),
|
||||
define_actor(fwoosh_geo),
|
||||
define_actor(goomba_geo),
|
||||
define_actor(haunted_cage_geo),
|
||||
define_actor(haunted_chair_geo),
|
||||
define_actor(heart_geo),
|
||||
define_actor(heave_ho_geo),
|
||||
define_actor(hoot_geo),
|
||||
define_actor(king_bobomb_geo),
|
||||
define_actor(klepto_geo),
|
||||
define_actor(koopa_with_shell_geo),
|
||||
define_actor(koopa_without_shell_geo),
|
||||
define_actor(koopa_flag_geo),
|
||||
define_actor(koopa_shell_geo),
|
||||
define_actor(lakitu_geo),
|
||||
define_actor(mad_piano_geo),
|
||||
define_actor(manta_seg5_geo_05008D14),
|
||||
define_actor(mario_geo),
|
||||
define_actor(marios_cap_geo),
|
||||
define_actor(marios_metal_cap_geo),
|
||||
define_actor(marios_wing_cap_geo),
|
||||
define_actor(marios_winged_metal_cap_geo),
|
||||
define_actor(metal_box_geo),
|
||||
define_actor(metallic_ball_geo),
|
||||
define_actor(mips_geo),
|
||||
define_actor(mist_geo),
|
||||
define_actor(moneybag_geo),
|
||||
define_actor(monty_mole_geo),
|
||||
define_actor(mr_blizzard_geo),
|
||||
define_actor(mr_blizzard_hidden_geo),
|
||||
define_actor(mr_i_geo),
|
||||
define_actor(mr_i_iris_geo),
|
||||
define_actor(mushroom_1up_geo),
|
||||
define_actor(number_geo),
|
||||
define_actor(peach_geo),
|
||||
define_actor(penguin_geo),
|
||||
define_actor(piranha_plant_geo),
|
||||
define_actor(pokey_head_geo),
|
||||
define_actor(pokey_body_part_geo),
|
||||
define_actor(purple_marble_geo),
|
||||
define_actor(purple_switch_geo),
|
||||
define_actor(scuttlebug_geo),
|
||||
define_actor(seaweed_geo),
|
||||
define_actor(skeeter_geo),
|
||||
define_actor(small_key_geo),
|
||||
define_actor(small_water_splash_geo),
|
||||
define_actor(smoke_geo),
|
||||
define_actor(snufit_geo),
|
||||
define_actor(sparkles_geo),
|
||||
define_actor(sparkles_animation_geo),
|
||||
define_actor(spindrift_geo),
|
||||
define_actor(spiny_geo),
|
||||
define_actor(spiny_ball_geo),
|
||||
define_actor(star_geo),
|
||||
define_actor(transparent_star_geo),
|
||||
define_actor(sushi_geo),
|
||||
define_actor(swoop_geo),
|
||||
define_actor(thwomp_geo),
|
||||
define_actor(toad_geo),
|
||||
define_actor(treasure_chest_base_geo),
|
||||
define_actor(treasure_chest_lid_geo),
|
||||
define_actor(bubbly_tree_geo),
|
||||
define_actor(spiky_tree_geo),
|
||||
define_actor(snow_tree_geo),
|
||||
define_actor(palm_tree_geo),
|
||||
define_actor(leaves_geo),
|
||||
define_actor(tweester_geo),
|
||||
define_actor(ukiki_geo),
|
||||
define_actor(unagi_geo),
|
||||
define_actor(warp_pipe_geo),
|
||||
define_actor(water_bomb_geo),
|
||||
define_actor(water_bomb_shadow_geo),
|
||||
define_actor(water_ring_geo),
|
||||
define_actor(water_splash_geo),
|
||||
define_actor(idle_water_wave_geo),
|
||||
define_actor(wave_trail_geo),
|
||||
define_actor(white_particle_geo),
|
||||
define_actor(white_puff_geo),
|
||||
define_actor(whomp_geo),
|
||||
define_actor(wiggler_head_geo),
|
||||
define_actor(wiggler_body_geo),
|
||||
define_actor(wooden_post_geo),
|
||||
define_actor(wooden_signpost_geo),
|
||||
define_actor(yellow_sphere_geo),
|
||||
define_actor(yoshi_geo),
|
||||
define_actor(yoshi_egg_geo),
|
||||
#ifdef COOP
|
||||
define_actor(luigi_geo),
|
||||
define_actor(luigis_cap_geo),
|
||||
define_actor(luigis_metal_cap_geo),
|
||||
define_actor(luigis_wing_cap_geo),
|
||||
define_actor(luigis_winged_metal_cap_geo),
|
||||
define_actor(toad_player_geo),
|
||||
define_actor(toads_cap_geo),
|
||||
define_actor(toads_metal_cap_geo),
|
||||
define_actor(toads_wing_cap_geo),
|
||||
define_actor(waluigi_geo),
|
||||
define_actor(waluigis_cap_geo),
|
||||
define_actor(waluigis_metal_cap_geo),
|
||||
define_actor(waluigis_wing_cap_geo),
|
||||
define_actor(waluigis_winged_metal_cap_geo),
|
||||
define_actor(wario_geo),
|
||||
define_actor(warios_cap_geo),
|
||||
define_actor(warios_metal_cap_geo),
|
||||
define_actor(warios_wing_cap_geo),
|
||||
define_actor(warios_winged_metal_cap_geo),
|
||||
#endif
|
||||
};
|
||||
|
||||
s32 DynOS_Geo_GetActorCount() {
|
||||
return (s32) (sizeof(sDynosActors) / (2 * sizeof(sDynosActors[0])));
|
||||
}
|
||||
|
||||
const char *DynOS_Geo_GetActorName(s32 aIndex) {
|
||||
return (const char *) sDynosActors[2 * aIndex];
|
||||
}
|
||||
|
||||
const void *DynOS_Geo_GetActorLayout(s32 aIndex) {
|
||||
return (const void *) sDynosActors[2 * aIndex + 1];
|
||||
}
|
||||
|
||||
s32 DynOS_Geo_GetActorIndex(const void *aGeoLayout) {
|
||||
for (s32 i = 0; i != DynOS_Geo_GetActorCount(); ++i) {
|
||||
if (sDynosActors[2 * i + 1] == aGeoLayout) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
//
|
||||
// Geo Functions
|
||||
//
|
||||
|
||||
static const Array<Pair<const char *, void *>> &__GeoFunctions() {
|
||||
#define define_geo_function(name) { #name, (void *) name }
|
||||
static const Array<Pair<const char *, void *>> sGeoFunctions = {
|
||||
define_geo_function(geo_mirror_mario_set_alpha),
|
||||
define_geo_function(geo_switch_mario_stand_run),
|
||||
define_geo_function(geo_switch_mario_eyes),
|
||||
define_geo_function(geo_mario_tilt_torso),
|
||||
define_geo_function(geo_mario_head_rotation),
|
||||
define_geo_function(geo_switch_mario_hand),
|
||||
define_geo_function(geo_mario_hand_foot_scaler),
|
||||
define_geo_function(geo_switch_mario_cap_effect),
|
||||
define_geo_function(geo_switch_mario_cap_on_off),
|
||||
define_geo_function(geo_mario_rotate_wing_cap_wings),
|
||||
define_geo_function(geo_switch_mario_hand_grab_pos),
|
||||
define_geo_function(geo_render_mirror_mario),
|
||||
define_geo_function(geo_mirror_mario_backface_culling),
|
||||
define_geo_function(geo_update_projectile_pos_from_parent),
|
||||
define_geo_function(geo_update_layer_transparency),
|
||||
define_geo_function(geo_switch_anim_state),
|
||||
define_geo_function(geo_switch_area),
|
||||
define_geo_function(geo_camera_main),
|
||||
define_geo_function(geo_camera_fov),
|
||||
define_geo_function(geo_envfx_main),
|
||||
define_geo_function(geo_skybox_main),
|
||||
define_geo_function(geo_wdw_set_initial_water_level),
|
||||
define_geo_function(geo_movtex_pause_control),
|
||||
define_geo_function(geo_movtex_draw_water_regions),
|
||||
define_geo_function(geo_movtex_draw_nocolor),
|
||||
define_geo_function(geo_movtex_draw_colored),
|
||||
define_geo_function(geo_movtex_draw_colored_no_update),
|
||||
define_geo_function(geo_movtex_draw_colored_2_no_update),
|
||||
define_geo_function(geo_movtex_update_horizontal),
|
||||
define_geo_function(geo_movtex_draw_colored_no_update),
|
||||
define_geo_function(geo_painting_draw),
|
||||
define_geo_function(geo_painting_update),
|
||||
define_geo_function(geo_exec_inside_castle_light),
|
||||
define_geo_function(geo_exec_flying_carpet_timer_update),
|
||||
define_geo_function(geo_exec_flying_carpet_create),
|
||||
define_geo_function(geo_exec_cake_end_screen),
|
||||
define_geo_function(geo_cannon_circle_base),
|
||||
define_geo_function(geo_move_mario_part_from_parent),
|
||||
define_geo_function(geo_bits_bowser_coloring),
|
||||
define_geo_function(geo_update_body_rot_from_parent),
|
||||
define_geo_function(geo_switch_bowser_eyes),
|
||||
define_geo_function(geo_switch_tuxie_mother_eyes),
|
||||
define_geo_function(geo_update_held_mario_pos),
|
||||
define_geo_function(geo_snufit_move_mask),
|
||||
define_geo_function(geo_snufit_scale_body),
|
||||
define_geo_function(geo_scale_bowser_key),
|
||||
{ "geo_rotate_coin", (void *) geo_rotate_3d_coin },
|
||||
define_geo_function(geo_offset_klepto_held_object),
|
||||
define_geo_function(geo_switch_peach_eyes),
|
||||
#ifdef COOP
|
||||
define_geo_function(geo_mario_set_player_colors),
|
||||
#endif
|
||||
};
|
||||
#undef define_geo_function
|
||||
return sGeoFunctions;
|
||||
}
|
||||
#define sGeoFunctions __GeoFunctions()
|
||||
|
||||
void *DynOS_Geo_GetFunctionPointerFromName(const String &aName) {
|
||||
for (const auto &_GeoFunction : sGeoFunctions) {
|
||||
if (aName == _GeoFunction.first) {
|
||||
return _GeoFunction.second;
|
||||
}
|
||||
};
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *DynOS_Geo_GetFunctionPointerFromIndex(s32 aIndex) {
|
||||
return sGeoFunctions[aIndex].second;
|
||||
}
|
||||
|
||||
s32 DynOS_Geo_GetFunctionIndex(const void *aPtr) {
|
||||
for (const auto &_GeoFunction : sGeoFunctions) {
|
||||
if (_GeoFunction.second == aPtr) {
|
||||
return (s32) (&_GeoFunction - sGeoFunctions.begin());
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void _RelocateGraphNodePointers(struct GraphNode *aHead, u64 aOffset) {
|
||||
struct GraphNode *_Node = aHead;
|
||||
do {
|
||||
if (_Node->prev) {
|
||||
_Node->prev = (struct GraphNode *) ((u64) _Node->prev + aOffset);
|
||||
}
|
||||
if (_Node->next) {
|
||||
_Node->next = (struct GraphNode *) ((u64) _Node->next + aOffset);
|
||||
}
|
||||
if (_Node->parent) {
|
||||
_Node->parent = (struct GraphNode *) ((u64) _Node->parent + aOffset);
|
||||
}
|
||||
if (_Node->children) {
|
||||
_Node->children = (struct GraphNode *) ((u64) _Node->children + aOffset);
|
||||
_RelocateGraphNodePointers(_Node->children, aOffset);
|
||||
}
|
||||
_Node = _Node->next;
|
||||
} while (_Node != aHead);
|
||||
}
|
||||
|
||||
void *DynOS_Geo_GetGraphNode(const void *aGeoLayout, bool aKeepInMemory) {
|
||||
static Array<Pair<void *, void *>> sLoadedGraphNodes;
|
||||
if (aKeepInMemory) {
|
||||
s32 _LoadedGraphNodeIndex = sLoadedGraphNodes.FindIf([&aGeoLayout](const Pair<void *, void *> &aLoadedGraphNode) { return aLoadedGraphNode.first == aGeoLayout; });
|
||||
if (_LoadedGraphNodeIndex != -1) {
|
||||
return sLoadedGraphNodes[_LoadedGraphNodeIndex].second;
|
||||
}
|
||||
}
|
||||
|
||||
// Process the geo layout on a large pool of memory (16 MB)
|
||||
struct AllocOnlyPool *_Pool = (struct AllocOnlyPool *) calloc(1, 0x1000000);
|
||||
_Pool->totalSpace = 0x1000000 - sizeof(struct AllocOnlyPool);
|
||||
_Pool->usedSpace = 0;
|
||||
_Pool->startPtr = (u8 *) _Pool + sizeof(struct AllocOnlyPool);
|
||||
_Pool->freePtr = (u8 *) _Pool + sizeof(struct AllocOnlyPool);
|
||||
void *_Processed = process_geo_layout(_Pool, (void *) aGeoLayout);
|
||||
|
||||
// Copy the graph node data to the minimum amount of memory needed
|
||||
if (_Processed && _Pool->usedSpace != 0) {
|
||||
struct GraphNode *_Node = (struct GraphNode *) calloc(1, _Pool->usedSpace);
|
||||
memcpy(_Node, _Pool->startPtr, _Pool->usedSpace);
|
||||
|
||||
// Relocate all graph pointers
|
||||
u64 _Offset = (u64) _Node - (u64) _Pool->startPtr;
|
||||
_RelocateGraphNodePointers(_Node, _Offset);
|
||||
|
||||
// Add it to loaded graph nodes
|
||||
if (aKeepInMemory) {
|
||||
sLoadedGraphNodes.Add({ (void *) aGeoLayout, (void *) _Node });
|
||||
}
|
||||
free(_Pool);
|
||||
return _Node;
|
||||
}
|
||||
free(_Pool);
|
||||
return NULL;
|
||||
}
|
485
data/dynos_warps.cpp
Normal file
485
data/dynos_warps.cpp
Normal file
|
@ -0,0 +1,485 @@
|
|||
#include "dynos.cpp.h"
|
||||
extern "C" {
|
||||
#include "sm64.h"
|
||||
#include "seq_ids.h"
|
||||
#include "course_table.h"
|
||||
#include "audio/external.h"
|
||||
#include "engine/surface_collision.h"
|
||||
#include "game/mario.h"
|
||||
#include "game/ingame_menu.h"
|
||||
#include "game/level_update.h"
|
||||
#include "game/sound_init.h"
|
||||
#include "game/object_list_processor.h"
|
||||
#ifndef COOP
|
||||
#include "game/options_menu.h"
|
||||
#endif
|
||||
extern s8 gDialogBoxState;
|
||||
extern s16 gMenuMode;
|
||||
extern s32 gWdwWaterLevelSet;
|
||||
extern u8 sSpawnTypeFromWarpBhv[];
|
||||
extern void set_mario_initial_action(struct MarioState *, u32, u32);
|
||||
extern void set_play_mode(s16);
|
||||
}
|
||||
|
||||
//
|
||||
// Data
|
||||
//
|
||||
|
||||
#ifndef COOP
|
||||
s32 gDDDBowsersSub = -1;
|
||||
s32 gDDDPoles = -1;
|
||||
#endif
|
||||
static s32 sDynosWarpLevelNum = -1;
|
||||
static s32 sDynosWarpAreaNum = -1;
|
||||
static s32 sDynosWarpActNum = -1;
|
||||
static s32 sDynosExitLevelNum = -1;
|
||||
static s32 sDynosExitAreaNum = -1;
|
||||
|
||||
//
|
||||
// Level Entry
|
||||
//
|
||||
|
||||
bool DynOS_Warp_ToLevel(s32 aLevel, s32 aArea, s32 aAct) {
|
||||
if (DynOS_Level_GetCourse(aLevel) == COURSE_NONE || !DynOS_Level_GetWarpEntry(aLevel, aArea)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
sDynosWarpLevelNum = aLevel;
|
||||
sDynosWarpAreaNum = aArea;
|
||||
sDynosWarpActNum = aAct;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DynOS_Warp_RestartLevel() {
|
||||
return DynOS_Warp_ToLevel(gCurrLevelNum, 1, gCurrActNum);
|
||||
}
|
||||
|
||||
//
|
||||
// Level Exit
|
||||
//
|
||||
|
||||
bool DynOS_Warp_ExitLevel(s32 aDelay) {
|
||||
if (DynOS_Level_GetCourse(gCurrLevelNum) == COURSE_NONE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Close the pause menu if it was open
|
||||
#ifndef COOP
|
||||
optmenu_toggle();
|
||||
#endif
|
||||
level_set_transition(0, NULL);
|
||||
gDialogBoxState = 0;
|
||||
gMenuMode = -1;
|
||||
|
||||
// Cancel out every music/sound/sequence
|
||||
for (u16 seqid = 0; seqid != SEQ_COUNT; ++seqid) {
|
||||
stop_background_music(seqid);
|
||||
}
|
||||
play_shell_music();
|
||||
stop_shell_music();
|
||||
stop_cap_music();
|
||||
func_80321080(0);
|
||||
fadeout_music(0);
|
||||
fadeout_level_music(0);
|
||||
|
||||
// Play Mario head transition, and change play mode to avoid getting stuck on the pause menu
|
||||
aDelay = MAX(1, aDelay);
|
||||
gMarioState->invincTimer = -1;
|
||||
play_transition(WARP_TRANSITION_FADE_INTO_MARIO, aDelay, 0x00, 0x00, 0x00);
|
||||
set_play_mode(0);
|
||||
sDynosExitLevelNum = gCurrLevelNum;
|
||||
sDynosExitAreaNum = gCurrAreaIndex;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DynOS_Warp_ToCastle(s32 aLevel) {
|
||||
if (DynOS_Level_GetCourse(aLevel) == COURSE_NONE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Close the pause menu if it was open
|
||||
#ifndef COOP
|
||||
optmenu_toggle();
|
||||
#endif
|
||||
level_set_transition(0, NULL);
|
||||
gDialogBoxState = 0;
|
||||
gMenuMode = -1;
|
||||
|
||||
// Cancel out every music/sound/sequence
|
||||
for (u16 seqid = 0; seqid != SEQ_COUNT; ++seqid) {
|
||||
stop_background_music(seqid);
|
||||
}
|
||||
play_shell_music();
|
||||
stop_shell_music();
|
||||
stop_cap_music();
|
||||
func_80321080(0);
|
||||
fadeout_music(0);
|
||||
fadeout_level_music(0);
|
||||
|
||||
// Change play mode to avoid getting stuck on the pause menu
|
||||
set_play_mode(0);
|
||||
sDynosExitLevelNum = aLevel;
|
||||
sDynosExitAreaNum = 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
//
|
||||
// Params
|
||||
//
|
||||
|
||||
const char *DynOS_Warp_GetParamName(s32 aLevel, s32 aIndex) {
|
||||
static const char *sLevelParams[][5] = {
|
||||
{ "", "", "", "", "" },
|
||||
{ "None", "No Submarine, No Poles", "Submarine Only", "Poles Only", "Submarine And Poles" },
|
||||
{ "None", "Water Level: Lowest", "Water Level: Low", "Water Level: High", "Water Level: Highest" },
|
||||
{ "None", "Top Flooded", "Top Drained", "Top Flooded", "Top Drained" },
|
||||
{ "None", "Clock Speed: Stopped", "Clock Speed: Slow", "Clock Speed: Fast", "Clock Speed: Random" },
|
||||
};
|
||||
switch (aLevel) {
|
||||
case LEVEL_DDD: return sLevelParams[1][MIN(4, aIndex)];
|
||||
case LEVEL_WDW: return sLevelParams[2][MIN(4, aIndex)];
|
||||
case LEVEL_THI: return sLevelParams[3][MIN(4, aIndex)];
|
||||
case LEVEL_TTC: return sLevelParams[4][MIN(4, aIndex)];
|
||||
}
|
||||
return sLevelParams[0][MIN(4, aIndex)];
|
||||
}
|
||||
|
||||
// Called thrice
|
||||
// Pass -1 to use the previous value (only once)
|
||||
void DynOS_Warp_SetParam(s32 aLevel, s32 aIndex) {
|
||||
static s32 sDynosWarpPrevParamIndex = -1;
|
||||
if (aIndex == -1) {
|
||||
aIndex = sDynosWarpPrevParamIndex;
|
||||
sDynosWarpPrevParamIndex = -1;
|
||||
} else {
|
||||
sDynosWarpPrevParamIndex = aIndex;
|
||||
}
|
||||
|
||||
#ifndef COOP
|
||||
switch (aLevel) {
|
||||
case LEVEL_DDD:
|
||||
switch (aIndex) {
|
||||
case 1: gDDDBowsersSub = 0; gDDDPoles = 0; break;
|
||||
case 2: gDDDBowsersSub = 1; gDDDPoles = 0; break;
|
||||
case 3: gDDDBowsersSub = 0; gDDDPoles = 1; break;
|
||||
case 4: gDDDBowsersSub = 1; gDDDPoles = 1; break;
|
||||
}
|
||||
break;
|
||||
|
||||
case LEVEL_WDW:
|
||||
if (gEnvironmentRegions) {
|
||||
switch (aIndex) {
|
||||
case 1: gEnvironmentRegions[6] = *gEnvironmentLevels = 31; gWdwWaterLevelSet = 1; break;
|
||||
case 2: gEnvironmentRegions[6] = *gEnvironmentLevels = 1024; gWdwWaterLevelSet = 1; break;
|
||||
case 3: gEnvironmentRegions[6] = *gEnvironmentLevels = 1792; gWdwWaterLevelSet = 1; break;
|
||||
case 4: gEnvironmentRegions[6] = *gEnvironmentLevels = 2816; gWdwWaterLevelSet = 1; break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case LEVEL_THI:
|
||||
switch (aIndex) {
|
||||
case 1: gTHIWaterDrained = 0; break;
|
||||
case 2: gTHIWaterDrained = 1; break;
|
||||
case 3: gTHIWaterDrained = 0; break;
|
||||
case 4: gTHIWaterDrained = 1; break;
|
||||
}
|
||||
break;
|
||||
|
||||
case LEVEL_TTC:
|
||||
switch (aIndex) {
|
||||
case 1: gTTCSpeedSetting = TTC_SPEED_STOPPED; break;
|
||||
case 2: gTTCSpeedSetting = TTC_SPEED_SLOW; break;
|
||||
case 3: gTTCSpeedSetting = TTC_SPEED_FAST; break;
|
||||
case 4: gTTCSpeedSetting = TTC_SPEED_RANDOM; break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
//
|
||||
// Update
|
||||
//
|
||||
|
||||
static void *DynOS_Warp_UpdateWarp(void *aCmd, bool aIsLevelInitDone) {
|
||||
static s32 sDynosWarpTargetArea = -1;
|
||||
|
||||
// Phase 1 - Clear the previous level and set up the new level
|
||||
if (sDynosWarpTargetArea == -1) {
|
||||
|
||||
// Close the pause menu if it was open
|
||||
#ifndef COOP
|
||||
optmenu_toggle();
|
||||
#endif
|
||||
level_set_transition(0, NULL);
|
||||
gDialogBoxState = 0;
|
||||
gMenuMode = -1;
|
||||
|
||||
// Cancel out every music/sound/sequence
|
||||
for (u16 seqid = 0; seqid != SEQ_COUNT; ++seqid) {
|
||||
stop_background_music(seqid);
|
||||
}
|
||||
play_shell_music();
|
||||
stop_shell_music();
|
||||
stop_cap_music();
|
||||
func_80321080(0);
|
||||
fadeout_music(0);
|
||||
fadeout_level_music(0);
|
||||
|
||||
// Free everything from the current level
|
||||
clear_objects();
|
||||
clear_area_graph_nodes();
|
||||
clear_areas();
|
||||
main_pool_pop_state();
|
||||
|
||||
// Reset Mario's state
|
||||
gMarioState->healCounter = 0;
|
||||
gMarioState->hurtCounter = 0;
|
||||
gMarioState->numCoins = 0;
|
||||
gMarioState->input = 0;
|
||||
gMarioState->controller->buttonPressed = 0;
|
||||
gHudDisplay.coins = 0;
|
||||
|
||||
// Set up new level values
|
||||
gCurrLevelNum = sDynosWarpLevelNum;
|
||||
gCurrCourseNum = DynOS_Level_GetCourse(gCurrLevelNum);
|
||||
gSavedCourseNum = gCurrCourseNum;
|
||||
gCurrActNum = MAX(1, sDynosWarpActNum * (gCurrCourseNum <= COURSE_STAGES_MAX));
|
||||
gDialogCourseActNum = gCurrActNum;
|
||||
gCurrAreaIndex = sDynosWarpAreaNum;
|
||||
#ifdef COOP
|
||||
gCurrActStarNum = sDynosWarpActNum;
|
||||
#else
|
||||
DynOS_Warp_SetParam(gCurrLevelNum, DynOS_Opt_GetValue("dynos_warp_param"));
|
||||
#endif
|
||||
sDynosWarpTargetArea = gCurrAreaIndex;
|
||||
|
||||
// Set up new level script
|
||||
sWarpDest.type = 0;
|
||||
sWarpDest.levelNum = 0;
|
||||
sWarpDest.areaIdx = gCurrAreaIndex;
|
||||
sWarpDest.nodeId = 0;
|
||||
sWarpDest.arg = 0;
|
||||
return (void *) DynOS_Level_GetScript(gCurrLevelNum);
|
||||
|
||||
} else {
|
||||
|
||||
// Phase 2 - Set Mario spawn info after the MARIO_POS command
|
||||
if (*((u8 *) aCmd) == 0x2B) {
|
||||
gMarioSpawnInfo->areaIndex = sDynosWarpTargetArea;
|
||||
gCurrAreaIndex = sDynosWarpTargetArea;
|
||||
}
|
||||
|
||||
// Phase 3 - End level initialization
|
||||
if (aIsLevelInitDone) {
|
||||
|
||||
// Init Mario
|
||||
s16 *_LevelEntryWarp = DynOS_Level_GetWarpEntry(gCurrLevelNum, gCurrAreaIndex);
|
||||
s16 sDynosWarpSpawnType = sSpawnTypeFromWarpBhv[_LevelEntryWarp[2]];
|
||||
gMarioSpawnInfo->startPos[0] = _LevelEntryWarp[3] + (sDynosWarpSpawnType == MARIO_SPAWN_DOOR_WARP) * 300.0f * sins(_LevelEntryWarp[6]);
|
||||
gMarioSpawnInfo->startPos[1] = _LevelEntryWarp[4];
|
||||
gMarioSpawnInfo->startPos[2] = _LevelEntryWarp[5] + (sDynosWarpSpawnType == MARIO_SPAWN_DOOR_WARP) * 300.0f * coss(_LevelEntryWarp[6]);
|
||||
gMarioSpawnInfo->startAngle[0] = 0;
|
||||
gMarioSpawnInfo->startAngle[1] = _LevelEntryWarp[6];
|
||||
gMarioSpawnInfo->startAngle[2] = 0;
|
||||
gMarioSpawnInfo->areaIndex = gCurrAreaIndex;
|
||||
init_mario();
|
||||
set_mario_initial_action(gMarioState, sDynosWarpSpawnType, 0);
|
||||
#ifndef COOP
|
||||
DynOS_Warp_SetParam(gCurrLevelNum, DynOS_Opt_GetValue("dynos_warp_param"));
|
||||
#endif
|
||||
|
||||
// Init transition
|
||||
reset_camera(gCurrentArea->camera);
|
||||
init_camera(gCurrentArea->camera);
|
||||
sDelayedWarpOp = WARP_OP_NONE;
|
||||
switch (sDynosWarpSpawnType) {
|
||||
case MARIO_SPAWN_UNKNOWN_03: play_transition(WARP_TRANSITION_FADE_FROM_STAR, 0x10, 0x00, 0x00, 0x00); break;
|
||||
case MARIO_SPAWN_DOOR_WARP: play_transition(WARP_TRANSITION_FADE_FROM_CIRCLE, 0x10, 0x00, 0x00, 0x00); break;
|
||||
case MARIO_SPAWN_TELEPORT: play_transition(WARP_TRANSITION_FADE_FROM_COLOR, 0x14, 0xFF, 0xFF, 0xFF); break;
|
||||
case MARIO_SPAWN_SPIN_AIRBORNE: play_transition(WARP_TRANSITION_FADE_FROM_COLOR, 0x1A, 0xFF, 0xFF, 0xFF); break;
|
||||
case MARIO_SPAWN_SPIN_AIRBORNE_CIRCLE: play_transition(WARP_TRANSITION_FADE_FROM_CIRCLE, 0x10, 0x00, 0x00, 0x00); break;
|
||||
case MARIO_SPAWN_UNKNOWN_27: play_transition(WARP_TRANSITION_FADE_FROM_COLOR, 0x10, 0x00, 0x00, 0x00); break;
|
||||
default: play_transition(WARP_TRANSITION_FADE_FROM_STAR, 0x10, 0x00, 0x00, 0x00); break;
|
||||
}
|
||||
|
||||
// Set music
|
||||
set_background_music(gCurrentArea->musicParam, gCurrentArea->musicParam2, 0);
|
||||
if (gMarioState->flags & MARIO_METAL_CAP) play_cap_music(SEQUENCE_ARGS(4, SEQ_EVENT_METAL_CAP));
|
||||
if (gMarioState->flags & MARIO_VANISH_CAP) play_cap_music(SEQUENCE_ARGS(4, SEQ_EVENT_POWERUP));
|
||||
if (gMarioState->flags & MARIO_WING_CAP) play_cap_music(SEQUENCE_ARGS(4, SEQ_EVENT_POWERUP));
|
||||
if (gCurrLevelNum == LEVEL_BOWSER_1 ||
|
||||
gCurrLevelNum == LEVEL_BOWSER_2 ||
|
||||
gCurrLevelNum == LEVEL_BOWSER_3) {
|
||||
sound_banks_enable(0, 0xFFFF); // Bowser levels sound fix
|
||||
}
|
||||
|
||||
// Reset values
|
||||
sDynosWarpTargetArea = -1;
|
||||
sDynosWarpLevelNum = -1;
|
||||
sDynosWarpAreaNum = -1;
|
||||
sDynosWarpActNum = -1;
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef COOP
|
||||
// Reset DDD settings to default
|
||||
if (gCurrCourseNum == COURSE_NONE) {
|
||||
gDDDBowsersSub = -1;
|
||||
gDDDPoles = -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void DynOS_Warp_FindExitPosition(s16 &aPosX, s16 &aPosY, s16 &aPosZ, s16 aFYaw, f32 aDist) {
|
||||
for (f32 _Dist = aDist; _Dist > 0.f; _Dist -= 10.f) {
|
||||
f32 _PosX = (f32) aPosX + _Dist * sins(aFYaw + 0x8000);
|
||||
f32 _PosZ = (f32) aPosZ + _Dist * coss(aFYaw + 0x8000);
|
||||
for (f32 _DeltaY = 0.f; _DeltaY <= 5000.f; _DeltaY += 100.f) {
|
||||
f32 _PosY = (f32) aPosY + _DeltaY;
|
||||
struct Surface *_Floor;
|
||||
f32 _FloorY = find_floor(_PosX, _PosY, _PosZ, &_Floor);
|
||||
if (_Floor &&
|
||||
_Floor->type != SURFACE_WARP &&
|
||||
_Floor->type != SURFACE_BURNING &&
|
||||
_Floor->type != SURFACE_DEATH_PLANE &&
|
||||
_Floor->type != SURFACE_VERTICAL_WIND &&
|
||||
_Floor->type != SURFACE_DEEP_QUICKSAND &&
|
||||
_Floor->type != SURFACE_INSTANT_QUICKSAND &&
|
||||
_Floor->type != SURFACE_INSTANT_MOVING_QUICKSAND) {
|
||||
aPosX = _PosX;
|
||||
aPosY = _FloorY;
|
||||
aPosZ = _PosZ;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void *DynOS_Warp_UpdateExit(void *aCmd, bool aIsLevelInitDone) {
|
||||
static s32 sDynosExitTargetArea = -1;
|
||||
static s16 *sDynosExitTargetWarp = NULL;
|
||||
|
||||
// Phase 0 - Wait for the Mario head transition to end
|
||||
if (sDynosExitTargetArea == -1 && DynOS_IsTransitionActive()) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Phase 1 - Clear the previous level and set up the new level
|
||||
if (sDynosExitTargetArea == -1) {
|
||||
|
||||
// Bowser levels
|
||||
if (sDynosExitLevelNum == LEVEL_BOWSER_1) sDynosExitLevelNum = LEVEL_BITDW;
|
||||
if (sDynosExitLevelNum == LEVEL_BOWSER_2) sDynosExitLevelNum = LEVEL_BITFS;
|
||||
if (sDynosExitLevelNum == LEVEL_BOWSER_3) sDynosExitLevelNum = LEVEL_BITS;
|
||||
|
||||
// Exit warp to Castle warp
|
||||
// Uses the death warp, as it's the only warp that exists for every stage in the game
|
||||
s16 *_ExitWarp = DynOS_Level_GetWarpDeath(sDynosExitLevelNum, sDynosExitAreaNum);
|
||||
sDynosExitTargetWarp = DynOS_Level_GetWarp(_ExitWarp[7], _ExitWarp[8], _ExitWarp[9]);
|
||||
|
||||
// Free everything from the current level
|
||||
clear_objects();
|
||||
clear_area_graph_nodes();
|
||||
clear_areas();
|
||||
main_pool_pop_state();
|
||||
|
||||
// Reset Mario's state
|
||||
gMarioState->healCounter = 0;
|
||||
gMarioState->hurtCounter = 0;
|
||||
gMarioState->numCoins = 0;
|
||||
gMarioState->input = 0;
|
||||
gMarioState->controller->buttonPressed = 0;
|
||||
gHudDisplay.coins = 0;
|
||||
|
||||
// Set up new level values
|
||||
gCurrLevelNum = _ExitWarp[7];
|
||||
gCurrCourseNum = DynOS_Level_GetCourse(gCurrLevelNum);
|
||||
gSavedCourseNum = gCurrCourseNum;
|
||||
gDialogCourseActNum = gCurrActNum;
|
||||
gCurrAreaIndex = _ExitWarp[8];
|
||||
sDynosExitTargetArea = _ExitWarp[8];
|
||||
|
||||
// Set up new level script
|
||||
sWarpDest.type = 0;
|
||||
sWarpDest.levelNum = 0;
|
||||
sWarpDest.areaIdx = gCurrAreaIndex;
|
||||
sWarpDest.nodeId = 0;
|
||||
sWarpDest.arg = 0;
|
||||
return (void *) DynOS_Level_GetScript(gCurrLevelNum);
|
||||
|
||||
} else {
|
||||
|
||||
// Phase 2 - Set Mario spawn info after the MARIO_POS command
|
||||
if (*((u8 *) aCmd) == 0x2B) {
|
||||
gMarioSpawnInfo->areaIndex = sDynosExitTargetArea;
|
||||
gCurrAreaIndex = sDynosExitTargetArea;
|
||||
}
|
||||
|
||||
// Phase 3 - End level initialization
|
||||
if (sDynosExitTargetWarp && aIsLevelInitDone) {
|
||||
|
||||
// Find target position
|
||||
// Because of course, every hack has its own warp distances and orientations...
|
||||
s16 _TargetPosX = sDynosExitTargetWarp[3];
|
||||
s16 _TargetPosY = sDynosExitTargetWarp[4];
|
||||
s16 _TargetPosZ = sDynosExitTargetWarp[5];
|
||||
s16 _TargetFYaw = sDynosExitTargetWarp[6];
|
||||
s16 _TargetDYaw = 0;
|
||||
f32 _TargetDist = 500.f;
|
||||
DynOS_Warp_FindExitPosition(_TargetPosX, _TargetPosY, _TargetPosZ, _TargetFYaw + _TargetDYaw, _TargetDist);
|
||||
|
||||
// Init Mario
|
||||
gMarioSpawnInfo->startPos[0] = _TargetPosX;
|
||||
gMarioSpawnInfo->startPos[1] = _TargetPosY;
|
||||
gMarioSpawnInfo->startPos[2] = _TargetPosZ;
|
||||
gMarioSpawnInfo->startAngle[0] = 0;
|
||||
gMarioSpawnInfo->startAngle[1] = _TargetFYaw + _TargetDYaw;
|
||||
gMarioSpawnInfo->startAngle[2] = 0;
|
||||
gMarioSpawnInfo->areaIndex = gCurrAreaIndex;
|
||||
init_mario();
|
||||
set_mario_initial_action(gMarioState, MARIO_SPAWN_UNKNOWN_02, 0);
|
||||
|
||||
// Init transition
|
||||
reset_camera(gCurrentArea->camera);
|
||||
init_camera(gCurrentArea->camera);
|
||||
sDelayedWarpOp = WARP_OP_NONE;
|
||||
play_transition(WARP_TRANSITION_FADE_FROM_STAR, 15, 0x00, 0x00, 0x00);
|
||||
play_sound(SOUND_MENU_MARIO_CASTLE_WARP, gDefaultSoundArgs);
|
||||
|
||||
// Set music
|
||||
set_background_music(gCurrentArea->musicParam, gCurrentArea->musicParam2, 0);
|
||||
sDynosExitTargetWarp = NULL;
|
||||
}
|
||||
|
||||
// Phase 4 - Unlock Mario as soon as the second transition is ended
|
||||
if (!sDynosExitTargetWarp && !DynOS_IsTransitionActive()) {
|
||||
sDynosExitTargetArea = -1;
|
||||
sDynosExitLevelNum = -1;
|
||||
sDynosExitAreaNum = -1;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *DynOS_Warp_Update(void *aCmd, bool aIsLevelInitDone) {
|
||||
|
||||
// Level Exit
|
||||
if (sDynosExitLevelNum != -1 &&
|
||||
sDynosExitAreaNum != -1) {
|
||||
return DynOS_Warp_UpdateExit(aCmd, aIsLevelInitDone);
|
||||
}
|
||||
|
||||
// Level Warp
|
||||
if (sDynosWarpLevelNum != -1 &&
|
||||
sDynosWarpAreaNum != -1 &&
|
||||
sDynosWarpActNum != -1) {
|
||||
return DynOS_Warp_UpdateWarp(aCmd, aIsLevelInitDone);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
15
dynos.mk
Normal file
15
dynos.mk
Normal file
|
@ -0,0 +1,15 @@
|
|||
# ----------------------
|
||||
# Dynamic Options System
|
||||
# ----------------------
|
||||
|
||||
DYNOS_INPUT_DIR := ./dynos
|
||||
DYNOS_OUTPUT_DIR := $(BUILD_DIR)/dynos
|
||||
DYNOS_PACKS_DIR := $(BUILD_DIR)/dynos/packs
|
||||
DYNOS_INIT := \
|
||||
mkdir -p $(DYNOS_INPUT_DIR); \
|
||||
mkdir -p $(DYNOS_OUTPUT_DIR); \
|
||||
mkdir -p $(DYNOS_PACKS_DIR); \
|
||||
cp -f -r $(DYNOS_INPUT_DIR) $(BUILD_DIR) 2>/dev/null || true ;
|
||||
|
||||
DYNOS_DO := $(shell $(call DYNOS_INIT))
|
||||
INCLUDE_CFLAGS += -DDYNOS
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
#include <ultra64.h>
|
||||
#include "macros.h"
|
||||
#include "data/dynos.c.h"
|
||||
#include "pc/network/version.h"
|
||||
|
||||
// Certain functions are marked as having return values, but do not
|
||||
|
@ -112,6 +113,7 @@ struct GraphNode
|
|||
/*0x08*/ struct GraphNode *next;
|
||||
/*0x0C*/ struct GraphNode *parent;
|
||||
/*0x10*/ struct GraphNode *children;
|
||||
/*0x14*/ const void *georef;
|
||||
};
|
||||
|
||||
struct AnimInfo
|
||||
|
|
|
@ -791,5 +791,8 @@ struct GraphNode *process_geo_layout(struct AllocOnlyPool *pool, void *segptr) {
|
|||
GeoLayoutJumpTable[gGeoLayoutCommand[0x00]]();
|
||||
}
|
||||
|
||||
if (gCurRootGraphNode) {
|
||||
gCurRootGraphNode->georef = (const void *) segptr;
|
||||
}
|
||||
return gCurRootGraphNode;
|
||||
}
|
||||
|
|
|
@ -896,7 +896,10 @@ struct LevelCommand *level_script_execute(struct LevelCommand *cmd) {
|
|||
sCurrentCmd = cmd;
|
||||
|
||||
while (sScriptStatus == SCRIPT_RUNNING) {
|
||||
void *dynosCurrCmd = (void *) sCurrentCmd;
|
||||
LevelScriptJumpTable[sCurrentCmd->type]();
|
||||
void *dynosNextCmd = dynos_update_cmd(dynosCurrCmd);
|
||||
if (dynosNextCmd) sCurrentCmd = dynosNextCmd;
|
||||
}
|
||||
|
||||
profiler_log_thread5_time(LEVEL_SCRIPT_EXECUTE);
|
||||
|
|
|
@ -405,6 +405,7 @@ void play_transition_after_delay(s16 transType, s16 time, u8 red, u8 green, u8 b
|
|||
}
|
||||
|
||||
void render_game(void) {
|
||||
dynos_update_gfx();
|
||||
if (gCurrentArea != NULL && !gWarpTransition.pauseRendering) {
|
||||
geo_process_root(gCurrentArea->unk04, D_8032CE74, D_8032CE78, gFBSetColor);
|
||||
|
||||
|
|
|
@ -394,9 +394,6 @@ void adjust_analog_stick(struct Controller *controller) {
|
|||
// if a demo sequence exists, this will run the demo
|
||||
// input list until it is complete. called every frame.
|
||||
void run_demo_inputs(void) {
|
||||
// eliminate the unused bits.
|
||||
gControllers[0].controllerData->button &= VALID_BUTTONS;
|
||||
|
||||
/*
|
||||
Check if a demo inputs list
|
||||
exists and if so, run the
|
||||
|
@ -465,6 +462,7 @@ void read_controller_inputs(void) {
|
|||
if (gControllerBits) {
|
||||
osRecvMesg(&gSIEventMesgQueue, &D_80339BEC, OS_MESG_BLOCK);
|
||||
osContGetReadData(gInteractableOverridePad ? &gInteractablePad : &gControllerPads[0]);
|
||||
dynos_update_opt((void *) &gControllerPads[0]);
|
||||
}
|
||||
run_demo_inputs();
|
||||
|
||||
|
|
|
@ -2920,6 +2920,8 @@ s32 cur_obj_update_dialog_with_cutscene(struct MarioState* m, s32 actionArg, s32
|
|||
s32 cur_obj_has_model(u16 modelID) {
|
||||
if (o->header.gfx.sharedChild == gLoadedGraphNodes[modelID]) {
|
||||
return TRUE;
|
||||
} else if (o->header.gfx.sharedChild && gLoadedGraphNodes[modelID] && o->header.gfx.sharedChild->georef == gLoadedGraphNodes[modelID]->georef) {
|
||||
return TRUE;
|
||||
} else {
|
||||
return FALSE;
|
||||
}
|
||||
|
|
|
@ -1183,7 +1183,9 @@ static void geo_process_object(struct Object *node) {
|
|||
|
||||
// FIXME: correct types
|
||||
if (node->header.gfx.animInfo.curAnim != NULL) {
|
||||
dynos_gfx_swap_animations(node);
|
||||
geo_set_animation_globals(&node->header.gfx.animInfo, hasAnimation);
|
||||
dynos_gfx_swap_animations(node);
|
||||
}
|
||||
if (obj_is_in_view(&node->header.gfx, gMatStack[gMatStackIndex])) {
|
||||
Mtx *mtx = alloc_display_list(sizeof(*mtx));
|
||||
|
@ -1300,7 +1302,9 @@ void geo_process_held_object(struct GraphNodeHeldObject *node) {
|
|||
gCurAnimType = 0;
|
||||
gCurGraphNodeHeldObject = (void *) node;
|
||||
if (node->objNode->header.gfx.animInfo.curAnim != NULL) {
|
||||
dynos_gfx_swap_animations(node->objNode);
|
||||
geo_set_animation_globals(&node->objNode->header.gfx.animInfo, hasAnimation);
|
||||
dynos_gfx_swap_animations(node->objNode);
|
||||
}
|
||||
|
||||
geo_process_node_and_siblings(node->objNode->header.gfx.sharedChild);
|
||||
|
|
|
@ -98,6 +98,10 @@ static void debug_warp_level(u8 level) {
|
|||
}
|
||||
|
||||
static void debug_warp_area() {
|
||||
extern bool dynos_warp_to_level(s32 aLevel, s32 aArea, s32 aAct);
|
||||
dynos_warp_to_level(LEVEL_CCM, 1, 5);
|
||||
return;
|
||||
|
||||
if (sCurrPlayMode == PLAY_MODE_CHANGE_LEVEL) { return; }
|
||||
|
||||
struct ObjectWarpNode* objectNode = gCurrentArea->warpNodes;
|
||||
|
|
|
@ -6,10 +6,8 @@
|
|||
#include <stdbool.h>
|
||||
#include <assert.h>
|
||||
|
||||
#ifdef EXTERNAL_DATA
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#include <stb/stb_image.h>
|
||||
#endif
|
||||
|
||||
#ifndef _LANGUAGE_C
|
||||
#define _LANGUAGE_C
|
||||
|
@ -52,13 +50,8 @@
|
|||
#define MAX_LIGHTS 8
|
||||
#define MAX_VERTICES 64
|
||||
|
||||
#ifdef EXTERNAL_DATA
|
||||
# define MAX_CACHED_TEXTURES 4096 // for preloading purposes
|
||||
# define HASH_SHIFT 0
|
||||
#else
|
||||
# define MAX_CACHED_TEXTURES 512
|
||||
# define HASH_SHIFT 5
|
||||
#endif
|
||||
|
||||
#define HASHMAP_LEN (MAX_CACHED_TEXTURES * 2)
|
||||
#define HASH_MASK (HASHMAP_LEN - 1)
|
||||
|
@ -606,6 +599,8 @@ static bool preload_texture(void *user, const char *path) {
|
|||
#endif // EXTERNAL_DATA
|
||||
|
||||
static void import_texture(int tile) {
|
||||
extern s32 dynos_gfx_import_texture(void **output, void *ptr, s32 tile, void *grapi, void **hashmap, void *pool, s32 *poolpos, s32 poolsize);
|
||||
if (dynos_gfx_import_texture((void **) &rendering_state.textures[tile], (void *) rdp.loaded_texture[tile].addr, tile, gfx_rapi, (void **) gfx_texture_cache.hashmap, (void *) gfx_texture_cache.pool, (int *) &gfx_texture_cache.pool_pos, MAX_CACHED_TEXTURES)) { return; }
|
||||
uint8_t fmt = rdp.texture_tile.fmt;
|
||||
uint8_t siz = rdp.texture_tile.siz;
|
||||
|
||||
|
|
Loading…
Reference in a new issue