mirror of https://github.com/sm64pc/sm64pc.git
This is me learning how to use git i'm running into constant errors and having a hard time but hopefully i'll get there in the end okay here we go into my local ocdizzle branch we go!
This commit is contained in:
parent
db9a6345ba
commit
13d9bcb5b4
|
@ -0,0 +1,28 @@
|
|||
#ifndef DYNOS_C_H
|
||||
#define DYNOS_C_H
|
||||
#ifndef __cplusplus
|
||||
|
||||
#include "dynos.h"
|
||||
|
||||
// The action signature is "bool (*) (const char *)"
|
||||
// The input is the button internal name (not label)
|
||||
// The output is the result of the action
|
||||
#define DYNOS_DEFINE_ACTION(func) \
|
||||
DYNOS_AT_STARTUP static void dynos_opt_add_action_##func() { \
|
||||
dynos_opt_add_action(#func, func, false); \
|
||||
}
|
||||
|
||||
s32 dynos_opt_get_value (const char *name);
|
||||
void dynos_opt_set_value (const char *name, s32 value);
|
||||
void dynos_opt_add_action (const char *funcname, bool (*funcptr)(const char *), bool overwrite);
|
||||
|
||||
void *dynos_update_cmd (void *cmd);
|
||||
void dynos_update_gfx ();
|
||||
void dynos_update_opt (void *pad);
|
||||
bool dynos_sanity_check_geo (s16 graphNodeType);
|
||||
bool dynos_sanity_check_seq (u8 loBits);
|
||||
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);
|
||||
|
||||
#endif
|
||||
#endif
|
|
@ -0,0 +1,714 @@
|
|||
#ifndef DYNOS_CPP_H
|
||||
#define DYNOS_CPP_H
|
||||
#ifdef __cplusplus
|
||||
|
||||
#include "dynos.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,
|
||||
#ifndef DYNOS_COOP
|
||||
DOPT_CHOICEPARAM,
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef DYNOS_COOP
|
||||
enum {
|
||||
DYNOS_COOP_COMMAND_NONE,
|
||||
DYNOS_COOP_COMMAND_WARP_TO_LEVEL,
|
||||
DYNOS_COOP_COMMAND_WARP_TO_CASTLE,
|
||||
DYNOS_COOP_COMMAND_RESTART_LEVEL,
|
||||
DYNOS_COOP_COMMAND_EXIT_LEVEL,
|
||||
};
|
||||
#endif
|
||||
|
||||
//
|
||||
// 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 95
|
||||
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_Init();
|
||||
void DynOS_UpdateOpt(void *aPad);
|
||||
void *DynOS_UpdateCmd(void *aCmd);
|
||||
void DynOS_UpdateGfx();
|
||||
bool DynOS_IsTransitionActive();
|
||||
#ifndef DYNOS_COOP
|
||||
void DynOS_ReturnToMainMenu();
|
||||
#endif
|
||||
#ifdef DYNOS_COOP
|
||||
void DynOS_Coop_SendCommand(s32 aType, s32 aLevel, s32 aArea, s32 aAct);
|
||||
#endif
|
||||
|
||||
//
|
||||
// Opt
|
||||
//
|
||||
|
||||
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);
|
||||
|
||||
//
|
||||
// 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 &aFilename);
|
||||
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);
|
||||
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);
|
||||
#ifndef DYNOS_COOP
|
||||
void DynOS_Warp_SetParam(s32 aLevel, s32 aIndex);
|
||||
const char *DynOS_Warp_GetParamName(s32 aLevel, s32 aIndex);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
#endif
|
|
@ -0,0 +1,40 @@
|
|||
#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 "types.h"
|
||||
#include "config.h"
|
||||
#include "pc/fs/fs.h"
|
||||
#include "audio_defines.h"
|
||||
#include "engine/math_util.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
|
|
@ -0,0 +1,36 @@
|
|||
#include "dynos.cpp.h"
|
||||
extern "C" {
|
||||
|
||||
s32 dynos_opt_get_value(const char *name) {
|
||||
return DynOS_Opt_GetValue(name);
|
||||
}
|
||||
|
||||
void dynos_opt_set_value(const char *name, s32 value) {
|
||||
return DynOS_Opt_SetValue(name, value);
|
||||
}
|
||||
|
||||
void dynos_opt_add_action(const char *funcname, bool (*funcptr)(const char *), bool overwrite) {
|
||||
return DynOS_Opt_AddAction(funcname, funcptr, overwrite);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -0,0 +1,278 @@
|
|||
#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 });
|
||||
}
|
||||
|
||||
GfxData *DynOS_Gfx_LoadFromBinary(const SysPath &aFilename) {
|
||||
FILE *_File = fopen(aFilename.c_str(), "rb");
|
||||
if (!_File) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Data
|
||||
GfxData *_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);
|
||||
return _GfxData;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -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
|
||||
);
|
||||
}
|
|
@ -0,0 +1,200 @@
|
|||
#include "dynos.cpp.h"
|
||||
extern "C" {
|
||||
#include "object_fields.h"
|
||||
#include "game/level_update.h"
|
||||
#include "game/object_list_processor.h"
|
||||
}
|
||||
|
||||
//
|
||||
// Free data
|
||||
// Must be unloaded the next frame to prevent a crash
|
||||
//
|
||||
|
||||
STATIC_STORAGE(Array<GfxData *>, GfxDataFreeList);
|
||||
#define sGfxDataFreeList __GfxDataFreeList()
|
||||
|
||||
STATIC_STORAGE(Array<GraphNode *>, GraphNodeFreeList);
|
||||
#define sGraphNodeFreeList __GraphNodeFreeList()
|
||||
|
||||
static void DynOS_Gfx_FreeUnloaded() {
|
||||
for (auto &_GfxData : sGfxDataFreeList) DynOS_Gfx_Free(_GfxData);
|
||||
for (auto &_GraphNode : sGraphNodeFreeList) Delete(_GraphNode);
|
||||
sGfxDataFreeList.Clear();
|
||||
sGraphNodeFreeList.Clear();
|
||||
}
|
||||
|
||||
//
|
||||
// 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.unk38.curAnim) {
|
||||
return -1;
|
||||
}
|
||||
for (s32 i = 0; aObject->oAnimations[i] != NULL; ++i) {
|
||||
if (aObject->oAnimations[i] == aObject->header.gfx.unk38.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.unk38.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.unk02 = _AnimData->mUnk02;
|
||||
sGfxDataAnimation.unk04 = _AnimData->mUnk04;
|
||||
sGfxDataAnimation.unk06 = _AnimData->mUnk06;
|
||||
sGfxDataAnimation.unk08 = _AnimData->mUnk08;
|
||||
sGfxDataAnimation.unk0A = _AnimData->mUnk0A.second;
|
||||
sGfxDataAnimation.values = _AnimData->mValues.second.begin();
|
||||
sGfxDataAnimation.index = _AnimData->mIndex.second.begin();
|
||||
sGfxDataAnimation.length = _AnimData->mLength;
|
||||
_Object->header.gfx.unk38.curAnim = &sGfxDataAnimation;
|
||||
}
|
||||
|
||||
// Restore the default animation
|
||||
} else {
|
||||
_Object->header.gfx.unk38.curAnim = pDefaultAnimation;
|
||||
pDefaultAnimation = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Update models
|
||||
//
|
||||
|
||||
static void DynOS_Gfx_UpdateModelData(struct Object *aObject, s32 aActorIndex) {
|
||||
ActorGfx *_ActorGfx = &DynOS_Gfx_GetActorList()[aActorIndex];
|
||||
const Array<PackData *> &pDynosPacks = DynOS_Gfx_GetPacks();
|
||||
for (s32 i = 0; i != pDynosPacks.Count(); ++i) {
|
||||
|
||||
// Pack
|
||||
bool _Enabled = DynOS_Opt_GetValue(String("dynos_pack_%d", i));
|
||||
|
||||
// If enabled and no pack is selected
|
||||
// load the pack's model and replace the default actor's model
|
||||
if (_Enabled && _ActorGfx->mPackIndex == -1) {
|
||||
|
||||
// Load Gfx data from binary
|
||||
SysPath _Filename = fstring("%s/%s.bin", pDynosPacks[i]->mPath.begin(), DynOS_Geo_GetActorName(aActorIndex));
|
||||
GfxData *_GfxData = DynOS_Gfx_LoadFromBinary(_Filename);
|
||||
if (_GfxData == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Mark previous model data as unload
|
||||
if (_ActorGfx->mGfxData) sGfxDataFreeList.Add(_ActorGfx->mGfxData);
|
||||
if (_ActorGfx->mGraphNode) sGraphNodeFreeList.Add(_ActorGfx->mGraphNode);
|
||||
|
||||
// Load graph node and animations
|
||||
_ActorGfx->mPackIndex = i;
|
||||
_ActorGfx->mGfxData = _GfxData;
|
||||
_ActorGfx->mGraphNode = (GraphNode *) DynOS_Geo_GetGraphNode((*(_GfxData->mGeoLayouts.end() - 1))->mData, false);
|
||||
_ActorGfx->mGraphNode->georef = DynOS_Geo_GetActorLayout(aActorIndex);
|
||||
break;
|
||||
}
|
||||
|
||||
// If disabled and this pack is the one selected
|
||||
// unload the pack's model and replace the actor's model by the default one
|
||||
else if (!_Enabled && _ActorGfx->mPackIndex == i) {
|
||||
|
||||
// Mark previous model data as unload
|
||||
if (_ActorGfx->mGfxData) sGfxDataFreeList.Add(_ActorGfx->mGfxData);
|
||||
if (_ActorGfx->mGraphNode) sGraphNodeFreeList.Add(_ActorGfx->mGraphNode);
|
||||
|
||||
// Default
|
||||
_ActorGfx->mPackIndex = -1;
|
||||
_ActorGfx->mGfxData = NULL;
|
||||
_ActorGfx->mGraphNode = (GraphNode *) DynOS_Geo_GetGraphNode(DynOS_Geo_GetActorLayout(aActorIndex), false);
|
||||
}
|
||||
}
|
||||
|
||||
// Update object
|
||||
aObject->header.gfx.sharedChild = _ActorGfx->mGraphNode;
|
||||
}
|
||||
|
||||
void DynOS_Gfx_Update() {
|
||||
|
||||
// Don't update until the object lists are loaded
|
||||
if (!gObjectLists) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Free unloaded things
|
||||
DynOS_Gfx_FreeUnloaded();
|
||||
|
||||
// Update per object
|
||||
for (s32 _List = 0; _List != NUM_OBJ_LISTS; ++_List) {
|
||||
struct Object *_Head = (struct Object *) &gObjectLists[_List];
|
||||
for (struct Object *_Object = (struct Object *) _Head->header.next; _Object != _Head; _Object = (struct Object *) _Object->header.next) {
|
||||
|
||||
// Does the object has a model?
|
||||
if (!_Object->header.gfx.sharedChild) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Actor index
|
||||
s32 _ActorIndex = DynOS_Geo_GetActorIndex(_Object->header.gfx.sharedChild->georef);
|
||||
if (_ActorIndex == -1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Replace the object's model and animations
|
||||
DynOS_Gfx_UpdateModelData(_Object, _ActorIndex);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,826 @@
|
|||
#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;
|
||||
}
|
||||
|
|
@ -0,0 +1,133 @@
|
|||
#include "dynos.cpp.h"
|
||||
extern "C" {
|
||||
#include "sm64.h"
|
||||
#include "level_commands.h"
|
||||
#include "game/level_update.h"
|
||||
#include "game/options_menu.h"
|
||||
#include "game/object_list_processor.h"
|
||||
extern s16 gMenuMode;
|
||||
extern s8 gDialogBoxState;
|
||||
#ifdef OMM_DEFINES_H
|
||||
extern void omm_opt_init();
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef DYNOS_COOP
|
||||
//
|
||||
// Network (Coop only)
|
||||
//
|
||||
|
||||
extern "C" {
|
||||
#include "pc/network/network.h"
|
||||
}
|
||||
|
||||
static struct DynosCoopCommandStruct {
|
||||
s32 mType = DYNOS_COOP_COMMAND_NONE;
|
||||
s32 mLevel = 0;
|
||||
s32 mArea = 0;
|
||||
s32 mAct = 0;
|
||||
} sDynosCoopCommand;
|
||||
static u8 sDynosCoopCustomPacketId = 0xFF;
|
||||
|
||||
static void DynOS_Coop_SendPacket(struct Packet *p, UNUSED void *params) {
|
||||
packet_write(p, &sDynosCoopCommand, sizeof(DynosCoopCommandStruct));
|
||||
}
|
||||
|
||||
static void DynOS_Coop_ReceivePacket(struct Packet *p) {
|
||||
packet_read(p, &sDynosCoopCommand, sizeof(DynosCoopCommandStruct));
|
||||
}
|
||||
|
||||
static void DynOS_Coop_Update() {
|
||||
if (sDynosCoopCustomPacketId == 0xFF) {
|
||||
network_register_mod((char *) "DynOS.1.0.coop");
|
||||
sDynosCoopCustomPacketId = network_register_custom_packet(DynOS_Coop_SendPacket, DynOS_Coop_ReceivePacket);
|
||||
}
|
||||
|
||||
// Commands
|
||||
switch (sDynosCoopCommand.mType) {
|
||||
case DYNOS_COOP_COMMAND_WARP_TO_LEVEL: {
|
||||
DynOS_Warp_ToLevel(sDynosCoopCommand.mLevel, sDynosCoopCommand.mArea, sDynosCoopCommand.mAct);
|
||||
} break;
|
||||
|
||||
case DYNOS_COOP_COMMAND_WARP_TO_CASTLE: {
|
||||
DynOS_Warp_ToCastle(sDynosCoopCommand.mLevel);
|
||||
} break;
|
||||
|
||||
case DYNOS_COOP_COMMAND_RESTART_LEVEL: {
|
||||
DynOS_Warp_RestartLevel();
|
||||
} break;
|
||||
|
||||
case DYNOS_COOP_COMMAND_EXIT_LEVEL: {
|
||||
DynOS_Warp_ExitLevel(30);
|
||||
} break;
|
||||
}
|
||||
sDynosCoopCommand.mType = DYNOS_COOP_COMMAND_NONE;
|
||||
}
|
||||
|
||||
void DynOS_Coop_SendCommand(s32 aType, s32 aLevel, s32 aArea, s32 aAct) {
|
||||
sDynosCoopCommand.mType = aType;
|
||||
sDynosCoopCommand.mLevel = aLevel;
|
||||
sDynosCoopCommand.mArea = aArea;
|
||||
sDynosCoopCommand.mAct = aAct;
|
||||
network_send_custom(sDynosCoopCustomPacketId, true, false, NULL);
|
||||
sDynosCoopCommand.mType = DYNOS_COOP_COMMAND_NONE;
|
||||
}
|
||||
#endif
|
||||
|
||||
//
|
||||
// Main Menu
|
||||
//
|
||||
|
||||
#ifndef DYNOS_COOP
|
||||
void DynOS_ReturnToMainMenu() {
|
||||
optmenu_toggle();
|
||||
level_set_transition(0, NULL);
|
||||
gDialogBoxState = 0;
|
||||
gMenuMode = -1;
|
||||
fade_into_special_warp(-2, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
//
|
||||
// Init
|
||||
//
|
||||
|
||||
DYNOS_AT_STARTUP void DynOS_Init() {
|
||||
#ifdef OMM_DEFINES_H
|
||||
omm_opt_init();
|
||||
#endif
|
||||
DynOS_Opt_Init();
|
||||
}
|
||||
|
||||
//
|
||||
// Update
|
||||
//
|
||||
|
||||
static bool sDynosIsLevelEntry = false;
|
||||
void DynOS_UpdateOpt(void *aPad) {
|
||||
if (sDynosIsLevelEntry) {
|
||||
#ifndef DYNOS_COOP
|
||||
DynOS_Warp_SetParam(gCurrLevelNum, -1);
|
||||
#endif
|
||||
sDynosIsLevelEntry = false;
|
||||
}
|
||||
DynOS_Opt_Update((OSContPad *) aPad);
|
||||
#ifdef DYNOS_COOP
|
||||
DynOS_Coop_Update();
|
||||
#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;
|
||||
}
|
|
@ -0,0 +1,509 @@
|
|||
#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 DYNOS_COOP
|
||||
extern const GeoLayout luigi_geo[];
|
||||
extern const GeoLayout luigis_cap_geo[];
|
||||
extern const GeoLayout luigis_metal_cap_geo[];
|
||||
extern const GeoLayout luigis_wing_cap_geo[];
|
||||
extern const GeoLayout luigis_winged_metal_cap_geo[];
|
||||
#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
|
||||
//
|
||||
|
||||
static const Array<Pair<const char *, void *>> &__Actors() {
|
||||
#define define_actor(geo) { #geo, (void *) geo }
|
||||
static const Array<Pair<const char *, void *>> sActors = {
|
||||
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),
|
||||
#ifdef DYNOS_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),
|
||||
#endif
|
||||
|
||||
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),
|
||||
};
|
||||
#undef define_actor
|
||||
return sActors;
|
||||
}
|
||||
#define sActors __Actors()
|
||||
|
||||
s32 DynOS_Geo_GetActorCount() {
|
||||
return sActors.Count();
|
||||
}
|
||||
|
||||
const char *DynOS_Geo_GetActorName(s32 aIndex) {
|
||||
return sActors[aIndex].first;
|
||||
}
|
||||
|
||||
void *DynOS_Geo_GetActorLayout(s32 aIndex) {
|
||||
return sActors[aIndex].second;
|
||||
}
|
||||
|
||||
s32 DynOS_Geo_GetActorIndex(const void *aGeoLayout) {
|
||||
for (const auto &_Actor : sActors) {
|
||||
if (_Actor.second == aGeoLayout) {
|
||||
return (s32) (&_Actor - sActors.begin());
|
||||
}
|
||||
}
|
||||
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),
|
||||
};
|
||||
#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;
|
||||
}
|
|
@ -0,0 +1,847 @@
|
|||
#include "dynos.cpp.h"
|
||||
extern "C" {
|
||||
#include "pc/configfile.h"
|
||||
#include "audio/external.h"
|
||||
#include "game/game_init.h"
|
||||
#include "pc/controller/controller_keyboard.h"
|
||||
#ifdef BETTERCAMERA
|
||||
#include "game/bettercamera.h"
|
||||
#endif
|
||||
}
|
||||
|
||||
//
|
||||
// Data
|
||||
//
|
||||
|
||||
static DynosOption *sPrevOpt = NULL;
|
||||
static DynosOption *sDynosMenu = NULL;
|
||||
static DynosOption *sOptionsMenu = NULL;
|
||||
static DynosOption *sCurrentMenu = NULL;
|
||||
static DynosOption *sCurrentOpt = NULL;
|
||||
extern s32 sBindingState;
|
||||
|
||||
//
|
||||
// Action list
|
||||
//
|
||||
|
||||
typedef bool (*DynosActionFunction)(const char *);
|
||||
struct DynosAction : NoCopy {
|
||||
String mFuncName;
|
||||
DynosActionFunction mAction;
|
||||
};
|
||||
|
||||
STATIC_STORAGE(Array<DynosAction *>, DynosActions);
|
||||
#define sDynosActions __DynosActions()
|
||||
|
||||
static DynosActionFunction DynOS_Opt_GetAction(const String& aFuncName) {
|
||||
for (auto &_DynosAction : sDynosActions) {
|
||||
if (_DynosAction->mFuncName == aFuncName) {
|
||||
return _DynosAction->mAction;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void DynOS_Opt_AddAction(const String& aFuncName, bool (*aFuncPtr)(const char *), bool aOverwrite) {
|
||||
for (auto &_DynosAction : sDynosActions) {
|
||||
if (_DynosAction->mFuncName == aFuncName) {
|
||||
if (aOverwrite) {
|
||||
_DynosAction->mAction = aFuncPtr;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
DynosAction *_DynosAction = New<DynosAction>();
|
||||
_DynosAction->mFuncName = aFuncName;
|
||||
_DynosAction->mAction = aFuncPtr;
|
||||
sDynosActions.Add(_DynosAction);
|
||||
}
|
||||
|
||||
//
|
||||
// Constructors
|
||||
//
|
||||
|
||||
static DynosOption *DynOS_Opt_GetExistingOption(DynosOption *aOpt, const String &aName) {
|
||||
while (aOpt) {
|
||||
if (aOpt->mName == aName) {
|
||||
return aOpt;
|
||||
}
|
||||
if (aOpt->mType == DOPT_SUBMENU) {
|
||||
DynosOption *_Opt = DynOS_Opt_GetExistingOption(aOpt->mSubMenu.mChild, aName);
|
||||
if (_Opt) {
|
||||
return _Opt;
|
||||
}
|
||||
}
|
||||
aOpt = aOpt->mNext;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static DynosOption *DynOS_Opt_NewOption(const String &aName, const String &aConfigName, const String &aLabel, const String &aTitle) {
|
||||
|
||||
// Check if the option already exists
|
||||
static DynosOption sDummyOpt;
|
||||
if (DynOS_Opt_GetExistingOption(sDynosMenu, aName)) {
|
||||
return &sDummyOpt;
|
||||
}
|
||||
|
||||
// Create a new option
|
||||
DynosOption *_Opt = New<DynosOption>();
|
||||
_Opt->mName = aName;
|
||||
_Opt->mConfigName = aConfigName;
|
||||
_Opt->mLabel = { aLabel, NULL };
|
||||
_Opt->mTitle = { aTitle, NULL };
|
||||
_Opt->mDynos = true;
|
||||
if (sPrevOpt == NULL) { // The very first option
|
||||
_Opt->mPrev = NULL;
|
||||
_Opt->mNext = NULL;
|
||||
_Opt->mParent = NULL;
|
||||
sDynosMenu = _Opt;
|
||||
} else {
|
||||
if (sPrevOpt->mType == DOPT_SUBMENU && sPrevOpt->mSubMenu.mEmpty) { // First option of a sub-menu
|
||||
_Opt->mPrev = NULL;
|
||||
_Opt->mNext = NULL;
|
||||
_Opt->mParent = sPrevOpt;
|
||||
sPrevOpt->mSubMenu.mChild = _Opt;
|
||||
sPrevOpt->mSubMenu.mEmpty = false;
|
||||
} else {
|
||||
_Opt->mPrev = sPrevOpt;
|
||||
_Opt->mNext = NULL;
|
||||
_Opt->mParent = sPrevOpt->mParent;
|
||||
sPrevOpt->mNext = _Opt;
|
||||
}
|
||||
}
|
||||
sPrevOpt = _Opt;
|
||||
return _Opt;
|
||||
}
|
||||
|
||||
static void DynOS_Opt_EndSubMenu() {
|
||||
if (sPrevOpt && sPrevOpt->mParent) {
|
||||
if (sPrevOpt->mType == DOPT_SUBMENU && sPrevOpt->mSubMenu.mEmpty) { // ENDMENU command following a SUBMENU command
|
||||
sPrevOpt->mSubMenu.mEmpty = false;
|
||||
} else {
|
||||
sPrevOpt = sPrevOpt->mParent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void DynOS_Opt_CreateSubMenu(const String &aName, const String &aLabel, const String &aTitle) {
|
||||
DynosOption *_Opt = DynOS_Opt_NewOption(aName, "", aLabel, aTitle);
|
||||
_Opt->mType = DOPT_SUBMENU;
|
||||
_Opt->mSubMenu.mChild = NULL;
|
||||
_Opt->mSubMenu.mEmpty = true;
|
||||
}
|
||||
|
||||
static void DynOS_Opt_CreateToggle(const String &aName, const String &aConfigName, const String &aLabel, s32 aValue) {
|
||||
DynosOption *_Opt = DynOS_Opt_NewOption(aName, aConfigName, aLabel, aLabel);
|
||||
_Opt->mType = DOPT_TOGGLE;
|
||||
_Opt->mToggle.mTog = New<bool>();
|
||||
*_Opt->mToggle.mTog = (bool) aValue;
|
||||
}
|
||||
|
||||
static void DynOS_Opt_CreateScroll(const String &aName, const String &aConfigName, const String &aLabel, s32 aMin, s32 aMax, s32 aStep, s32 aValue) {
|
||||
DynosOption *_Opt = DynOS_Opt_NewOption(aName, aConfigName, aLabel, aLabel);
|
||||
_Opt->mType = DOPT_SCROLL;
|
||||
_Opt->mScroll.mMin = aMin;
|
||||
_Opt->mScroll.mMax = aMax;
|
||||
_Opt->mScroll.mStep = aStep;
|
||||
_Opt->mScroll.mValue = New<s32>();
|
||||
*_Opt->mScroll.mValue = aValue;
|
||||
}
|
||||
|
||||
static void DynOS_Opt_CreateChoice(const String &aName, const String &aConfigName, const String &aLabel, const Array<String>& aChoices, s32 aValue) {
|
||||
DynosOption *_Opt = DynOS_Opt_NewOption(aName, aConfigName, aLabel, aLabel);
|
||||
_Opt->mType = DOPT_CHOICE;
|
||||
_Opt->mChoice.mIndex = New<s32>();
|
||||
*_Opt->mChoice.mIndex = aValue;
|
||||
for (const auto &_Choice : aChoices) {
|
||||
_Opt->mChoice.mChoices.Add({ _Choice, NULL });
|
||||
}
|
||||
}
|
||||
|
||||
static void DynOS_Opt_CreateButton(const String &aName, const String &aLabel, const String& aFuncName) {
|
||||
DynosOption *_Opt = DynOS_Opt_NewOption(aName, "", aLabel, aLabel);
|
||||
_Opt->mType = DOPT_BUTTON;
|
||||
_Opt->mButton.mFuncName = aFuncName;
|
||||
}
|
||||
|
||||
static void DynOS_Opt_CreateBind(const String &aName, const String &aConfigName, const String &aLabel, u32 aMask, u32 aBind0, u32 aBind1, u32 aBind2) {
|
||||
DynosOption *_Opt = DynOS_Opt_NewOption(aName, aConfigName, aLabel, aLabel);
|
||||
_Opt->mType = DOPT_BIND;
|
||||
_Opt->mBind.mMask = aMask;
|
||||
_Opt->mBind.mBinds = New<u32>(3);
|
||||
_Opt->mBind.mBinds[0] = aBind0;
|
||||
_Opt->mBind.mBinds[1] = aBind1;
|
||||
_Opt->mBind.mBinds[2] = aBind2;
|
||||
_Opt->mBind.mIndex = 0;
|
||||
}
|
||||
|
||||
static void DynOS_Opt_ReadFile(const SysPath &aFolder, const SysPath &aFilename) {
|
||||
|
||||
// Open file
|
||||
SysPath _FullFilename = fstring("%s/%s", aFolder.c_str(), aFilename.c_str());
|
||||
FILE *_File = fopen(_FullFilename.c_str(), "rt");
|
||||
if (_File == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Read file and create options
|
||||
char _Buffer[4096];
|
||||
while (fgets(_Buffer, 4096, _File) != NULL) {
|
||||
Array<String> _Tokens = Split(_Buffer, " #\t\r\n\b", "#", true);
|
||||
|
||||
// Empty line
|
||||
if (_Tokens.Empty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// SUBMENU [Name] [Label] [Title]
|
||||
if (_Tokens[0] == "SUBMENU" && _Tokens.Count() >= 4) {
|
||||
DynOS_Opt_CreateSubMenu(_Tokens[1], _Tokens[2], _Tokens[3]);
|
||||
continue;
|
||||
}
|
||||
|
||||
// TOGGLE [Name] [Label] [ConfigName] [InitialValue]
|
||||
if (_Tokens[0] == "TOGGLE" && _Tokens.Count() >= 5) {
|
||||
DynOS_Opt_CreateToggle(_Tokens[1], _Tokens[3], _Tokens[2], _Tokens[4].ParseInt());
|
||||
continue;
|
||||
}
|
||||
|
||||
// SCROLL [Name] [Label] [ConfigName] [InitialValue] [Min] [Max] [Step]
|
||||
if (_Tokens[0] == "SCROLL" && _Tokens.Count() >= 8) {
|
||||
DynOS_Opt_CreateScroll(_Tokens[1], _Tokens[3], _Tokens[2], _Tokens[5].ParseInt(), _Tokens[6].ParseInt(), _Tokens[7].ParseInt(), _Tokens[4].ParseInt());
|
||||
continue;
|
||||
}
|
||||
|
||||
// CHOICE [Name] [Label] [ConfigName] [InitialValue] [ChoiceStrings...]
|
||||
if (_Tokens[0] == "CHOICE" && _Tokens.Count() >= 6) {
|
||||
DynOS_Opt_CreateChoice(_Tokens[1], _Tokens[3], _Tokens[2], Array<String>(_Tokens.begin() + 5, _Tokens.end()), _Tokens[4].ParseInt());
|
||||
continue;
|
||||
}
|
||||
|
||||
// BUTTON [Name] [Label] [FuncName]
|
||||
if (_Tokens[0] == "BUTTON" && _Tokens.Count() >= 4) {
|
||||
DynOS_Opt_CreateButton(_Tokens[1], _Tokens[2], _Tokens[3]);
|
||||
continue;
|
||||
}
|
||||
|
||||
// BIND [Name] [Label] [ConfigName] [Mask] [DefaultValues]
|
||||
if (_Tokens[0] == "BIND" && _Tokens.Count() >= 8) {
|
||||
DynOS_Opt_CreateBind(_Tokens[1], _Tokens[3], _Tokens[2], _Tokens[4].ParseInt(), _Tokens[5].ParseInt(), _Tokens[6].ParseInt(), _Tokens[7].ParseInt());
|
||||
continue;
|
||||
}
|
||||
|
||||
// ENDMENU
|
||||
if (_Tokens[0] == "ENDMENU") {
|
||||
DynOS_Opt_EndSubMenu();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
fclose(_File);
|
||||
}
|
||||
|
||||
static void DynOS_Opt_LoadOptions() {
|
||||
SysPath _DynosFolder = fstring("%s/%s", DYNOS_EXE_FOLDER, DYNOS_RES_FOLDER);
|
||||
DIR *_DynosDir = opendir(_DynosFolder.c_str());
|
||||
sPrevOpt = NULL;
|
||||
if (_DynosDir) {
|
||||
struct dirent *_DynosEnt = NULL;
|
||||
while ((_DynosEnt = readdir(_DynosDir)) != NULL) {
|
||||
SysPath _Filename = SysPath(_DynosEnt->d_name);
|
||||
if (_Filename.find(".txt") == _Filename.length() - 4) {
|
||||
DynOS_Opt_ReadFile(_DynosFolder, _Filename);
|
||||
}
|
||||
}
|
||||
closedir(_DynosDir);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Loop through DynosOptions
|
||||
//
|
||||
|
||||
DynosOption *DynOS_Opt_Loop(DynosOption *aOpt, DynosLoopFunc aFunc, void *aData) {
|
||||
while (aOpt) {
|
||||
if (aFunc(aOpt, aData)) {
|
||||
return aOpt;
|
||||
} else if (aOpt->mType == DOPT_SUBMENU) {
|
||||
DynosOption *_Opt = DynOS_Opt_Loop(aOpt->mSubMenu.mChild, aFunc, aData);
|
||||
if (_Opt) {
|
||||
return _Opt;
|
||||
}
|
||||
}
|
||||
aOpt = aOpt->mNext;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//
|
||||
// Get/Set values
|
||||
//
|
||||
|
||||
static bool DynOS_Opt_Get(DynosOption *aOpt, void *aData) {
|
||||
return aOpt->mName == (const char *) aData;
|
||||
}
|
||||
|
||||
s32 DynOS_Opt_GetValue(const String &aName) {
|
||||
DynosOption *_Opt = DynOS_Opt_Loop(sDynosMenu, DynOS_Opt_Get, (void *) aName.begin());
|
||||
if (_Opt) {
|
||||
switch (_Opt->mType) {
|
||||
case DOPT_TOGGLE: return *_Opt->mToggle.mTog;
|
||||
case DOPT_CHOICE: return *_Opt->mChoice.mIndex;
|
||||
case DOPT_CHOICELEVEL: return *_Opt->mChoice.mIndex;
|
||||
case DOPT_CHOICEAREA: return *_Opt->mChoice.mIndex;
|
||||
case DOPT_CHOICESTAR: return *_Opt->mChoice.mIndex;
|
||||
#ifndef DYNOS_COOP
|
||||
case DOPT_CHOICEPARAM: return *_Opt->mChoice.mIndex;
|
||||
#endif
|
||||
case DOPT_SCROLL: return *_Opt->mScroll.mValue;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void DynOS_Opt_SetValue(const String &aName, s32 aValue) {
|
||||
DynosOption *_Opt = DynOS_Opt_Loop(sDynosMenu, DynOS_Opt_Get, (void *) aName.begin());
|
||||
if (_Opt) {
|
||||
switch (_Opt->mType) {
|
||||
case DOPT_TOGGLE: *_Opt->mToggle.mTog = aValue; break;
|
||||
case DOPT_CHOICE: *_Opt->mChoice.mIndex = aValue; break;
|
||||
case DOPT_CHOICELEVEL: *_Opt->mChoice.mIndex = aValue; break;
|
||||
case DOPT_CHOICEAREA: *_Opt->mChoice.mIndex = aValue; break;
|
||||
case DOPT_CHOICESTAR: *_Opt->mChoice.mIndex = aValue; break;
|
||||
#ifndef DYNOS_COOP
|
||||
case DOPT_CHOICEPARAM: *_Opt->mChoice.mIndex = aValue; break;
|
||||
#endif
|
||||
case DOPT_SCROLL: *_Opt->mScroll.mValue = aValue; break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Processing
|
||||
//
|
||||
|
||||
#define SOUND_DYNOS_SAVED (SOUND_MENU_MARIO_CASTLE_WARP2 | (0xFF << 8))
|
||||
#define SOUND_DYNOS_SELECT (SOUND_MENU_CHANGE_SELECT | (0xF8 << 8))
|
||||
#define SOUND_DYNOS_OK (SOUND_MENU_CHANGE_SELECT | (0xF8 << 8))
|
||||
#define SOUND_DYNOS_CANCEL (SOUND_MENU_CAMERA_BUZZ | (0xFC << 8))
|
||||
|
||||
enum {
|
||||
INPUT_LEFT,
|
||||
INPUT_RIGHT,
|
||||
INPUT_A,
|
||||
INPUT_Z
|
||||
};
|
||||
|
||||
enum {
|
||||
RESULT_NONE,
|
||||
RESULT_OK,
|
||||
RESULT_CANCEL
|
||||
};
|
||||
|
||||
static s32 DynOS_Opt_ProcessInput(DynosOption *aOpt, s32 input) {
|
||||
switch (aOpt->mType) {
|
||||
case DOPT_TOGGLE:
|
||||
if (input == INPUT_LEFT) {
|
||||
*aOpt->mToggle.mTog = false;
|
||||
return RESULT_OK;
|
||||
}
|
||||
if (input == INPUT_RIGHT) {
|
||||
*aOpt->mToggle.mTog = true;
|
||||
return RESULT_OK;
|
||||
}
|
||||
if (input == INPUT_A) {
|
||||
*aOpt->mToggle.mTog = !(*aOpt->mToggle.mTog);
|
||||
return RESULT_OK;
|
||||
}
|
||||
break;
|
||||
|
||||
case DOPT_CHOICE:
|
||||
if (input == INPUT_LEFT) {
|
||||
*aOpt->mChoice.mIndex = (*aOpt->mChoice.mIndex + aOpt->mChoice.mChoices.Count() - 1) % (aOpt->mChoice.mChoices.Count());
|
||||
return RESULT_OK;
|
||||
}
|
||||
if (input == INPUT_RIGHT || input == INPUT_A) {
|
||||
*aOpt->mChoice.mIndex = (*aOpt->mChoice.mIndex + 1) % (aOpt->mChoice.mChoices.Count());
|
||||
return RESULT_OK;
|
||||
}
|
||||
break;
|
||||
|
||||
case DOPT_CHOICELEVEL:
|
||||
if (input == INPUT_LEFT) {
|
||||
*aOpt->mChoice.mIndex = (*aOpt->mChoice.mIndex + DynOS_Level_GetCount() - 1) % (DynOS_Level_GetCount());
|
||||
return RESULT_OK;
|
||||
}
|
||||
if (input == INPUT_RIGHT || input == INPUT_A) {
|
||||
*aOpt->mChoice.mIndex = (*aOpt->mChoice.mIndex + 1) % (DynOS_Level_GetCount());
|
||||
return RESULT_OK;
|
||||
}
|
||||
break;
|
||||
|
||||
case DOPT_CHOICEAREA:
|
||||
if (input == INPUT_LEFT) {
|
||||
*aOpt->mChoice.mIndex = (*aOpt->mChoice.mIndex + 3) % (4);
|
||||
return RESULT_OK;
|
||||
}
|
||||
if (input == INPUT_RIGHT || input == INPUT_A) {
|
||||
*aOpt->mChoice.mIndex = (*aOpt->mChoice.mIndex + 1) % (4);
|
||||
return RESULT_OK;
|
||||
}
|
||||
break;
|
||||
|
||||
case DOPT_CHOICESTAR:
|
||||
if (input == INPUT_LEFT) {
|
||||
*aOpt->mChoice.mIndex = (*aOpt->mChoice.mIndex + 5) % (6);
|
||||
return RESULT_OK;
|
||||
}
|
||||
if (input == INPUT_RIGHT || input == INPUT_A) {
|
||||
*aOpt->mChoice.mIndex = (*aOpt->mChoice.mIndex + 1) % (6);
|
||||
return RESULT_OK;
|
||||
}
|
||||
break;
|
||||
|
||||
#ifndef DYNOS_COOP
|
||||
case DOPT_CHOICEPARAM:
|
||||
if (input == INPUT_LEFT) {
|
||||
*aOpt->mChoice.mIndex = (*aOpt->mChoice.mIndex + 4) % (5);
|
||||
return RESULT_OK;
|
||||
}
|
||||
if (input == INPUT_RIGHT || input == INPUT_A) {
|
||||
*aOpt->mChoice.mIndex = (*aOpt->mChoice.mIndex + 1) % (5);
|
||||
return RESULT_OK;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
case DOPT_SCROLL:
|
||||
if (input == INPUT_LEFT) {
|
||||
*aOpt->mScroll.mValue = MAX(aOpt->mScroll.mMin, *aOpt->mScroll.mValue - aOpt->mScroll.mStep * (gPlayer1Controller->buttonDown & A_BUTTON ? 5 : 1));
|
||||
return RESULT_OK;
|
||||
}
|
||||
if (input == INPUT_RIGHT) {
|
||||
*aOpt->mScroll.mValue = MIN(aOpt->mScroll.mMax, *aOpt->mScroll.mValue + aOpt->mScroll.mStep * (gPlayer1Controller->buttonDown & A_BUTTON ? 5 : 1));
|
||||
return RESULT_OK;
|
||||
}
|
||||
break;
|
||||
|
||||
case DOPT_BIND:
|
||||
if (input == INPUT_LEFT) {
|
||||
aOpt->mBind.mIndex = MAX(0, aOpt->mBind.mIndex - 1);
|
||||
return RESULT_OK;
|
||||
}
|
||||
if (input == INPUT_RIGHT) {
|
||||
aOpt->mBind.mIndex = MIN(2, aOpt->mBind.mIndex + 1);
|
||||
return RESULT_OK;
|
||||
}
|
||||
if (input == INPUT_Z) {
|
||||
aOpt->mBind.mBinds[aOpt->mBind.mIndex] = VK_INVALID;
|
||||
return RESULT_OK;
|
||||
}
|
||||
if (input == INPUT_A) {
|
||||
aOpt->mBind.mBinds[aOpt->mBind.mIndex] = VK_INVALID;
|
||||
sBindingState = 1;
|
||||
controller_get_raw_key();
|
||||
return RESULT_OK;
|
||||
}
|
||||
break;
|
||||
|
||||
case DOPT_BUTTON:
|
||||
if (input == INPUT_A) {
|
||||
DynosActionFunction _Action = DynOS_Opt_GetAction(aOpt->mButton.mFuncName);
|
||||
if (_Action != NULL && _Action(aOpt->mName.begin())) {
|
||||
return RESULT_OK;
|
||||
}
|
||||
return RESULT_CANCEL;
|
||||
}
|
||||
break;
|
||||
|
||||
case DOPT_SUBMENU:
|
||||
if (input == INPUT_A) {
|
||||
if (aOpt->mSubMenu.mChild != NULL) {
|
||||
sCurrentOpt = aOpt->mSubMenu.mChild;
|
||||
return RESULT_OK;
|
||||
}
|
||||
return RESULT_CANCEL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return RESULT_NONE;
|
||||
}
|
||||
|
||||
static void DynOS_Opt_Open(DynosOption *aMenu) {
|
||||
play_sound(SOUND_DYNOS_SELECT, gDefaultSoundArgs);
|
||||
sCurrentMenu = aMenu;
|
||||
sCurrentOpt = aMenu;
|
||||
}
|
||||
|
||||
static void DynOS_Opt_Close(bool aPlaySavedSfx) {
|
||||
if (sCurrentMenu != NULL) {
|
||||
if (aPlaySavedSfx) {
|
||||
play_sound(SOUND_DYNOS_SAVED, gDefaultSoundArgs);
|
||||
}
|
||||
#ifdef BETTERCAMERA
|
||||
newcam_init_settings();
|
||||
#endif
|
||||
controller_reconfigure();
|
||||
configfile_save(configfile_name());
|
||||
DynOS_Opt_SaveConfig(sDynosMenu);
|
||||
sCurrentMenu = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void DynOS_Opt_ProcessInputs() {
|
||||
static s32 sStickTimer = 0;
|
||||
static bool sPrevStick = 0;
|
||||
|
||||
// Stick values
|
||||
f32 _StickX = gPlayer1Controller->stickX;
|
||||
f32 _StickY = gPlayer1Controller->stickY;
|
||||
if (absx(_StickX) > 60 || absx(_StickY) > 60) {
|
||||
if (sStickTimer == 0) {
|
||||
sStickTimer = (sPrevStick ? 2 : 9);
|
||||
} else {
|
||||
_StickX = 0;
|
||||
_StickY = 0;
|
||||
sStickTimer--;
|
||||
}
|
||||
sPrevStick = true;
|
||||
} else {
|
||||
sStickTimer = 0;
|
||||
sPrevStick = false;
|
||||
}
|
||||
|
||||
// Key binding
|
||||
if (sBindingState != 0) {
|
||||
u32 _Key = (sCurrentOpt->mDynos ? (u32) DynOS_Opt_ControllerGetKeyPressed() : controller_get_raw_key());
|
||||
if (_Key != VK_INVALID) {
|
||||
play_sound(SOUND_DYNOS_SELECT, gDefaultSoundArgs);
|
||||
sCurrentOpt->mBind.mBinds[sCurrentOpt->mBind.mIndex] = _Key;
|
||||
sBindingState = false;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (sCurrentMenu != NULL) {
|
||||
|
||||
// Up
|
||||
if (_StickY > +60) {
|
||||
if (sCurrentOpt->mPrev != NULL) {
|
||||
sCurrentOpt = sCurrentOpt->mPrev;
|
||||
} else {
|
||||
while (sCurrentOpt->mNext) sCurrentOpt = sCurrentOpt->mNext;
|
||||
}
|
||||
play_sound(SOUND_DYNOS_SELECT, gDefaultSoundArgs);
|
||||
return;
|
||||
}
|
||||
|
||||
// Down
|
||||
if (_StickY < -60) {
|
||||
if (sCurrentOpt->mNext != NULL) {
|
||||
sCurrentOpt = sCurrentOpt->mNext;
|
||||
} else {
|
||||
while (sCurrentOpt->mPrev) sCurrentOpt = sCurrentOpt->mPrev;
|
||||
}
|
||||
play_sound(SOUND_DYNOS_SELECT, gDefaultSoundArgs);
|
||||
return;
|
||||
}
|
||||
|
||||
// Left
|
||||
if (_StickX < -60) {
|
||||
switch (DynOS_Opt_ProcessInput(sCurrentOpt, INPUT_LEFT)) {
|
||||
case RESULT_OK: play_sound(SOUND_DYNOS_OK, gDefaultSoundArgs); break;
|
||||
case RESULT_CANCEL: play_sound(SOUND_DYNOS_CANCEL, gDefaultSoundArgs); break;
|
||||
case RESULT_NONE: break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Right
|
||||
if (_StickX > +60) {
|
||||
switch (DynOS_Opt_ProcessInput(sCurrentOpt, INPUT_RIGHT)) {
|
||||
case RESULT_OK: play_sound(SOUND_DYNOS_OK, gDefaultSoundArgs); break;
|
||||
case RESULT_CANCEL: play_sound(SOUND_DYNOS_CANCEL, gDefaultSoundArgs); break;
|
||||
case RESULT_NONE: break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// A
|
||||
if (gPlayer1Controller->buttonPressed & A_BUTTON) {
|
||||
switch (DynOS_Opt_ProcessInput(sCurrentOpt, INPUT_A)) {
|
||||
case RESULT_OK: play_sound(SOUND_DYNOS_OK, gDefaultSoundArgs); break;
|
||||
case RESULT_CANCEL: play_sound(SOUND_DYNOS_CANCEL, gDefaultSoundArgs); break;
|
||||
case RESULT_NONE: break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// B
|
||||
if (gPlayer1Controller->buttonPressed & B_BUTTON) {
|
||||
if (sCurrentOpt->mParent != NULL) {
|
||||
sCurrentOpt = sCurrentOpt->mParent;
|
||||
play_sound(SOUND_DYNOS_SELECT, gDefaultSoundArgs);
|
||||
} else {
|
||||
DynOS_Opt_Close(true);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Z
|
||||
if (gPlayer1Controller->buttonPressed & Z_TRIG) {
|
||||
switch (DynOS_Opt_ProcessInput(sCurrentOpt, INPUT_Z)) {
|
||||
case RESULT_OK: play_sound(SOUND_DYNOS_OK, gDefaultSoundArgs); break;
|
||||
case RESULT_CANCEL: play_sound(SOUND_DYNOS_CANCEL, gDefaultSoundArgs); break;
|
||||
case RESULT_NONE:
|
||||
if (sCurrentMenu == sDynosMenu) {
|
||||
DynOS_Opt_Close(true);
|
||||
} else {
|
||||
DynOS_Opt_Open(sDynosMenu);
|
||||
} break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// R
|
||||
if (gPlayer1Controller->buttonPressed & R_TRIG) {
|
||||
if (sCurrentMenu == sOptionsMenu) {
|
||||
DynOS_Opt_Close(true);
|
||||
} else {
|
||||
DynOS_Opt_Open(sOptionsMenu);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Start
|
||||
if (gPlayer1Controller->buttonPressed & START_BUTTON) {
|
||||
DynOS_Opt_Close(true);
|
||||
return;
|
||||
}
|
||||
} else if (gPlayer1Controller->buttonPressed & R_TRIG) {
|
||||
DynOS_Opt_Open(sOptionsMenu);
|
||||
} else if (gPlayer1Controller->buttonPressed & Z_TRIG) {
|
||||
DynOS_Opt_Open(sDynosMenu);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Init
|
||||
//
|
||||
|
||||
static void DynOS_Opt_CreateWarpToLevelSubMenu() {
|
||||
DynOS_Opt_CreateSubMenu("dynos_warp_to_level_submenu", "Warp to Level", "WARP TO LEUEL");
|
||||
|
||||
// Level select
|
||||
{
|
||||
DynosOption *aOpt = DynOS_Opt_NewOption("dynos_warp_level", "", "Level Select", "");
|
||||
aOpt->mType = DOPT_CHOICELEVEL;
|
||||
aOpt->mChoice.mIndex = New<s32>();
|
||||
*aOpt->mChoice.mIndex = 0;
|
||||
}
|
||||
|
||||
// Area select
|
||||
{
|
||||
DynosOption *aOpt = DynOS_Opt_NewOption("dynos_warp_area", "", "Area Select", "");
|
||||
aOpt->mType = DOPT_CHOICEAREA;
|
||||
aOpt->mChoice.mIndex = New<s32>();
|
||||
*aOpt->mChoice.mIndex = 0;
|
||||
}
|
||||
|
||||
// Star select
|
||||
{
|
||||
DynosOption *aOpt = DynOS_Opt_NewOption("dynos_warp_act", "", "Star Select", "");
|
||||
aOpt->mType = DOPT_CHOICESTAR;
|
||||
aOpt->mChoice.mIndex = New<s32>();
|
||||
*aOpt->mChoice.mIndex = 0;
|
||||
}
|
||||
|
||||
#ifndef DYNOS_COOP
|
||||
// Param select
|
||||
{
|
||||
DynosOption *aOpt = DynOS_Opt_NewOption("dynos_warp_param", "", "Param Select", "");
|
||||
aOpt->mType = DOPT_CHOICEPARAM;
|
||||
aOpt->mChoice.mIndex = New<s32>();
|
||||
*aOpt->mChoice.mIndex = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
DynOS_Opt_CreateButton("dynos_warp_to_level", "Warp", "DynOS_Opt_WarpToLevel");
|
||||
DynOS_Opt_EndSubMenu();
|
||||
}
|
||||
|
||||
static void DynOS_Opt_CreateWarpToCastleSubMenu() {
|
||||
DynOS_Opt_CreateSubMenu("dynos_warp_to_castle_submenu", "Warp to Castle", "WARP TO CASTLE");
|
||||
|
||||
// Level select
|
||||
{
|
||||
DynosOption *aOpt = DynOS_Opt_NewOption("dynos_warp_castle", "", "Level Exit", "");
|
||||
aOpt->mType = DOPT_CHOICELEVEL;
|
||||
aOpt->mChoice.mIndex = New<s32>();
|
||||
*aOpt->mChoice.mIndex = 0;
|
||||
}
|
||||
|
||||
DynOS_Opt_CreateButton("dynos_warp_to_castle", "Warp", "DynOS_Opt_WarpToCastle");
|
||||
DynOS_Opt_EndSubMenu();
|
||||
}
|
||||
|
||||
static u32 DynOS_Opt_GetHash(const String& aStr) {
|
||||
u32 _Hash = 5381u;
|
||||
for (char c : aStr) { _Hash += c + (_Hash << 5); }
|
||||
return _Hash;
|
||||
}
|
||||
|
||||
static void DynOS_Opt_CreateModelPacksSubMenu() {
|
||||
Array<String> _Packs = DynOS_Gfx_Init();
|
||||
if (_Packs.Count() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
DynOS_Opt_CreateSubMenu("dynos_model_loader_submenu", "Model Packs", "MODEL PACKS");
|
||||
for (s32 i = 0; i != _Packs.Count(); ++i) {
|
||||
DynOS_Opt_CreateToggle(String("dynos_pack_%d", i), String("dynos_pack_%08X", DynOS_Opt_GetHash(_Packs[i])), _Packs[i], false);
|
||||
}
|
||||
DynOS_Opt_CreateButton("dynos_packs_disable_all", "Disable all packs", "DynOS_Opt_DisableAllPacks");
|
||||
DynOS_Opt_EndSubMenu();
|
||||
}
|
||||
|
||||
void DynOS_Opt_Init() {
|
||||
|
||||
// Convert options menu
|
||||
DynOS_Opt_InitVanilla(sOptionsMenu);
|
||||
|
||||
// Create DynOS menu
|
||||
DynOS_Opt_LoadOptions();
|
||||
|
||||
// Warp to level
|
||||
DynOS_Opt_CreateWarpToLevelSubMenu();
|
||||
|
||||
// Warp to castle
|
||||
DynOS_Opt_CreateWarpToCastleSubMenu();
|
||||
|
||||
// Restart level
|
||||
DynOS_Opt_CreateButton("dynos_restart_level", "Restart Level", "DynOS_Opt_RestartLevel");
|
||||
|
||||
// Exit level
|
||||
DynOS_Opt_CreateButton("dynos_exit_level", "Exit Level", "DynOS_Opt_ExitLevel");
|
||||
|
||||
#ifndef DYNOS_COOP
|
||||
// Return to main menu
|
||||
DynOS_Opt_CreateButton("dynos_return_to_main_menu", "Return to Main Menu", "DynOS_Opt_ReturnToMainMenu");
|
||||
#endif
|
||||
|
||||
// Model loader
|
||||
DynOS_Opt_CreateModelPacksSubMenu();
|
||||
|
||||
// Init config
|
||||
DynOS_Opt_LoadConfig(sDynosMenu);
|
||||
}
|
||||
|
||||
//
|
||||
// Update
|
||||
//
|
||||
|
||||
void DynOS_Opt_Update(OSContPad *aPad) {
|
||||
DynOS_Opt_Loop(sDynosMenu, DynOS_Opt_ControllerUpdate, (void *) aPad);
|
||||
if (DynOS_IsTransitionActive()) {
|
||||
aPad->button = 0;
|
||||
aPad->stick_x = 0;
|
||||
aPad->stick_y = 0;
|
||||
aPad->ext_stick_x = 0;
|
||||
aPad->ext_stick_y = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Hijack
|
||||
// This is C code
|
||||
//
|
||||
|
||||
extern "C" {
|
||||
|
||||
u8 optmenu_open = 0;
|
||||
|
||||
void optmenu_toggle(void) {
|
||||
DynOS_Opt_Close(false);
|
||||
optmenu_open = 0;
|
||||
}
|
||||
|
||||
void optmenu_draw(void) {
|
||||
DynOS_Opt_DrawMenu(sCurrentOpt, sCurrentMenu, sOptionsMenu, sDynosMenu);
|
||||
}
|
||||
|
||||
void optmenu_draw_prompt(void) {
|
||||
DynOS_Opt_DrawPrompt(sCurrentMenu, sOptionsMenu, sDynosMenu);
|
||||
DynOS_Opt_ProcessInputs();
|
||||
optmenu_open = (sCurrentMenu != NULL);
|
||||
}
|
||||
|
||||
void optmenu_check_buttons(void) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//
|
||||
// Built-in options
|
||||
//
|
||||
|
||||
#define DYNOS_DEFINE_ACTION(func) \
|
||||
DYNOS_AT_STARTUP static void DynOS_Opt_AddAction_##func() { \
|
||||
DynOS_Opt_AddAction(#func, func, false); \
|
||||
}
|
||||
|
||||
#ifndef DYNOS_COOP
|
||||
static bool DynOS_Opt_ReturnToMainMenu(UNUSED const char *optName) {
|
||||
DynOS_ReturnToMainMenu();
|
||||
return true;
|
||||
}
|
||||
DYNOS_DEFINE_ACTION(DynOS_Opt_ReturnToMainMenu);
|
||||
#endif
|
||||
|
||||
static bool DynOS_Opt_WarpToLevel(UNUSED const char *optName) {
|
||||
s32 _Level = DynOS_Level_GetList()[DynOS_Opt_GetValue("dynos_warp_level")];
|
||||
s32 _Area = DynOS_Opt_GetValue("dynos_warp_area") + 1;
|
||||
s32 _Act = DynOS_Opt_GetValue("dynos_warp_act") + 1;
|
||||
#ifdef DYNOS_COOP
|
||||
DynOS_Coop_SendCommand(DYNOS_COOP_COMMAND_WARP_TO_LEVEL, _Level, _Area, _Act);
|
||||
#endif
|
||||
return DynOS_Warp_ToLevel(_Level, _Area, _Act);
|
||||
}
|
||||
DYNOS_DEFINE_ACTION(DynOS_Opt_WarpToLevel);
|
||||
|
||||
static bool DynOS_Opt_WarpToCastle(UNUSED const char *optName) {
|
||||
s32 _Level = DynOS_Level_GetList()[DynOS_Opt_GetValue("dynos_warp_castle")];
|
||||
#ifdef DYNOS_COOP
|
||||
DynOS_Coop_SendCommand(DYNOS_COOP_COMMAND_WARP_TO_CASTLE, _Level, 0, 0);
|
||||
#endif
|
||||
return DynOS_Warp_ToCastle(_Level);
|
||||
}
|
||||
DYNOS_DEFINE_ACTION(DynOS_Opt_WarpToCastle);
|
||||
|
||||
static bool DynOS_Opt_RestartLevel(UNUSED const char *optName) {
|
||||
#ifdef DYNOS_COOP
|
||||
DynOS_Coop_SendCommand(DYNOS_COOP_COMMAND_RESTART_LEVEL, 0, 0, 0);
|
||||
#endif
|
||||
return DynOS_Warp_RestartLevel();
|
||||
}
|
||||
DYNOS_DEFINE_ACTION(DynOS_Opt_RestartLevel);
|
||||
|
||||
static bool DynOS_Opt_ExitLevel(UNUSED const char *optName) {
|
||||
#ifdef DYNOS_COOP
|
||||
DynOS_Coop_SendCommand(DYNOS_COOP_COMMAND_EXIT_LEVEL, 0, 0, 0);
|
||||
#endif
|
||||
return DynOS_Warp_ExitLevel(30);
|
||||
}
|
||||
DYNOS_DEFINE_ACTION(DynOS_Opt_ExitLevel);
|
||||
|
||||
static bool DynOS_Opt_DisableAllPacks(UNUSED const char *optName) {
|
||||
const Array<PackData *> &pDynosPacks = DynOS_Gfx_GetPacks();
|
||||
for (s32 i = 0; i != pDynosPacks.Count(); ++i) {
|
||||
DynOS_Opt_SetValue(String("dynos_pack_%d", i), false);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
DYNOS_DEFINE_ACTION(DynOS_Opt_DisableAllPacks);
|
||||
|
||||
#undef DYNOS_DEFINE_ACTION
|
|
@ -0,0 +1,62 @@
|
|||
#include "dynos.cpp.h"
|
||||
|
||||
extern DynosOption *DynOS_Opt_Loop(DynosOption *aOpt, DynosLoopFunc aFunc, void *aData);
|
||||
|
||||
static bool DynOS_Opt_ReadConfig(DynosOption *aOpt, void *aData) {
|
||||
return (aOpt->mConfigName == (const char *) aData);
|
||||
}
|
||||
|
||||
void DynOS_Opt_LoadConfig(DynosOption *aMenu) {
|
||||
SysPath _Filename = fstring("%s/%s", DYNOS_USER_FOLDER, DYNOS_CONFIG_FILENAME);
|
||||
FILE *_File = fopen(_Filename.c_str(), "r");
|
||||
if (_File) {
|
||||
char _Buffer[1024];
|
||||
while (fgets(_Buffer, 1024, _File)) {
|
||||
|
||||
// Option strings
|
||||
char *_NameBegin = _Buffer;
|
||||
char *_DataBegin = strchr(_NameBegin, '=');
|
||||
if (_NameBegin && _DataBegin) {
|
||||
*(_DataBegin++) = 0;
|
||||
|
||||
// Option name
|
||||
String _OptName = String(_NameBegin);
|
||||
DynosOption *_Opt = DynOS_Opt_Loop(aMenu, DynOS_Opt_ReadConfig, (void *) _OptName.begin());
|
||||
if (_Opt) {
|
||||
|
||||
// Option values
|
||||
switch (_Opt->mType) {
|
||||
case DOPT_TOGGLE: sscanf(_DataBegin, "%hhu\n", &_Opt->mToggle.mTog[0]); break;
|
||||
case DOPT_CHOICE: sscanf(_DataBegin, "%d\n", &_Opt->mChoice.mIndex[0]); break;
|
||||
case DOPT_SCROLL: sscanf(_DataBegin, "%d\n", &_Opt->mScroll.mValue[0]); break;
|
||||
case DOPT_BIND: sscanf(_DataBegin, "%04X;%04X;%04X\n", &_Opt->mBind.mBinds[0], &_Opt->mBind.mBinds[1], &_Opt->mBind.mBinds[2]); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
fclose(_File);
|
||||
}
|
||||
}
|
||||
|
||||
static bool DynOS_Opt_WriteConfig(DynosOption *aOpt, void *aData) {
|
||||
if (aOpt->mConfigName.Length() != 0 &&
|
||||
aOpt->mConfigName != "null" &&
|
||||
aOpt->mConfigName != "NULL") {
|
||||
switch (aOpt->mType) {
|
||||
case DOPT_TOGGLE: fprintf((FILE *) aData, "%s=%hhu\n", aOpt->mConfigName.begin(), aOpt->mToggle.mTog[0]); break;
|
||||
case DOPT_CHOICE: fprintf((FILE *) aData, "%s=%d\n", aOpt->mConfigName.begin(), aOpt->mChoice.mIndex[0]); break;
|
||||
case DOPT_SCROLL: fprintf((FILE *) aData, "%s=%d\n", aOpt->mConfigName.begin(), aOpt->mScroll.mValue[0]); break;
|
||||
case DOPT_BIND: fprintf((FILE *) aData, "%s=%04X;%04X;%04X\n", aOpt->mConfigName.begin(), aOpt->mBind.mBinds[0], aOpt->mBind.mBinds[1], aOpt->mBind.mBinds[2]); break;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void DynOS_Opt_SaveConfig(DynosOption *aMenu) {
|
||||
SysPath _Filename = fstring("%s/%s", DYNOS_USER_FOLDER, DYNOS_CONFIG_FILENAME);
|
||||
FILE *_File = fopen(_Filename.c_str(), "w");
|
||||
if (_File) {
|
||||
DynOS_Opt_Loop(aMenu, DynOS_Opt_WriteConfig, (void *) _File);
|
||||
fclose(_File);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
#include "dynos.cpp.h"
|
||||
extern "C" {
|
||||
#include "pc/controller/controller_api.h"
|
||||
}
|
||||
|
||||
static bool DynOS_Opt_ControllerIsKeyDown(s32 aCont, s32 aKey) {
|
||||
|
||||
// Keyboard
|
||||
if (aCont == 0 && aKey >= 0 && aKey < SDL_NUM_SCANCODES) {
|
||||
return SDL_GetKeyboardState(NULL)[aKey];
|
||||
}
|
||||
|
||||
// Game Controller
|
||||
else if (aKey >= 0x1000) {
|
||||
|
||||
// Button
|
||||
s32 _Button = (aKey - 0x1000);
|
||||
if (_Button < SDL_CONTROLLER_BUTTON_MAX) {
|
||||
return SDL_GameControllerGetButton(SDL_GameControllerOpen(aCont - 1), SDL_GameControllerButton(_Button));
|
||||
}
|
||||
|
||||
// Axis
|
||||
s32 _Axis = (aKey - 0x1000 - SDL_CONTROLLER_BUTTON_MAX);
|
||||
if (_Axis < SDL_CONTROLLER_AXIS_MAX * 2) {
|
||||
s32 _AxisValue = SDL_GameControllerGetAxis(SDL_GameControllerOpen(aCont - 1), SDL_GameControllerAxis(_Axis / 2));
|
||||
if (_Axis & 1) return (_AxisValue < (SHRT_MIN / 2));
|
||||
else return (_AxisValue > (SHRT_MAX / 2));
|
||||
}
|
||||
}
|
||||
// Invalid
|
||||
return false;
|
||||
}
|
||||
|
||||
#define MAX_CONTS 8
|
||||
bool DynOS_Opt_ControllerUpdate(DynosOption *aOpt, void *aData) {
|
||||
if (aOpt->mType == DOPT_BIND) {
|
||||
OSContPad *pad = (OSContPad *) aData;
|
||||
for (s32 _Cont = 0; _Cont < MAX_CONTS; ++_Cont)
|
||||
for (s32 _Bind = 0; _Bind < 3; ++_Bind) {
|
||||
pad->button |= aOpt->mBind.mMask * DynOS_Opt_ControllerIsKeyDown(_Cont, aOpt->mBind.mBinds[_Bind]);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#define MAX_GKEYS (SDL_CONTROLLER_BUTTON_MAX + SDL_CONTROLLER_AXIS_MAX * 2)
|
||||
s32 sBindingState = 0; // 0 = No bind, 1 = Wait for all keys released, 2 = Return first pressed key
|
||||
s32 DynOS_Opt_ControllerGetKeyPressed() {
|
||||
|
||||
// Keyboard
|
||||
for (s32 _Key = 0; _Key < SDL_NUM_SCANCODES; ++_Key) {
|
||||
if (DynOS_Opt_ControllerIsKeyDown(0, _Key)) {
|
||||
if (sBindingState == 1) return VK_INVALID;
|
||||
return _Key;
|
||||
}
|
||||
}
|
||||
|
||||
// Game Controller
|
||||
for (s32 _Cont = 1; _Cont < MAX_CONTS; ++_Cont)
|
||||
for (s32 _Key = 0; _Key < MAX_GKEYS; ++_Key) {
|
||||
if (DynOS_Opt_ControllerIsKeyDown(_Cont, _Key + 0x1000)) {
|
||||
if (sBindingState == 1) return VK_INVALID;
|
||||
return _Key + 0x1000;
|
||||
}
|
||||
}
|
||||
|
||||
// No key
|
||||
sBindingState = 2;
|
||||
return VK_INVALID;
|
||||
}
|
|
@ -0,0 +1,311 @@
|
|||
#include "dynos.cpp.h"
|
||||
extern "C" {
|
||||
#include "course_table.h"
|
||||
#include "game/game_init.h"
|
||||
#include "game/ingame_menu.h"
|
||||
#include "game/segment2.h"
|
||||
#include "pc/controller/controller_api.h"
|
||||
#include "gfx_dimensions.h"
|
||||
}
|
||||
|
||||
extern s32 sBindingState;
|
||||
|
||||
#define DYNOS_TEXT_DYNOS_MENU { "DYNOS MENU", NULL }
|
||||
#define DYNOS_TEXT_A { "([A]) >", NULL }
|
||||
#define DYNOS_TEXT_OPEN_LEFT { "[Z] DynOS", NULL }
|
||||
#define DYNOS_TEXT_CLOSE_LEFT { "[Z] Return", NULL }
|
||||
#define DYNOS_TEXT_OPTIONS_MENU { "OPTIONS", NULL }
|
||||
#define DYNOS_TEXT_DISABLED { "Disabled", NULL }
|
||||
#define DYNOS_TEXT_ENABLED { "Enabled", NULL }
|
||||
#define DYNOS_TEXT_NONE { "NONE", NULL }
|
||||
#define DYNOS_TEXT_DOT_DOT_DOT { "...", NULL }
|
||||
#define DYNOS_TEXT_OPEN_RIGHT { "[R] Options", NULL }
|
||||
#define DYNOS_TEXT_CLOSE_RIGHT { "[R] Return", NULL }
|
||||
|
||||
static void RenderString(const u8 *aStr64, s32 aX, s32 aY) {
|
||||
create_dl_translation_matrix(MENU_MTX_PUSH, aX, aY, 0);
|
||||
for (; *aStr64 != DIALOG_CHAR_TERMINATOR; ++aStr64) {
|
||||
if (*aStr64 != DIALOG_CHAR_SPACE) {
|
||||
void **fontLUT = (void **) segmented_to_virtual(main_font_lut);
|
||||
void *packedTexture = segmented_to_virtual(fontLUT[*aStr64]);
|
||||
gDPPipeSync(gDisplayListHead++);
|
||||
gDPSetTextureImage(gDisplayListHead++, G_IM_FMT_IA, G_IM_SIZ_16b, 1, VIRTUAL_TO_PHYSICAL(packedTexture));
|
||||
gSPDisplayList(gDisplayListHead++, dl_ia_text_tex_settings);
|
||||
}
|
||||
create_dl_translation_matrix(MENU_MTX_NOPUSH, DynOS_String_WidthChar64(*aStr64), 0, 0);
|
||||
}
|
||||
gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW);
|
||||
}
|
||||
|
||||
static void PrintString(const Label& aLabel, s32 aX, s32 aY, u32 aFrontColorRGBA, u32 aBackColorRGBA, bool aAlignLeft) {
|
||||
const u8 *_Str64 = (aLabel.second ? aLabel.second : DynOS_String_Convert(aLabel.first.begin(), false));
|
||||
|
||||
gSPDisplayList(gDisplayListHead++, dl_ia_text_begin);
|
||||
if ((aBackColorRGBA & 0xFF) != 0) {
|
||||
gDPSetEnvColor(gDisplayListHead++, ((aBackColorRGBA >> 24) & 0xFF), ((aBackColorRGBA >> 16) & 0xFF), ((aBackColorRGBA >> 8) & 0xFF), ((aBackColorRGBA >> 0) & 0xFF));
|
||||
if (aAlignLeft) {
|
||||
RenderString(_Str64, GFX_DIMENSIONS_FROM_LEFT_EDGE(aX) + 1, aY - 1);
|
||||
} else {
|
||||
RenderString(_Str64, GFX_DIMENSIONS_FROM_RIGHT_EDGE(aX + DynOS_String_Width(_Str64) - 1), aY - 1);
|
||||
}
|
||||
}
|
||||
if ((aFrontColorRGBA & 0xFF) != 0) {
|
||||
gDPSetEnvColor(gDisplayListHead++, ((aFrontColorRGBA >> 24) & 0xFF), ((aFrontColorRGBA >> 16) & 0xFF), ((aFrontColorRGBA >> 8) & 0xFF), ((aFrontColorRGBA >> 0) & 0xFF));
|
||||
if (aAlignLeft) {
|
||||
RenderString(_Str64, GFX_DIMENSIONS_FROM_LEFT_EDGE(aX), aY);
|
||||
} else {
|
||||
RenderString(_Str64, GFX_DIMENSIONS_FROM_RIGHT_EDGE(aX + DynOS_String_Width(_Str64)), aY);
|
||||
}
|
||||
}
|
||||
gSPDisplayList(gDisplayListHead++, dl_ia_text_end);
|
||||
gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, 255);
|
||||
}
|
||||
|
||||
static void PrintBox(s32 aX, s32 aY, s32 aWidth, s32 aHeight, u32 aColorRGBA, bool aAlignLeft) {
|
||||
if ((aColorRGBA && 0xFF) != 0) {
|
||||
Mtx *_Matrix = (Mtx *) alloc_display_list(sizeof(Mtx));
|
||||
if (!_Matrix) return;
|
||||
if (aAlignLeft) {
|
||||
create_dl_translation_matrix(MENU_MTX_PUSH, GFX_DIMENSIONS_FROM_LEFT_EDGE(aX), aY + aHeight, 0);
|
||||
} else {
|
||||
create_dl_translation_matrix(MENU_MTX_PUSH, GFX_DIMENSIONS_FROM_RIGHT_EDGE(aX + aWidth), aY + aHeight, 0);
|
||||
}
|
||||
guScale(_Matrix, (f32) aWidth / 130.f, (f32) aHeight / 80.f, 1.f);
|
||||
gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(_Matrix), G_MTX_MODELVIEW | G_MTX_MUL | G_MTX_NOPUSH);
|
||||
gDPSetEnvColor(gDisplayListHead++, ((aColorRGBA >> 24) & 0xFF), ((aColorRGBA >> 16) & 0xFF), ((aColorRGBA >> 8) & 0xFF), ((aColorRGBA >> 0) & 0xFF));
|
||||
gSPDisplayList(gDisplayListHead++, dl_draw_text_bg_box);
|
||||
gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW);
|
||||
gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, 255);
|
||||
}
|
||||
}
|
||||
|
||||
static const char *IntToString(const char *fmt, s32 x) {
|
||||
static char sBuffer[16];
|
||||
snprintf(sBuffer, 16, fmt, x);
|
||||
return sBuffer;
|
||||
}
|
||||
|
||||
#define get_label(opt) (opt->mLabel)
|
||||
#define get_title(opt) (opt->mTitle)
|
||||
#define get_choice(opt) (opt->mChoice.mChoices[*opt->mChoice.mIndex])
|
||||
#define get_dec_number(n) { "", DynOS_String_Convert(IntToString("%d", n), false) }
|
||||
#define get_hex_number(n) { "", DynOS_String_Convert(IntToString("%04X", n), false) }
|
||||
#define get_level(opt) { "", DynOS_Level_GetName(DynOS_Level_GetList()[*opt->mChoice.mIndex], true, true) }
|
||||
#define get_star(opt) { "", DynOS_Level_GetActName(DynOS_Level_GetList()[DynOS_Opt_GetValue("dynos_warp_level")], *opt->mChoice.mIndex + 1, true, true) }
|
||||
#define get_param(opt) { DynOS_Warp_GetParamName(DynOS_Level_GetList()[DynOS_Opt_GetValue("dynos_warp_level")], *opt->mChoice.mIndex), NULL }
|
||||
|
||||
static s32 GetCurrentOptionCount(DynosOption *aCurrentOpt) {
|
||||
s32 _Count = 0;
|
||||
while (aCurrentOpt->mPrev) { aCurrentOpt = aCurrentOpt->mPrev; }
|
||||
while (aCurrentOpt) { aCurrentOpt = aCurrentOpt->mNext; _Count++; }
|
||||
return _Count;
|
||||
}
|
||||
|
||||
static s32 GetCurrentOptionIndex(DynosOption *aCurrentOpt) {
|
||||
s32 _Index = 0;
|
||||
while (aCurrentOpt->mPrev) { aCurrentOpt = aCurrentOpt->mPrev; _Index++; }
|
||||
return _Index;
|
||||
}
|
||||
|
||||
#define PREV(opt) (opt == NULL ? NULL : opt->mPrev)
|
||||
#define NEXT(opt) (opt == NULL ? NULL : opt->mNext)
|
||||
static DynosOption **GetCurrentOptions(DynosOption *aCurrentOpt) {
|
||||
static DynosOption *sOptionList[13];
|
||||
|
||||
sOptionList[6] = aCurrentOpt;
|
||||
sOptionList[5] = PREV(sOptionList[6]);
|
||||
sOptionList[4] = PREV(sOptionList[5]);
|
||||
sOptionList[3] = PREV(sOptionList[4]);
|
||||
sOptionList[2] = PREV(sOptionList[3]);
|
||||
sOptionList[1] = PREV(sOptionList[2]);
|
||||
sOptionList[0] = PREV(sOptionList[1]);
|
||||
sOptionList[7] = NEXT(sOptionList[6]);
|
||||
sOptionList[8] = NEXT(sOptionList[7]);
|
||||
sOptionList[9] = NEXT(sOptionList[8]);
|
||||
sOptionList[10] = NEXT(sOptionList[9]);
|
||||
sOptionList[11] = NEXT(sOptionList[10]);
|
||||
sOptionList[12] = NEXT(sOptionList[11]);
|
||||
|
||||
s32 _StartIndex = 12, _EndIndex = 0;
|
||||
for (s32 i = 0; i != 13; ++i) {
|
||||
if (sOptionList[i] != NULL) {
|
||||
_StartIndex = MIN(_StartIndex, i);
|
||||
_EndIndex = MAX(_EndIndex, i);
|
||||
}
|
||||
}
|
||||
|
||||
if (_EndIndex - _StartIndex < 7) {
|
||||
return &sOptionList[_StartIndex];
|
||||
}
|
||||
if (_EndIndex <= 9) {
|
||||
return &sOptionList[_EndIndex - 6];
|
||||
}
|
||||
if (_StartIndex >= 3) {
|
||||
return &sOptionList[_StartIndex];
|
||||
}
|
||||
return &sOptionList[3];
|
||||
}
|
||||
#undef PREV
|
||||
#undef NEXT
|
||||
|
||||
#define COLOR_WHITE 0xFFFFFFFF
|
||||
#define COLOR_BLACK 0x000000FF
|
||||
#define COLOR_GRAY 0xA0A0A0FF
|
||||
#define COLOR_DARK_GRAY 0x808080FF
|
||||
#define COLOR_SELECT 0x80E0FFFF
|
||||
#define COLOR_SELECT_BOX 0x00FFFF20
|
||||
#define COLOR_ENABLED 0x20E020FF
|
||||
#define COLOR_DISABLED 0xFF2020FF
|
||||
#define OFFSET_FROM_LEFT_EDGE (20.f * sqr(GFX_DIMENSIONS_ASPECT_RATIO))
|
||||
#define OFFSET_FROM_RIGHT_EDGE (20.f * sqr(GFX_DIMENSIONS_ASPECT_RATIO))
|
||||
#define SCROLL_BAR_SIZE ((s32) (45.f * GFX_DIMENSIONS_ASPECT_RATIO))
|
||||
|
||||
static void DynOS_Opt_DrawOption(DynosOption *aOpt, DynosOption *aCurrentOpt, s32 aY) {
|
||||
if (aOpt == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Selected box
|
||||
if (aOpt == aCurrentOpt) {
|
||||
u8 _Alpha = (u8) ((coss(gGlobalTimer * 0x800) + 1.f) * 0x20);
|
||||
PrintBox(OFFSET_FROM_LEFT_EDGE - 4, aY - 2, GFX_DIMENSIONS_FROM_RIGHT_EDGE(OFFSET_FROM_RIGHT_EDGE) - GFX_DIMENSIONS_FROM_LEFT_EDGE(OFFSET_FROM_LEFT_EDGE) + 8, 20, COLOR_SELECT_BOX + _Alpha, 1);
|
||||
}
|
||||
|
||||
// Label
|
||||
if (aOpt == aCurrentOpt) {
|
||||
PrintString(get_label(aOpt), OFFSET_FROM_LEFT_EDGE, aY, COLOR_SELECT, COLOR_BLACK, 1);
|
||||
} else {
|
||||
PrintString(get_label(aOpt), OFFSET_FROM_LEFT_EDGE, aY, COLOR_WHITE, COLOR_BLACK, 1);
|
||||
}
|
||||
|
||||
// Values
|
||||
switch (aOpt->mType) {
|
||||
case DOPT_TOGGLE: {
|
||||
if (*aOpt->mToggle.mTog) {
|
||||
PrintString(DYNOS_TEXT_ENABLED, OFFSET_FROM_RIGHT_EDGE, aY, COLOR_ENABLED, COLOR_BLACK, 0);
|
||||
} else {
|
||||
PrintString(DYNOS_TEXT_DISABLED, OFFSET_FROM_RIGHT_EDGE, aY, COLOR_DISABLED, COLOR_BLACK, 0);
|
||||
}
|
||||
} break;
|
||||
|
||||
case DOPT_CHOICE: {
|
||||
PrintString(get_choice(aOpt), OFFSET_FROM_RIGHT_EDGE, aY, aOpt == aCurrentOpt ? COLOR_SELECT : COLOR_WHITE, COLOR_BLACK, 0);
|
||||
} break;
|
||||
|
||||
case DOPT_CHOICELEVEL: {
|
||||
PrintString(get_level(aOpt), OFFSET_FROM_RIGHT_EDGE, aY, aOpt == aCurrentOpt ? COLOR_SELECT : COLOR_WHITE, COLOR_BLACK, 0);
|
||||
} break;
|
||||
|
||||
case DOPT_CHOICEAREA: {
|
||||
s32 _Level = DynOS_Level_GetList()[DynOS_Opt_GetValue("dynos_warp_level")];
|
||||
s32 _Area = *aOpt->mChoice.mIndex + 1;
|
||||
const u8 *_Name = DynOS_Level_GetAreaName(_Level, _Area, true);
|
||||
if (DynOS_Level_GetWarpEntry(_Level, _Area)) {
|
||||
PrintString({ "", _Name }, OFFSET_FROM_RIGHT_EDGE, aY, aOpt == aCurrentOpt ? COLOR_SELECT : COLOR_WHITE, COLOR_BLACK, 0);
|
||||
} else {
|
||||
PrintString({ "", _Name }, OFFSET_FROM_RIGHT_EDGE, aY, COLOR_GRAY, COLOR_BLACK, 0);
|
||||
}
|
||||
} break;
|
||||
|
||||
case DOPT_CHOICESTAR: {
|
||||
s32 _Course = DynOS_Level_GetCourse(DynOS_Level_GetList()[DynOS_Opt_GetValue("dynos_warp_level")]);
|
||||
if (_Course >= COURSE_MIN && _Course <= COURSE_STAGES_MAX) {
|
||||
PrintString(get_star(aOpt), OFFSET_FROM_RIGHT_EDGE, aY, aOpt == aCurrentOpt ? COLOR_SELECT : COLOR_WHITE, COLOR_BLACK, 0);
|
||||
}
|
||||
} break;
|
||||
|
||||
#ifndef DYNOS_COOP
|
||||
case DOPT_CHOICEPARAM: {
|
||||
PrintString(get_param(aOpt), OFFSET_FROM_RIGHT_EDGE, aY, aOpt == aCurrentOpt ? COLOR_SELECT : COLOR_WHITE, COLOR_BLACK, 0);
|
||||
} break;
|
||||
#endif
|
||||
|
||||
case DOPT_SCROLL: {
|
||||
s32 _Width = (s32) (SCROLL_BAR_SIZE * (f32) (*aOpt->mScroll.mValue - aOpt->mScroll.mMin) / (f32) (aOpt->mScroll.mMax - aOpt->mScroll.mMin));
|
||||
PrintString(get_dec_number(*aOpt->mScroll.mValue), OFFSET_FROM_RIGHT_EDGE, aY, aOpt == aCurrentOpt ? COLOR_SELECT : COLOR_WHITE, COLOR_BLACK, 0);
|
||||
PrintBox(OFFSET_FROM_RIGHT_EDGE + 28, aY + 4, SCROLL_BAR_SIZE + 2, 8, COLOR_DARK_GRAY, 0);
|
||||
PrintBox(OFFSET_FROM_RIGHT_EDGE + 29 + SCROLL_BAR_SIZE - _Width, aY + 5, _Width, 6, aOpt == aCurrentOpt ? COLOR_SELECT : COLOR_WHITE, 0);
|
||||
} break;
|
||||
|
||||
case DOPT_BIND: {
|
||||
for (s32 i = 0; i != 3; ++i) {
|
||||
u32 _Bind = aOpt->mBind.mBinds[i];
|
||||
if (aOpt == aCurrentOpt && i == aOpt->mBind.mIndex) {
|
||||
if (sBindingState != 0) {
|
||||
PrintString(DYNOS_TEXT_DOT_DOT_DOT, OFFSET_FROM_RIGHT_EDGE + (2 - i) * 36, aY, COLOR_SELECT, COLOR_BLACK, 0);
|
||||
} else if (_Bind == VK_INVALID) {
|
||||
PrintString(DYNOS_TEXT_NONE, OFFSET_FROM_RIGHT_EDGE + (2 - i) * 36, aY, COLOR_SELECT, COLOR_BLACK, 0);
|
||||
} else {
|
||||
PrintString(get_hex_number(_Bind), OFFSET_FROM_RIGHT_EDGE + (2 - i) * 36, aY, COLOR_SELECT, COLOR_BLACK, 0);
|
||||
}
|
||||
} else {
|
||||
if (_Bind == VK_INVALID) {
|
||||
PrintString(DYNOS_TEXT_NONE, OFFSET_FROM_RIGHT_EDGE + (2 - i) * 36, aY, COLOR_GRAY, COLOR_BLACK, 0);
|
||||
} else {
|
||||
PrintString(get_hex_number(_Bind), OFFSET_FROM_RIGHT_EDGE + (2 - i) * 36, aY, COLOR_WHITE, COLOR_BLACK, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
} break;
|
||||
|
||||
case DOPT_BUTTON: {
|
||||
} break;
|
||||
|
||||
case DOPT_SUBMENU: {
|
||||
if (aOpt == aCurrentOpt) {
|
||||
PrintString(DYNOS_TEXT_A, OFFSET_FROM_RIGHT_EDGE, aY, COLOR_SELECT, COLOR_BLACK, 0);
|
||||
}
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void DynOS_Opt_DrawMenu(DynosOption *aCurrentOption, DynosOption *aCurrentMenu, DynosOption *aOptionsMenu, DynosOption *aDynosMenu) {
|
||||
if (aCurrentMenu == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Colorful label
|
||||
Label _Title;
|
||||
if (aCurrentOption->mParent) {
|
||||
_Title = get_title(aCurrentOption->mParent);
|
||||
} else if (aCurrentMenu == aDynosMenu) {
|
||||
_Title = DYNOS_TEXT_DYNOS_MENU;
|
||||
} else if (aCurrentMenu == aOptionsMenu) {
|
||||
_Title = DYNOS_TEXT_OPTIONS_MENU;
|
||||
}
|
||||
gSPDisplayList(gDisplayListHead++, dl_rgba16_text_begin);
|
||||
gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, 255);
|
||||
if (!_Title.second) _Title.second = DynOS_String_Convert(_Title.first.begin(), false);
|
||||
print_hud_lut_string(HUD_LUT_GLOBAL, (SCREEN_WIDTH / 2 - DynOS_String_Length(_Title.second) * 6), 40, _Title.second);
|
||||
gSPDisplayList(gDisplayListHead++, dl_rgba16_text_end);
|
||||
|
||||
// Display options
|
||||
DynosOption **_Options = GetCurrentOptions(aCurrentOption);
|
||||
for (s32 i = 0; i != 7; ++i) {
|
||||
DynOS_Opt_DrawOption(_Options[i], aCurrentOption, 156 - 20 * i);
|
||||
}
|
||||
|
||||
// Scroll bar
|
||||
s32 _OptCount = GetCurrentOptionCount(aCurrentOption);
|
||||
s32 _OptIndex = GetCurrentOptionIndex(aCurrentOption);
|
||||
if (_OptCount > 7) {
|
||||
s32 _Height = (s32) (134.f * sqrtf(1.f / (_OptCount - 6)));
|
||||
s32 _Y = 37 + (134 - _Height) * (1.f - MAX(0.f, MIN(1.f, (f32)(_OptIndex - 3) / (f32)(_OptCount - 6))));
|
||||
PrintBox(OFFSET_FROM_RIGHT_EDGE - 16, 36, 8, 136, COLOR_DARK_GRAY, 0);
|
||||
PrintBox(OFFSET_FROM_RIGHT_EDGE - 15, _Y, 6, _Height, COLOR_WHITE, 0);
|
||||
}
|
||||
}
|
||||
|
||||
#define PROMPT_OFFSET (56.25f * GFX_DIMENSIONS_ASPECT_RATIO)
|
||||
void DynOS_Opt_DrawPrompt(DynosOption *aCurrentMenu, DynosOption *aOptionsMenu, DynosOption *aDynosMenu) {
|
||||
if (aCurrentMenu == aOptionsMenu) {
|
||||
PrintString(DYNOS_TEXT_OPEN_LEFT, PROMPT_OFFSET, 212, COLOR_WHITE, COLOR_BLACK, 1);
|
||||
PrintString(DYNOS_TEXT_CLOSE_RIGHT, PROMPT_OFFSET, 212, COLOR_WHITE, COLOR_BLACK, 0);
|
||||
} else if (aCurrentMenu == aDynosMenu) {
|
||||
PrintString(DYNOS_TEXT_CLOSE_LEFT, PROMPT_OFFSET, 212, COLOR_WHITE, COLOR_BLACK, 1);
|
||||
PrintString(DYNOS_TEXT_OPEN_RIGHT, PROMPT_OFFSET, 212, COLOR_WHITE, COLOR_BLACK, 0);
|
||||
} else {
|
||||
PrintString(DYNOS_TEXT_OPEN_LEFT, PROMPT_OFFSET, 212, COLOR_WHITE, COLOR_BLACK, 1);
|
||||
PrintString(DYNOS_TEXT_OPEN_RIGHT, PROMPT_OFFSET, 212, COLOR_WHITE, COLOR_BLACK, 0);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,155 @@
|
|||
#include "dynos.cpp.h"
|
||||
|
||||
static DynosOption *sPrevOpt = NULL;
|
||||
static DynosOption *sOptionsMenu = NULL;
|
||||
|
||||
//
|
||||
// Vanilla actions
|
||||
//
|
||||
|
||||
typedef void (*VanillaActionFunction)(struct Option *, s32);
|
||||
typedef struct VanillaAction {
|
||||
String mFuncName;
|
||||
VanillaActionFunction mAction;
|
||||
} VanillaAction;
|
||||
|
||||
STATIC_STORAGE(Array<VanillaAction *>, VanillaActions);
|
||||
#define sVanillaActions __VanillaActions()
|
||||
|
||||
static VanillaActionFunction DynOS_Opt_GetVanillaAction(const String& aFuncName) {
|
||||
for (auto &_DynosAction : sVanillaActions) {
|
||||
if (_DynosAction->mFuncName == aFuncName) {
|
||||
return _DynosAction->mAction;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void DynOS_Opt_AddVanillaAction(const String& aFuncName, void (*aFuncPtr)(struct Option *, s32)) {
|
||||
for (auto &_DynosAction : sVanillaActions) {
|
||||
if (_DynosAction->mFuncName == aFuncName) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
VanillaAction *_DynosAction = New<VanillaAction>();
|
||||
_DynosAction->mFuncName = aFuncName;
|
||||
_DynosAction->mAction = aFuncPtr;
|
||||
sVanillaActions.Add(_DynosAction);
|
||||
}
|
||||
|
||||
static bool DynOS_Opt_CallVanillaAction(const char *aOptName) {
|
||||
VanillaActionFunction _Func = DynOS_Opt_GetVanillaAction(aOptName);
|
||||
if (_Func) {
|
||||
_Func(NULL, 0);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//
|
||||
// Convert classic options menu into DynOS menu
|
||||
//
|
||||
|
||||
static DynosOption *DynOS_Opt_ConvertOption(const u8 *aLabel, const u8 *aTitle) {
|
||||
static u32 sOptIdx = 0;
|
||||
DynosOption *_Opt = New<DynosOption>();
|
||||
_Opt->mName = String("vanilla_opt_%08X", sOptIdx++);
|
||||
_Opt->mConfigName = "";
|
||||
_Opt->mLabel = { "", aLabel };
|
||||
_Opt->mTitle = { "", aTitle };
|
||||
_Opt->mDynos = false;
|
||||
if (sPrevOpt == NULL) { // The very first option
|
||||
_Opt->mPrev = NULL;
|
||||
_Opt->mNext = NULL;
|
||||
_Opt->mParent = NULL;
|
||||
sOptionsMenu = _Opt;
|
||||
} else {
|
||||
if (sPrevOpt->mType == DOPT_SUBMENU && sPrevOpt->mSubMenu.mEmpty) { // First option of a sub-menu
|
||||
_Opt->mPrev = NULL;
|
||||
_Opt->mNext = NULL;
|
||||
_Opt->mParent = sPrevOpt;
|
||||
sPrevOpt->mSubMenu.mChild = _Opt;
|
||||
sPrevOpt->mSubMenu.mEmpty = false;
|
||||
} else {
|
||||
_Opt->mPrev = sPrevOpt;
|
||||
_Opt->mNext = NULL;
|
||||
_Opt->mParent = sPrevOpt->mParent;
|
||||
sPrevOpt->mNext = _Opt;
|
||||
}
|
||||
}
|
||||
sPrevOpt = _Opt;
|
||||
return _Opt;
|
||||
}
|
||||
|
||||
static void DynOS_Opt_EndSubMenu() {
|
||||
if (sPrevOpt) {
|
||||
if (sPrevOpt->mType == DOPT_SUBMENU && sPrevOpt->mSubMenu.mEmpty) { // ENDMENU command following a SUBMENU command
|
||||
sPrevOpt->mSubMenu.mEmpty = false;
|
||||
} else {
|
||||
sPrevOpt = sPrevOpt->mParent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void DynOS_Opt_ConvertSubMenu(const u8 *aLabel, const u8 *aTitle) {
|
||||
DynosOption *_Opt = DynOS_Opt_ConvertOption(aLabel, aTitle);
|
||||
_Opt->mType = DOPT_SUBMENU;
|
||||
_Opt->mSubMenu.mChild = NULL;
|
||||
_Opt->mSubMenu.mEmpty = true;
|
||||
}
|
||||
|
||||
static void DynOS_Opt_ConvertToggle(const u8 *aLabel, bool *pValue) {
|
||||
DynosOption *_Opt = DynOS_Opt_ConvertOption(aLabel, aLabel);
|
||||
_Opt->mType = DOPT_TOGGLE;
|
||||
_Opt->mToggle.mTog = (bool *) pValue;
|
||||
}
|
||||
|
||||
static void DynOS_Opt_ConvertScroll(const u8 *aLabel, s32 aMin, s32 aMax, s32 aStep, u32 *pValue) {
|
||||
DynosOption *_Opt = DynOS_Opt_ConvertOption(aLabel, aLabel);
|
||||
_Opt->mType = DOPT_SCROLL;
|
||||
_Opt->mScroll.mMin = aMin;
|
||||
_Opt->mScroll.mMax = aMax;
|
||||
_Opt->mScroll.mStep = aStep;
|
||||
_Opt->mScroll.mValue = (s32 *) pValue;
|
||||
}
|
||||
|
||||
static void DynOS_Opt_ConvertChoice(const u8 *aLabel, const u8 **aChoices, s32 aCount, u32 *pValue) {
|
||||
DynosOption *_Opt = DynOS_Opt_ConvertOption(aLabel, aLabel);
|
||||
_Opt->mType = DOPT_CHOICE;
|
||||
_Opt->mChoice.mIndex = (s32 *) pValue;
|
||||
for (s32 i = 0; i != aCount; ++i) {
|
||||
_Opt->mChoice.mChoices.Add({ "", aChoices[i] });
|
||||
}
|
||||
}
|
||||
|
||||
static void DynOS_Opt_ConvertButton(const u8 *aLabel, VanillaActionFunction aAction) {
|
||||
DynosOption *_Opt = DynOS_Opt_ConvertOption(aLabel, aLabel);
|
||||
_Opt->mType = DOPT_BUTTON;
|
||||
_Opt->mButton.mFuncName = "DynOS_Opt_CallVanillaAction";
|
||||
DynOS_Opt_AddVanillaAction(_Opt->mName, aAction);
|
||||
}
|
||||
|
||||
static void DynOS_Opt_ConvertBind(const u8 *aLabel, u32 *pBinds) {
|
||||
DynosOption *_Opt = DynOS_Opt_ConvertOption(aLabel, aLabel);
|
||||
_Opt->mType = DOPT_BIND;
|
||||
_Opt->mBind.mMask = 0;
|
||||
_Opt->mBind.mBinds = pBinds;
|
||||
_Opt->mBind.mIndex = 0;
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
extern void dynos_opt_convert_vanilla_main_menu();
|
||||
void dynos_opt_end_submenu() { return DynOS_Opt_EndSubMenu(); }
|
||||
void dynos_opt_convert_submenu(const u8 *label, const u8 *title) { return DynOS_Opt_ConvertSubMenu(label, title); }
|
||||
void dynos_opt_convert_toggle(const u8 *label, bool *bval) { return DynOS_Opt_ConvertToggle(label, bval); }
|
||||
void dynos_opt_convert_scroll(const u8 *label, s32 min, s32 max, s32 step, u32 *uval) { return DynOS_Opt_ConvertScroll(label, min, max, step, uval); }
|
||||
void dynos_opt_convert_choice(const u8 *label, const u8 **choices, s32 numChoices, u32 *uval) { return DynOS_Opt_ConvertChoice(label, choices, numChoices, uval); }
|
||||
void dynos_opt_convert_button(const u8 *label, void *action) { return DynOS_Opt_ConvertButton(label, (VanillaActionFunction) action); }
|
||||
void dynos_opt_convert_bind(const u8 *label, u32 *uval) { return DynOS_Opt_ConvertBind(label, uval); }
|
||||
}
|
||||
void DynOS_Opt_InitVanilla(DynosOption *&aOptionsMenu) {
|
||||
sPrevOpt = NULL;
|
||||
dynos_opt_convert_vanilla_main_menu();
|
||||
DynOS_Opt_AddAction("DynOS_Opt_CallVanillaAction", DynOS_Opt_CallVanillaAction, true);
|
||||
aOptionsMenu = sOptionsMenu;
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
#include "dynos.c.h"
|
||||
|
||||
// Not my problem
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wsizeof-pointer-div"
|
||||
#pragma GCC diagnostic ignored "-Wdiscarded-qualifiers"
|
||||
#pragma GCC diagnostic ignored "-Wpointer-sign"
|
||||
#pragma GCC diagnostic ignored "-Wsign-compare"
|
||||
#define optmenu_toggle optmenu_toggle_unused
|
||||
#define optmenu_draw optmenu_draw_unused
|
||||
#define optmenu_draw_prompt optmenu_draw_prompt_unused
|
||||
#define optmenu_check_buttons optmenu_check_buttons_unused
|
||||
#define optmenu_open optmenu_open_unused
|
||||
#define DYNOS_INL
|
||||
#include "game/options_menu.c"
|
||||
#undef DYNOS_INL
|
||||
#undef optmenu_toggle
|
||||
#undef optmenu_draw
|
||||
#undef optmenu_draw_prompt
|
||||
#undef optmenu_check_buttons
|
||||
#undef optmenu_open
|
||||
#pragma GCC diagnostic pop
|
||||
// Now, that's my problem
|
||||
|
||||
extern void dynos_opt_end_submenu();
|
||||
extern void dynos_opt_convert_submenu(const u8 *label, const u8 *title);
|
||||
extern void dynos_opt_convert_toggle(const u8 *label, bool *bval);
|
||||
extern void dynos_opt_convert_scroll(const u8 *label, s32 min, s32 max, s32 step, u32 *uval);
|
||||
extern void dynos_opt_convert_choice(const u8 *label, const u8 **choices, s32 numChoices, u32 *uval);
|
||||
extern void dynos_opt_convert_button(const u8 *label, void *action);
|
||||
extern void dynos_opt_convert_bind(const u8 *label, u32 *uval);
|
||||
|
||||
static void dynos_opt_convert_menu(struct SubMenu *submenu) {
|
||||
for (s32 i = 0; i != submenu->numOpts; ++i) {
|
||||
struct Option *opt = &submenu->opts[i];
|
||||
switch (opt->type) {
|
||||
case OPT_TOGGLE:
|
||||
dynos_opt_convert_toggle(opt->label, opt->bval);
|
||||
break;
|
||||
|
||||
case OPT_CHOICE:
|
||||
dynos_opt_convert_choice(opt->label, opt->choices, opt->numChoices, opt->uval);
|
||||
break;
|
||||
|
||||
case OPT_SCROLL:
|
||||
dynos_opt_convert_scroll(opt->label, opt->scrMin, opt->scrMax, opt->scrStep, opt->uval);
|
||||
break;
|
||||
|
||||
case OPT_SUBMENU:
|
||||
dynos_opt_convert_submenu(opt->label, opt->nextMenu->label);
|
||||
dynos_opt_convert_menu(opt->nextMenu);
|
||||
dynos_opt_end_submenu();
|
||||
break;
|
||||
|
||||
case OPT_BIND:
|
||||
dynos_opt_convert_bind(opt->label, opt->uval);
|
||||
break;
|
||||
|
||||
case OPT_BUTTON:
|
||||
dynos_opt_convert_button(opt->label, opt->actionFn);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void dynos_opt_convert_vanilla_main_menu() {
|
||||
dynos_opt_convert_menu(&menuMain);
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
#include "dynos.c.h"
|
||||
#include "audio/internal.h"
|
||||
#include "engine/graph_node.h"
|
||||
|
||||
bool dynos_sanity_check_geo(s16 graphNodeType) {
|
||||
return
|
||||
(graphNodeType == GRAPH_NODE_TYPE_ROOT) ||
|
||||
(graphNodeType == GRAPH_NODE_TYPE_ORTHO_PROJECTION) ||
|
||||
(graphNodeType == GRAPH_NODE_TYPE_PERSPECTIVE) ||
|
||||
(graphNodeType == GRAPH_NODE_TYPE_MASTER_LIST) ||
|
||||
(graphNodeType == GRAPH_NODE_TYPE_START) ||
|
||||
(graphNodeType == GRAPH_NODE_TYPE_LEVEL_OF_DETAIL) ||
|
||||
(graphNodeType == GRAPH_NODE_TYPE_SWITCH_CASE) ||
|
||||
(graphNodeType == GRAPH_NODE_TYPE_CAMERA) ||
|
||||
(graphNodeType == GRAPH_NODE_TYPE_TRANSLATION_ROTATION) ||
|
||||
(graphNodeType == GRAPH_NODE_TYPE_TRANSLATION) ||
|
||||
(graphNodeType == GRAPH_NODE_TYPE_ROTATION) ||
|
||||
(graphNodeType == GRAPH_NODE_TYPE_OBJECT) ||
|
||||
(graphNodeType == GRAPH_NODE_TYPE_ANIMATED_PART) ||
|
||||
(graphNodeType == GRAPH_NODE_TYPE_BILLBOARD) ||
|
||||
(graphNodeType == GRAPH_NODE_TYPE_DISPLAY_LIST) ||
|
||||
(graphNodeType == GRAPH_NODE_TYPE_SCALE) ||
|
||||
(graphNodeType == GRAPH_NODE_TYPE_SHADOW) ||
|
||||
(graphNodeType == GRAPH_NODE_TYPE_OBJECT_PARENT) ||
|
||||
(graphNodeType == GRAPH_NODE_TYPE_GENERATED_LIST) ||
|
||||
(graphNodeType == GRAPH_NODE_TYPE_BACKGROUND) ||
|
||||
(graphNodeType == GRAPH_NODE_TYPE_HELD_OBJ) ||
|
||||
(graphNodeType == GRAPH_NODE_TYPE_CULLING_RADIUS);
|
||||
}
|
||||
|
||||
bool dynos_sanity_check_seq(u8 loBits) {
|
||||
return
|
||||
(loBits < LAYERS_MAX);
|
||||
}
|
|
@ -0,0 +1,475 @@
|
|||
#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"
|
||||
#include "game/options_menu.h"
|
||||
extern s8 gDialogBoxState;
|
||||
extern s16 gMenuMode;
|
||||
extern s32 gWdwWaterLevelSet;
|
||||
extern const u8 sSpawnTypeFromWarpBhv[];
|
||||
extern void set_mario_initial_action(struct MarioState *, u32, u32);
|
||||
extern void set_play_mode(s16);
|
||||
}
|
||||
|
||||
//
|
||||
// Data
|
||||
//
|
||||
|
||||
#ifndef DYNOS_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
|
||||
optmenu_toggle();
|
||||
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
|
||||
optmenu_toggle();
|
||||
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
|
||||
//
|
||||
|
||||
#ifndef DYNOS_COOP
|
||||
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;
|
||||
}
|
||||
|
||||
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
|
||||
optmenu_toggle();
|
||||
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;
|
||||
#ifndef DYNOS_COOP
|
||||
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 DYNOS_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;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
#ifndef DYNOS_COOP
|
||||
// Reset DDD settings to default
|
||||
if (gCurrCourseNum == COURSE_NONE) {
|
||||
gDDDBowsersSub = -1;
|
||||
gDDDPoles = -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
return NULL;
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
# ----------------------
|
||||
# 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
|
||||
|
||||
$(BUILD_DIR)/data/dynos_opt_vanilla_c.o: $(BUILD_DIR)/include/text_strings.h
|
||||
|
||||
# ----
|
||||
# Coop
|
||||
# ----
|
||||
|
||||
SM64EX_COOP := $(or $(and $(wildcard src/pc/network/network.h),1),0)
|
||||
ifeq ($(SM64EX_COOP),1)
|
||||
INCLUDE_CFLAGS += -DDYNOS_COOP
|
||||
endif
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
# Dynamic Options System aka DynOS v0.4
|
||||
# By PeachyPeach
|
||||
#
|
||||
# This is a comment
|
||||
# Here are the available commands:
|
||||
# SUBMENU [Name] [Label] [Label2]
|
||||
# TOGGLE [Name] [Label] [ConfigName] [InitialValue]
|
||||
# SCROLL [Name] [Label] [ConfigName] [InitialValue] [Min] [Max] [Step]
|
||||
# CHOICE [Name] [Label] [ConfigName] [InitialValue] [ChoiceStrings...]
|
||||
# BIND [Name] [Label] [ConfigName] [Mask] [DefaultValues]
|
||||
# BUTTON [Name] [Label] [FuncName]
|
||||
# ENDMENU
|
||||
#
|
||||
# Valid Label characters:
|
||||
# 0-9 A-Z a-z
|
||||
# '.,-()&:!%?"~_
|
||||
#
|
||||
|
||||
|
||||
SUBMENU "cheater_submenu" "CHEATER" "CHEATER"
|
||||
TOGGLE "chaos_mode" "CHAOS MODE" "chaos_mode" 0
|
||||
BIND "time_button" "Time Stop Button" "time_button" 0x0080 0x0008 0x1001 0xFFFF
|
||||
SUBMENU "che_submenu" "New Cheats!" "CHEATER"
|
||||
TOGGLE "no_heavy" "No Hold Heavy" "no_heavy" 0
|
||||
TOGGLE "swim_any" "Swim Anywhere" "swim_any" 0
|
||||
TOGGLE "haz_walk" "Walk On Hazards" "haz_walk" 0
|
||||
TOGGLE "coin_mag" "Coin Magnet" "coin_mag" 0
|
||||
SCROLL "spl" "Spamba Per Level" "spl" 0 0 7 1
|
||||
ENDMENU
|
||||
SUBMENU "wat_submenu" "Drain JRB?" "CHEATER"
|
||||
TOGGLE "wat_con" "Water Control" "wat_con" 0
|
||||
SCROLL "wat_lev" "Water Level (9)" "wat_lev" 0 1 20 1
|
||||
ENDMENU
|
||||
ENDMENU
|
|
@ -0,0 +1,234 @@
|
|||
/* Copyright (C) 1991-2017 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the GNU C Library; if not, see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
/*
|
||||
* ISO C99 Standard: 7.23 Date and time <time.h>
|
||||
*/
|
||||
#ifndef _TIME_H
|
||||
#define _TIME_H 1
|
||||
#include <features.h>
|
||||
#define __need_size_t
|
||||
#define __need_NULL
|
||||
#include <stddef.h>
|
||||
/* This defines CLOCKS_PER_SEC, which is the number of processor clock
|
||||
ticks per second, and possibly a number of other constants. */
|
||||
#include <bits/time.h>
|
||||
/* Many of the typedefs and structs whose official home is this header
|
||||
may also need to be defined by other headers. */
|
||||
#include <bits/types/clock_t.h>
|
||||
#include <bits/types/time_t.h>
|
||||
#include <bits/types/struct_tm.h>
|
||||
#if defined __USE_POSIX199309 || defined __USE_ISOC11
|
||||
# include <bits/types/struct_timespec.h>
|
||||
#endif
|
||||
#ifdef __USE_POSIX199309
|
||||
# include <bits/types/clockid_t.h>
|
||||
# include <bits/types/timer_t.h>
|
||||
# include <bits/types/struct_itimerspec.h>
|
||||
struct sigevent;
|
||||
#endif
|
||||
#ifdef __USE_XOPEN2K
|
||||
# ifndef __pid_t_defined
|
||||
typedef __pid_t pid_t;
|
||||
# define __pid_t_defined
|
||||
# endif
|
||||
#endif
|
||||
#ifdef __USE_XOPEN2K8
|
||||
# include <bits/types/locale_t.h>
|
||||
#endif
|
||||
#ifdef __USE_ISOC11
|
||||
/* Time base values for timespec_get. */
|
||||
# define TIME_UTC 1
|
||||
#endif
|
||||
__BEGIN_DECLS
|
||||
/* Time used by the program so far (user time + system time).
|
||||
The result / CLOCKS_PER_SECOND is program time in seconds. */
|
||||
extern clock_t clock (void) __THROW;
|
||||
/* Return the current time and put it in *TIMER if TIMER is not NULL. */
|
||||
extern time_t time (time_t *__timer) __THROW;
|
||||
/* Return the difference between TIME1 and TIME0. */
|
||||
extern double difftime (time_t __time1, time_t __time0)
|
||||
__THROW __attribute__ ((__const__));
|
||||
/* Return the `time_t' representation of TP and normalize TP. */
|
||||
extern time_t mktime (struct tm *__tp) __THROW;
|
||||
/* Format TP into S according to FORMAT.
|
||||
Write no more than MAXSIZE characters and return the number
|
||||
of characters written, or 0 if it would exceed MAXSIZE. */
|
||||
extern size_t strftime (char *__restrict __s, size_t __maxsize,
|
||||
const char *__restrict __format,
|
||||
const struct tm *__restrict __tp) __THROW;
|
||||
#ifdef __USE_XOPEN
|
||||
/* Parse S according to FORMAT and store binary time information in TP.
|
||||
The return value is a pointer to the first unparsed character in S. */
|
||||
extern char *strptime (const char *__restrict __s,
|
||||
const char *__restrict __fmt, struct tm *__tp)
|
||||
__THROW;
|
||||
#endif
|
||||
#ifdef __USE_XOPEN2K8
|
||||
/* Similar to the two functions above but take the information from
|
||||
the provided locale and not the global locale. */
|
||||
extern size_t strftime_l (char *__restrict __s, size_t __maxsize,
|
||||
const char *__restrict __format,
|
||||
const struct tm *__restrict __tp,
|
||||
locale_t __loc) __THROW;
|
||||
#endif
|
||||
#ifdef __USE_GNU
|
||||
extern char *strptime_l (const char *__restrict __s,
|
||||
const char *__restrict __fmt, struct tm *__tp,
|
||||
locale_t __loc) __THROW;
|
||||
#endif
|
||||
/* Return the `struct tm' representation of *TIMER
|
||||
in Universal Coordinated Time (aka Greenwich Mean Time). */
|
||||
extern struct tm *gmtime (const time_t *__timer) __THROW;
|
||||
/* Return the `struct tm' representation
|
||||
of *TIMER in the local timezone. */
|
||||
extern struct tm *localtime (const time_t *__timer) __THROW;
|
||||
#ifdef __USE_POSIX
|
||||
/* Return the `struct tm' representation of *TIMER in UTC,
|
||||
using *TP to store the result. */
|
||||
extern struct tm *gmtime_r (const time_t *__restrict __timer,
|
||||
struct tm *__restrict __tp) __THROW;
|
||||
/* Return the `struct tm' representation of *TIMER in local time,
|
||||
using *TP to store the result. */
|
||||
extern struct tm *localtime_r (const time_t *__restrict __timer,
|
||||
struct tm *__restrict __tp) __THROW;
|
||||
#endif /* POSIX */
|
||||
/* Return a string of the form "Day Mon dd hh:mm:ss yyyy\n"
|
||||
that is the representation of TP in this format. */
|
||||
extern char *asctime (const struct tm *__tp) __THROW;
|
||||
/* Equivalent to `asctime (localtime (timer))'. */
|
||||
extern char *ctime (const time_t *__timer) __THROW;
|
||||
#ifdef __USE_POSIX
|
||||
/* Reentrant versions of the above functions. */
|
||||
/* Return in BUF a string of the form "Day Mon dd hh:mm:ss yyyy\n"
|
||||
that is the representation of TP in this format. */
|
||||
extern char *asctime_r (const struct tm *__restrict __tp,
|
||||
char *__restrict __buf) __THROW;
|
||||
/* Equivalent to `asctime_r (localtime_r (timer, *TMP*), buf)'. */
|
||||
extern char *ctime_r (const time_t *__restrict __timer,
|
||||
char *__restrict __buf) __THROW;
|
||||
#endif /* POSIX */
|
||||
/* Defined in localtime.c. */
|
||||
extern char *__tzname[2]; /* Current timezone names. */
|
||||
extern int __daylight; /* If daylight-saving time is ever in use. */
|
||||
extern long int __timezone; /* Seconds west of UTC. */
|
||||
#ifdef __USE_POSIX
|
||||
/* Same as above. */
|
||||
extern char *tzname[2];
|
||||
/* Set time conversion information from the TZ environment variable.
|
||||
If TZ is not defined, a locale-dependent default is used. */
|
||||
extern void tzset (void) __THROW;
|
||||
#endif
|
||||
#if defined __USE_MISC || defined __USE_XOPEN
|
||||
extern int daylight;
|
||||
extern long int timezone;
|
||||
#endif
|
||||
#ifdef __USE_MISC
|
||||
/* Set the system time to *WHEN.
|
||||
This call is restricted to the superuser. */
|
||||
extern int stime (const time_t *__when) __THROW;
|
||||
#endif
|
||||
/* Nonzero if YEAR is a leap year (every 4 years,
|
||||
except every 100th isn't, and every 400th is). */
|
||||
#define __isleap(year) \
|
||||
((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
|
||||
#ifdef __USE_MISC
|
||||
/* Miscellaneous functions many Unices inherited from the public domain
|
||||
localtime package. These are included only for compatibility. */
|
||||
/* Like `mktime', but for TP represents Universal Time, not local time. */
|
||||
extern time_t timegm (struct tm *__tp) __THROW;
|
||||
/* Another name for `mktime'. */
|
||||
extern time_t timelocal (struct tm *__tp) __THROW;
|
||||
/* Return the number of days in YEAR. */
|
||||
extern int dysize (int __year) __THROW __attribute__ ((__const__));
|
||||
#endif
|
||||
#ifdef __USE_POSIX199309
|
||||
/* Pause execution for a number of nanoseconds.
|
||||
This function is a cancellation point and therefore not marked with
|
||||
__THROW. */
|
||||
extern int nanosleep (const struct timespec *__requested_time,
|
||||
struct timespec *__remaining);
|
||||
/* Get resolution of clock CLOCK_ID. */
|
||||
extern int clock_getres (clockid_t __clock_id, struct timespec *__res) __THROW;
|
||||
/* Get current value of clock CLOCK_ID and store it in TP. */
|
||||
extern int clock_gettime (clockid_t __clock_id, struct timespec *__tp) __THROW;
|
||||
/* Set clock CLOCK_ID to value TP. */
|
||||
extern int clock_settime (clockid_t __clock_id, const struct timespec *__tp)
|
||||
__THROW;
|
||||
# ifdef __USE_XOPEN2K
|
||||
/* High-resolution sleep with the specified clock.
|
||||
This function is a cancellation point and therefore not marked with
|
||||
__THROW. */
|
||||
extern int clock_nanosleep (clockid_t __clock_id, int __flags,
|
||||
const struct timespec *__req,
|
||||
struct timespec *__rem);
|
||||
/* Return clock ID for CPU-time clock. */
|
||||
extern int clock_getcpuclockid (pid_t __pid, clockid_t *__clock_id) __THROW;
|
||||
# endif
|
||||
/* Create new per-process timer using CLOCK_ID. */
|
||||
extern int timer_create (clockid_t __clock_id,
|
||||
struct sigevent *__restrict __evp,
|
||||
timer_t *__restrict __timerid) __THROW;
|
||||
/* Delete timer TIMERID. */
|
||||
extern int timer_delete (timer_t __timerid) __THROW;
|
||||
/* Set timer TIMERID to VALUE, returning old value in OVALUE. */
|
||||
extern int timer_settime (timer_t __timerid, int __flags,
|
||||
const struct itimerspec *__restrict __value,
|
||||
struct itimerspec *__restrict __ovalue) __THROW;
|
||||
/* Get current value of timer TIMERID and store it in VALUE. */
|
||||
extern int timer_gettime (timer_t __timerid, struct itimerspec *__value)
|
||||
__THROW;
|
||||
/* Get expiration overrun for timer TIMERID. */
|
||||
extern int timer_getoverrun (timer_t __timerid) __THROW;
|
||||
#endif
|
||||
#ifdef __USE_ISOC11
|
||||
/* Set TS to calendar time based in time base BASE. */
|
||||
extern int timespec_get (struct timespec *__ts, int __base)
|
||||
__THROW __nonnull ((1));
|
||||
#endif
|
||||
#ifdef __USE_XOPEN_EXTENDED
|
||||
/* Set to one of the following values to indicate an error.
|
||||
1 the DATEMSK environment variable is null or undefined,
|
||||
2 the template file cannot be opened for reading,
|
||||
3 failed to get file status information,
|
||||
4 the template file is not a regular file,
|
||||
5 an error is encountered while reading the template file,
|
||||
6 memory allication failed (not enough memory available),
|
||||
7 there is no line in the template that matches the input,
|
||||
8 invalid input specification Example: February 31 or a time is
|
||||
specified that can not be represented in a time_t (representing
|
||||
the time in seconds since 00:00:00 UTC, January 1, 1970) */
|
||||
extern int getdate_err;
|
||||
/* Parse the given string as a date specification and return a value
|
||||
representing the value. The templates from the file identified by
|
||||
the environment variable DATEMSK are used. In case of an error
|
||||
`getdate_err' is set.
|
||||
This function is a possible cancellation point and therefore not
|
||||
marked with __THROW. */
|
||||
extern struct tm *getdate (const char *__string);
|
||||
#endif
|
||||
#ifdef __USE_GNU
|
||||
/* Since `getdate' is not reentrant because of the use of `getdate_err'
|
||||
and the static buffer to return the result in, we provide a thread-safe
|
||||
variant. The functionality is the same. The result is returned in
|
||||
the buffer pointed to by RESBUFP and in case of an error the return
|
||||
value is != 0 with the same values as given above for `getdate_err'.
|
||||
This function is not part of POSIX and therefore no official
|
||||
cancellation point. But due to similarity with an POSIX interface
|
||||
or due to the implementation it is a cancellation point and
|
||||
therefore not marked with __THROW. */
|
||||
extern int getdate_r (const char *__restrict __string,
|
||||
struct tm *__restrict __resbufp);
|
||||
#endif
|
||||
__END_DECLS
|
||||
#endif /* time.h. */
|
|
@ -0,0 +1,220 @@
|
|||
#ifndef TEXT_CHEATS_STRINGS_H
|
||||
#define TEXT_CHEATS_STRINGS_H
|
||||
|
||||
#if defined(VERSION_JP) || defined(VERSION_SH)
|
||||
|
||||
#define TEXT_OPT_COIN _("COIN CHEATS (HOLD B)")
|
||||
#define TEXT_OPT_HOVER _("HOVER MODE")
|
||||
#define TEXT_OPT_MOON _("MOON GRAVITY")
|
||||
#define TEXT_OPT_RUN _("RUN SPEED")
|
||||
#define TEXT_OPT_NDB _("NO DEATH BARRIER")
|
||||
#define TEXT_OPT_JUMP _("ALL JUMPS HIGHER")
|
||||
#define TEXT_OPT_SPDDPS _("SPEED DISPLAY")
|
||||
#define TEXT_OPT_TPF _("T POSE FLOAT")
|
||||
#define TEXT_OPT_JB _("SONG LIST")
|
||||
#define TEXT_OPT_JBC _("PLAY SONG")
|
||||
#define TEXT_OPT_QUIKEND _("QUICK ENDING")
|
||||
#define TEXT_OPT_HURT _("HURT MARIO")
|
||||
#define TEXT_OPT_CANN _("CANNON ANYWHERE")
|
||||
#define TEXT_OPT_AWK _("AUTOWALLKICK")
|
||||
#define TEXT_OPT_SHELL _("GET SHELL")
|
||||
#define TEXT_OPT_BOB _("GET BOBOMB")
|
||||
#define TEXT_OPT_SPAMBA _("SPAMBA")
|
||||
#define TEXT_OPT_SWIM _("QUICK SWIM")
|
||||
#define TEXT_OPT_WING_CAP _("GET WING CAP")
|
||||
#define TEXT_OPT_METAL_CAP _("GET METAL CAP")
|
||||
#define TEXT_OPT_VANISH_CAP _("GET VANISH CAP")
|
||||
#define TEXT_OPT_REMOVE_CAP _("REMOVE CAP")
|
||||
#define TEXT_OPT_NORMAL_CAP _("RESET CAP")
|
||||
#define TEXT_OPT_BLJ _("BLJ ANYWHERE")
|
||||
#define TEXT_OPT_PAC _("PLAY AS")
|
||||
#define TEXT_OPT_TRIPLE _("ALL JUMPS TRIPLE")
|
||||
#define TEXT_OPT_FLY _("FLYER")
|
||||
#define TEXT_OPT_NOB _("NO BOUNDS")
|
||||
#define TEXT_OPT_FLJ _("FORWARD LONG JUMP")
|
||||
#define TEXT_OPT_TS _("TIME STOP")
|
||||
|
||||
#define TEXT_OPT_COIN1 _("OFF")
|
||||
#define TEXT_OPT_COIN2 _("COIN")
|
||||
#define TEXT_OPT_COIN3 _("BLUE COIN")
|
||||
#define TEXT_OPT_COIN4 _("RED COIN")
|
||||
|
||||
#define TEXT_OPT_SS1 _("NORMAL")
|
||||
#define TEXT_OPT_SS2 _("SLOW")
|
||||
#define TEXT_OPT_SS3 _("SLOWER")
|
||||
#define TEXT_OPT_SS4 _("FAST")
|
||||
#define TEXT_OPT_SS5 _("FASTER")
|
||||
|
||||
#define TEXT_OPT_PA1 _("DISABLED")
|
||||
#define TEXT_OPT_PA2 _("BLACK BOBOMB")
|
||||
#define TEXT_OPT_PA3 _("PINK BOBOMB")
|
||||
#define TEXT_OPT_PA4 _("GOOMBA")
|
||||
#define TEXT_OPT_PA5 _("KAPPA SHELL")
|
||||
#define TEXT_OPT_PA6 _("CHUCKYA")
|
||||
#define TEXT_OPT_PA7 _("FLYGUY")
|
||||
#define TEXT_OPT_PA8 _("PER LEVEL")
|
||||
|
||||
#define TEXT_OPT_SEQ1 _("INTRO")
|
||||
#define TEXT_OPT_SEQ2 _("GRASS")
|
||||
#define TEXT_OPT_SEQ3 _("CASTLE")
|
||||
#define TEXT_OPT_SEQ4 _("WATER")
|
||||
#define TEXT_OPT_SEQ5 _("HOT")
|
||||
#define TEXT_OPT_SEQ6 _("BOWSER")
|
||||
#define TEXT_OPT_SEQ7 _("SNOW")
|
||||
#define TEXT_OPT_SEQ8 _("SLIDE")
|
||||
#define TEXT_OPT_SEQ9 _("SPOOKY")
|
||||
#define TEXT_OPT_SEQ10 _("UNDERGROUND")
|
||||
#define TEXT_OPT_SEQ11 _("KOOPA ROAD")
|
||||
#define TEXT_OPT_SEQ12 _("FINAL BOWSER")
|
||||
#define TEXT_OPT_SEQ13 _("TITLE")
|
||||
#define TEXT_OPT_SEQ14 _("FILE SELECT")
|
||||
#define TEXT_OPT_SEQ15 _("POWERUP")
|
||||
#define TEXT_OPT_SEQ16 _("METAL CAP")
|
||||
#define TEXT_OPT_SEQ17 _("BOSS")
|
||||
#define TEXT_OPT_SEQ18 _("MERRYGOROUND")
|
||||
#define TEXT_OPT_SEQ19 _("CREDITS")
|
||||
|
||||
#define TEXT_OPT_HURTCHT1 _("DISABLED")
|
||||
#define TEXT_OPT_HURTCHT2 _("BURN")
|
||||
#define TEXT_OPT_HURTCHT3 _("SHOCK")
|
||||
#define TEXT_OPT_HURTCHT4 _("ONE HP")
|
||||
|
||||
#define TEXT_OPT_SPAMCHT1 _("DISABLED")
|
||||
#define TEXT_OPT_SPAMCHT2 _("AMP")
|
||||
#define TEXT_OPT_SPAMCHT3 _("BLUE COIN SWITCH")
|
||||
#define TEXT_OPT_SPAMCHT4 _("BOWLING BALL")
|
||||
#define TEXT_OPT_SPAMCHT5 _("BREAKABLE BOX")
|
||||
#define TEXT_OPT_SPAMCHT6 _("BREAKABLE BOX SMALL")
|
||||
#define TEXT_OPT_SPAMCHT7 _("JUMPING BOX")
|
||||
#define TEXT_OPT_SPAMCHT8 _("CHECKERBOARD PLATFORM")
|
||||
#define TEXT_OPT_SPAMCHT9 _("CHUCKYA")
|
||||
#define TEXT_OPT_SPAMCHT10 _("FLYGUY")
|
||||
#define TEXT_OPT_SPAMCHT11 _("GOOMBAS")
|
||||
#define TEXT_OPT_SPAMCHT12 _("HEART")
|
||||
#define TEXT_OPT_SPAMCHT13 _("METAL BOX")
|
||||
#define TEXT_OPT_SPAMCHT14 _("PURPLE SWITCH")
|
||||
|
||||
#define TEXT_OPT_BLJCHT1 _("DISABLED")
|
||||
#define TEXT_OPT_BLJCHT2 _("ENABLED")
|
||||
#define TEXT_OPT_BLJCHT3 _("ENABLED - BOOST: 1")
|
||||
#define TEXT_OPT_BLJCHT4 _("ENABLED - BOOST: 2")
|
||||
#define TEXT_OPT_BLJCHT5 _("ENABLED - BOOST: 3")
|
||||
#define TEXT_OPT_BLJCHT6 _("ENABLED - BOOST: 4")
|
||||
#define TEXT_OPT_BLJCHT7 _("ENABLED - BOOST: 5")
|
||||
#define TEXT_OPT_BLJCHT8 _("RAPID FIRE")
|
||||
#define TEXT_OPT_BLJCHT9 _("RAPID FIRE - BOOST: 1")
|
||||
#define TEXT_OPT_BLJCHT10 _("RAPID FIRE - BOOST: 2")
|
||||
#define TEXT_OPT_BLJCHT11 _("RAPID FIRE - BOOST: 3")
|
||||
#define TEXT_OPT_BLJCHT12 _("RAPID FIRE - BOOST: 4")
|
||||
#define TEXT_OPT_BLJCHT13 _("RAPID FIRE - BOOST: 5")
|
||||
|
||||
#else // VERSION
|
||||
|
||||
#define TEXT_OPT_COIN _("Coin Cheats Hold [B]")
|
||||
#define TEXT_OPT_HOVER _("Hover Mode")
|
||||
#define TEXT_OPT_MOON _("Moon Gravity")
|
||||
#define TEXT_OPT_RUN _("Run Speed Modifier")
|
||||
#define TEXT_OPT_NDB _("No Death Barrier")
|
||||
#define TEXT_OPT_JUMP _("All Jumps Higher")
|
||||
#define TEXT_OPT_SPDDPS _("Speed Display")
|
||||
#define TEXT_OPT_TPF _("T Pose Float [A]")
|
||||
#define TEXT_OPT_JB _("Jukebox List")
|
||||
#define TEXT_OPT_JBC _("Jukebox Activate")
|
||||
#define TEXT_OPT_QUIKEND _("Quick Ending")
|
||||
#define TEXT_OPT_HURT _("Hurt Mario L & [A]")
|
||||
#define TEXT_OPT_CANN _("Cannon Anywhere L & [C]^")
|
||||
#define TEXT_OPT_AWK _("AutoWallKick")
|
||||
#define TEXT_OPT_SHELL _("Get Shell L & [R]")
|
||||
#define TEXT_OPT_BOB _("Get Bobomb L & [B]")
|
||||
#define TEXT_OPT_SPAMBA _("Spamba L & [Z]")
|
||||
#define TEXT_OPT_SWIM _("Swift Swim")
|
||||
#define TEXT_OPT_WING_CAP _("Get WING Cap")
|
||||
#define TEXT_OPT_METAL_CAP _("Get METAL Cap")
|
||||
#define TEXT_OPT_VANISH_CAP _("Get VANISH Cap")
|
||||
#define TEXT_OPT_REMOVE_CAP _("REMOVE Cap")
|
||||
#define TEXT_OPT_NORMAL_CAP _("RESET Cap")
|
||||
#define TEXT_OPT_BLJ _("BLJ Anywhere")
|
||||
#define TEXT_OPT_PAC _("Play as")
|
||||
#define TEXT_OPT_TRIPLE _("All Jumps Triple")
|
||||
#define TEXT_OPT_FLY _("FLYER")
|
||||
#define TEXT_OPT_NOB _("No Bounds")
|
||||
#define TEXT_OPT_FLJ _("Forward Long Jump")
|
||||
#define TEXT_OPT_TS _("Time Stop")
|
||||
|
||||
#define TEXT_OPT_COIN1 _("Off")
|
||||
#define TEXT_OPT_COIN2 _("Coin")
|
||||
#define TEXT_OPT_COIN3 _("Blue Coin")
|
||||
#define TEXT_OPT_COIN4 _("Red Coin")
|
||||
|
||||
#define TEXT_OPT_SS1 _("Normal")
|
||||
#define TEXT_OPT_SS2 _("Slow")
|
||||
#define TEXT_OPT_SS3 _("Slower")
|
||||
#define TEXT_OPT_SS4 _("Fast")
|
||||
#define TEXT_OPT_SS5 _("Faster")
|
||||
|
||||
#define TEXT_OPT_PA1 _("Disabled")
|
||||
#define TEXT_OPT_PA2 _("Black Bobomb")
|
||||
#define TEXT_OPT_PA3 _("Pink Bobomb")
|
||||
#define TEXT_OPT_PA4 _("Goomba")
|
||||
#define TEXT_OPT_PA5 _("Koopa Shell")
|
||||
#define TEXT_OPT_PA6 _("Chuckya")
|
||||
#define TEXT_OPT_PA7 _("FlyGuy")
|
||||
#define TEXT_OPT_PA8 _("Per Level")
|
||||
|
||||
#define TEXT_OPT_SEQ1 _("Intro")
|
||||
#define TEXT_OPT_SEQ2 _("Grass")
|
||||
#define TEXT_OPT_SEQ3 _("Castle")
|
||||
#define TEXT_OPT_SEQ4 _("Water")
|
||||
#define TEXT_OPT_SEQ5 _("Hot")
|
||||
#define TEXT_OPT_SEQ6 _("Bowser")
|
||||
#define TEXT_OPT_SEQ7 _("Snow")
|
||||
#define TEXT_OPT_SEQ8 _("Slide")
|
||||
#define TEXT_OPT_SEQ9 _("Spooky")
|
||||
#define TEXT_OPT_SEQ10 _("Underground")
|
||||
#define TEXT_OPT_SEQ11 _("Koopa Road")
|
||||
#define TEXT_OPT_SEQ12 _("Rainbow Bowser")
|
||||
#define TEXT_OPT_SEQ13 _("Goddard")
|
||||
#define TEXT_OPT_SEQ14 _("File Select")
|
||||
#define TEXT_OPT_SEQ15 _("Powerup")
|
||||
#define TEXT_OPT_SEQ16 _("Metal Cap")
|
||||
#define TEXT_OPT_SEQ17 _("Boss")
|
||||
#define TEXT_OPT_SEQ18 _("MerryGoRound")
|
||||
#define TEXT_OPT_SEQ19 _("Credits")
|
||||
|
||||
#define TEXT_OPT_HURTCHT1 _("Disabled")
|
||||
#define TEXT_OPT_HURTCHT2 _("Burn")
|
||||
#define TEXT_OPT_HURTCHT3 _("Shock")
|
||||
#define TEXT_OPT_HURTCHT4 _("One HP")
|
||||
|
||||
#define TEXT_OPT_SPAMCHT1 _("Disabled")
|
||||
#define TEXT_OPT_SPAMCHT2 _("Amp")
|
||||
#define TEXT_OPT_SPAMCHT3 _("Blue Coin Switch")
|
||||
#define TEXT_OPT_SPAMCHT4 _("Bowling Ball")
|
||||
#define TEXT_OPT_SPAMCHT5 _("Breakable box, large")
|
||||
#define TEXT_OPT_SPAMCHT6 _("Breakable box, small")
|
||||
#define TEXT_OPT_SPAMCHT7 _("Jumping Box")
|
||||
#define TEXT_OPT_SPAMCHT8 _("Checkerboard Platform")
|
||||
#define TEXT_OPT_SPAMCHT9 _("Chuckya")
|
||||
#define TEXT_OPT_SPAMCHT10 _("FlyGuy")
|
||||
#define TEXT_OPT_SPAMCHT11 _("Goombas")
|
||||
#define TEXT_OPT_SPAMCHT12 _("Heart")
|
||||
#define TEXT_OPT_SPAMCHT13 _("Metal Box")
|
||||
#define TEXT_OPT_SPAMCHT14 _("Purple Switch")
|
||||
|
||||
#define TEXT_OPT_BLJCHT1 _("Disabled")
|
||||
#define TEXT_OPT_BLJCHT2 _("Enabled")
|
||||
#define TEXT_OPT_BLJCHT3 _("Enabled - Boost: 1")
|
||||
#define TEXT_OPT_BLJCHT4 _("Enabled - Boost: 2")
|
||||
#define TEXT_OPT_BLJCHT5 _("Enabled - Boost: 3")
|
||||
#define TEXT_OPT_BLJCHT6 _("Enabled - Boost: 4")
|
||||
#define TEXT_OPT_BLJCHT7 _("Enabled - Boost: 5")
|
||||
#define TEXT_OPT_BLJCHT8 _("Rapid Fire")
|
||||
#define TEXT_OPT_BLJCHT9 _("Rapid Fire - Boost: 1")
|
||||
#define TEXT_OPT_BLJCHT10 _("Rapid Fire - Boost: 2")
|
||||
#define TEXT_OPT_BLJCHT11 _("Rapid Fire - Boost: 3")
|
||||
#define TEXT_OPT_BLJCHT12 _("Rapid Fire - Boost: 4")
|
||||
#define TEXT_OPT_BLJCHT13 _("Rapid Fire - Boost: 5")
|
||||
|
||||
#endif // VERSION
|
||||
|
||||
#endif // TEXT_CHEATS_STRINGS_H
|
|
@ -0,0 +1,215 @@
|
|||
#ifndef CHEATS_MENU_H
|
||||
#define CHEATS_MENU_H
|
||||
|
||||
static const u8 optsCoinCheatStr[][32] = {
|
||||
{ TEXT_OPT_COIN1 },
|
||||
{ TEXT_OPT_COIN2 },
|
||||
{ TEXT_OPT_COIN3 },
|
||||
{ TEXT_OPT_COIN4 },
|
||||
};
|
||||
|
||||
static const u8 *CoinChoices[] = {
|
||||
optsCoinCheatStr[0],
|
||||
optsCoinCheatStr[1],
|
||||
optsCoinCheatStr[2],
|
||||
optsCoinCheatStr[3],
|
||||
};
|
||||
|
||||
static const u8 optsSeqStr[][64] = {
|
||||
{ TEXT_OPT_SEQ1 },
|
||||
{ TEXT_OPT_SEQ2 },
|
||||
{ TEXT_OPT_SEQ3 },
|
||||
{ TEXT_OPT_SEQ4 },
|
||||
{ TEXT_OPT_SEQ5 },
|
||||
{ TEXT_OPT_SEQ6 },
|
||||
{ TEXT_OPT_SEQ7 },
|
||||
{ TEXT_OPT_SEQ8 },
|
||||
{ TEXT_OPT_SEQ9 },
|
||||
{ TEXT_OPT_SEQ10 },
|
||||
{ TEXT_OPT_SEQ11 },
|
||||
{ TEXT_OPT_SEQ12 },
|
||||
{ TEXT_OPT_SEQ13 },
|
||||
{ TEXT_OPT_SEQ14 },
|
||||
{ TEXT_OPT_SEQ15 },
|
||||
{ TEXT_OPT_SEQ16 },
|
||||
{ TEXT_OPT_SEQ17 },
|
||||
{ TEXT_OPT_SEQ18 },
|
||||
{ TEXT_OPT_SEQ19 },
|
||||
};
|
||||
|
||||
static const u8 *SeqChoices[] = {
|
||||
optsSeqStr[0],
|
||||
optsSeqStr[1],
|
||||
optsSeqStr[2],
|
||||
optsSeqStr[3],
|
||||
optsSeqStr[4],
|
||||
optsSeqStr[5],
|
||||
optsSeqStr[6],
|
||||
optsSeqStr[7],
|
||||
optsSeqStr[8],
|
||||
optsSeqStr[9],
|
||||
optsSeqStr[10],
|
||||
optsSeqStr[11],
|
||||
optsSeqStr[12],
|
||||
optsSeqStr[13],
|
||||
optsSeqStr[14],
|
||||
optsSeqStr[15],
|
||||
optsSeqStr[16],
|
||||
optsSeqStr[17],
|
||||
optsSeqStr[18],
|
||||
};
|
||||
|
||||
static const u8 optsSpeedStr[][16] = {
|
||||
{ TEXT_OPT_SS1 },
|
||||
{ TEXT_OPT_SS2 },
|
||||
{ TEXT_OPT_SS3 },
|
||||
{ TEXT_OPT_SS4 },
|
||||
{ TEXT_OPT_SS5 },
|
||||
};
|
||||
|
||||
static const u8 *SpeedChoices[] = {
|
||||
optsSpeedStr[0],
|
||||
optsSpeedStr[1],
|
||||
optsSpeedStr[2],
|
||||
optsSpeedStr[3],
|
||||
optsSpeedStr[4],
|
||||
};
|
||||
|
||||
static const u8 optsPlayAsCheatStr[][32] = {
|
||||
{ TEXT_OPT_PA1 },
|
||||
{ TEXT_OPT_PA2 },
|
||||
{ TEXT_OPT_PA3 },
|
||||
{ TEXT_OPT_PA4 },
|
||||
{ TEXT_OPT_PA5 },
|
||||
{ TEXT_OPT_PA6 },
|
||||
{ TEXT_OPT_PA7 },
|
||||
{ TEXT_OPT_PA8 },
|
||||
};
|
||||
|
||||
static const u8* PlayAsCheatChoices[] = {
|
||||
optsPlayAsCheatStr[0],
|
||||
optsPlayAsCheatStr[1],
|
||||
optsPlayAsCheatStr[2],
|
||||
optsPlayAsCheatStr[3],
|
||||
optsPlayAsCheatStr[4],
|
||||
optsPlayAsCheatStr[5],
|
||||
optsPlayAsCheatStr[6],
|
||||
optsPlayAsCheatStr[7],
|
||||
};
|
||||
|
||||
|
||||
static const u8 optsHurtCheatStr[][32] = {
|
||||
{ TEXT_OPT_HURTCHT1 },
|
||||
{ TEXT_OPT_HURTCHT2 },
|
||||
{ TEXT_OPT_HURTCHT3 },
|
||||
{ TEXT_OPT_HURTCHT4 },
|
||||
};
|
||||
|
||||
static const u8* HurtCheatChoices[] = {
|
||||
optsHurtCheatStr[0],
|
||||
optsHurtCheatStr[1],
|
||||
optsHurtCheatStr[2],
|
||||
optsHurtCheatStr[3],
|
||||
};
|
||||
|
||||
static const u8 optsSpamCheatStr[][32] = {
|
||||
{ TEXT_OPT_SPAMCHT1 },
|
||||
{ TEXT_OPT_SPAMCHT2 },
|
||||
{ TEXT_OPT_SPAMCHT3 },
|
||||
{ TEXT_OPT_SPAMCHT4 },
|
||||
{ TEXT_OPT_SPAMCHT5 },
|
||||
{ TEXT_OPT_SPAMCHT6 },
|
||||
{ TEXT_OPT_SPAMCHT7 },
|
||||
{ TEXT_OPT_SPAMCHT8 },
|
||||
{ TEXT_OPT_SPAMCHT9 },
|
||||
{ TEXT_OPT_SPAMCHT10 },
|
||||
{ TEXT_OPT_SPAMCHT11 },
|
||||
{ TEXT_OPT_SPAMCHT12 },
|
||||
{ TEXT_OPT_SPAMCHT13 },
|
||||
{ TEXT_OPT_SPAMCHT14 },
|
||||
};
|
||||
|
||||
static const u8* SpamCheatChoices[] = {
|
||||
optsSpamCheatStr[0],
|
||||
optsSpamCheatStr[1],
|
||||
optsSpamCheatStr[2],
|
||||
optsSpamCheatStr[3],
|
||||
optsSpamCheatStr[4],
|
||||
optsSpamCheatStr[5],
|
||||
optsSpamCheatStr[6],
|
||||
optsSpamCheatStr[7],
|
||||
optsSpamCheatStr[8],
|
||||
optsSpamCheatStr[9],
|
||||
optsSpamCheatStr[10],
|
||||
optsSpamCheatStr[11],
|
||||
optsSpamCheatStr[12],
|
||||
optsSpamCheatStr[13],
|
||||
};
|
||||
|
||||
static const u8 optsBLJCheatStr[][32] = {
|
||||
{ TEXT_OPT_BLJCHT1 },
|
||||
{ TEXT_OPT_BLJCHT2 },
|
||||
{ TEXT_OPT_BLJCHT3 },
|
||||
{ TEXT_OPT_BLJCHT4 },
|
||||
{ TEXT_OPT_BLJCHT5 },
|
||||
{ TEXT_OPT_BLJCHT6 },
|
||||
{ TEXT_OPT_BLJCHT7 },
|
||||
{ TEXT_OPT_BLJCHT8 },
|
||||
{ TEXT_OPT_BLJCHT9 },
|
||||
{ TEXT_OPT_BLJCHT10 },
|
||||
{ TEXT_OPT_BLJCHT11 },
|
||||
{ TEXT_OPT_BLJCHT12 },
|
||||
{ TEXT_OPT_BLJCHT13 },
|
||||
};
|
||||
|
||||
static const u8* bljCheatChoices[] = {
|
||||
optsBLJCheatStr[0],
|
||||
optsBLJCheatStr[1],
|
||||
optsBLJCheatStr[2],
|
||||
optsBLJCheatStr[3],
|
||||
optsBLJCheatStr[4],
|
||||
optsBLJCheatStr[5],
|
||||
optsBLJCheatStr[6],
|
||||
optsBLJCheatStr[7],
|
||||
optsBLJCheatStr[8],
|
||||
optsBLJCheatStr[9],
|
||||
optsBLJCheatStr[10],
|
||||
optsBLJCheatStr[11],
|
||||
optsBLJCheatStr[12],
|
||||
};
|
||||
|
||||
static const u8 optsCheatsStr2[][64] = {
|
||||
{ TEXT_OPT_COIN },
|
||||
{ TEXT_OPT_HOVER },
|
||||
{ TEXT_OPT_MOON },
|
||||
{ TEXT_OPT_RUN },
|
||||
{ TEXT_OPT_NDB },
|
||||
{ TEXT_OPT_JUMP },
|
||||
{ TEXT_OPT_SPDDPS },
|
||||
{ TEXT_OPT_TPF },
|
||||
{ TEXT_OPT_JB },
|
||||
{ TEXT_OPT_JBC },
|
||||
{ TEXT_OPT_QUIKEND },
|
||||
{ TEXT_OPT_HURT },
|
||||
{ TEXT_OPT_CANN },
|
||||
{ TEXT_OPT_AWK },
|
||||
{ TEXT_OPT_SHELL },
|
||||
{ TEXT_OPT_BOB },
|
||||
{ TEXT_OPT_SPAMBA },
|
||||
{ TEXT_OPT_SWIM },
|
||||
{ TEXT_OPT_WING_CAP },
|
||||
{ TEXT_OPT_METAL_CAP },
|
||||
{ TEXT_OPT_VANISH_CAP },
|
||||
{ TEXT_OPT_REMOVE_CAP },
|
||||
{ TEXT_OPT_NORMAL_CAP },
|
||||
{ TEXT_OPT_BLJ },
|
||||
{ TEXT_OPT_PAC },
|
||||
{ TEXT_OPT_TRIPLE },
|
||||
{ TEXT_OPT_FLY },
|
||||
{ TEXT_OPT_NOB },
|
||||
{ TEXT_OPT_FLJ },
|
||||
{ TEXT_OPT_TS },
|
||||
|
||||
};
|
||||
|
||||
#endif // CHEATS_MENU_H
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,42 @@
|
|||
#ifndef MARIO_CHEATS_H
|
||||
#define MARIO_CHEATS_H
|
||||
|
||||
#include <PR/ultratypes.h>
|
||||
|
||||
#include "macros.h"
|
||||
#include "model_ids.h"
|
||||
#include "types.h"
|
||||
|
||||
#if defined(MODEL_PLAYER) && defined(MODEL_LUIGIS_CAP)
|
||||
#define R96
|
||||
#endif
|
||||
|
||||
void cheats_set_model(struct MarioState *m);
|
||||
void cheats_swimming_speed(struct MarioState *m);
|
||||
void cheats_air_step(struct MarioState *m);
|
||||
void cheats_long_jump(struct MarioState *m);
|
||||
void cheats_mario_inputs(struct MarioState *m);
|
||||
|
||||
/* Options */
|
||||
#define TIME_BUTTON 0x0080
|
||||
|
||||
#include "data/dynos.c.h"
|
||||
#define __chaos_mode__ dynos_opt_get_value("chaos_mode")
|
||||
#define __time_button__ dynos_opt_get_value("time_button")
|
||||
#define __spl__ dynos_opt_get_value("spl")
|
||||
#define __no_heavy__ dynos_opt_get_value("no_heavy")
|
||||
#define __haz_walk__ dynos_opt_get_value("haz_walk")
|
||||
#define __swim_any__ dynos_opt_get_value("swim_any")
|
||||
#define __coin_mag__ dynos_opt_get_value("coin_mag")
|
||||
#define __wat_con__ dynos_opt_get_value("wat_con")
|
||||
#define __wat_lev__ dynos_opt_get_value("wat_lev")
|
||||
#define CHAOS_MODE (__chaos_mode__ == 1)
|
||||
#define SPL (__spl__)
|
||||
#define NO_HEAVY (__no_heavy__ == 1)
|
||||
#define HAZ_WALK (__haz_walk__ == 1)
|
||||
#define SWIM_ANY (__swim_any__ == 1)
|
||||
#define COIN_MAG (__coin_mag__ == 1)
|
||||
#define WAT_CON (__wat_con__ == 1)
|
||||
#define WAT_LEV (__wat_lev__)
|
||||
|
||||
#endif // MARIO_CHEATS_H
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,15 @@
|
|||
#ifndef TIME_TRIALS_H
|
||||
#define TIME_TRIALS_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include "types.h"
|
||||
|
||||
#define TIME_TRIALS time_trials_enabled()
|
||||
|
||||
extern Gfx *gTimeTableDisplayListHead;
|
||||
bool time_trials_enabled();
|
||||
void time_trials_update(bool isPaused);
|
||||
bool time_trials_render_time_table(s8 *index);
|
||||
void time_trials_render_star_select_time(s32 starIndex);
|
||||
|
||||
#endif // TIME_TRIALS_H
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue