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:
Daren Gordon 2022-08-09 10:47:49 -04:00
parent db9a6345ba
commit 13d9bcb5b4
40 changed files with 13131 additions and 0 deletions

1
Test.txt Normal file
View File

@ -0,0 +1 @@
blahblahblah

28
data/dynos.c.h Normal file
View File

@ -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

714
data/dynos.cpp.h Normal file
View File

@ -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

40
data/dynos.h Normal file
View File

@ -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

36
data/dynos_c.cpp Normal file
View File

@ -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);
}
}

63
data/dynos_gfx_init.cpp Normal file
View File

@ -0,0 +1,63 @@
#include "dynos.cpp.h"
Array<ActorGfx> &DynOS_Gfx_GetActorList() {
static Array<ActorGfx> sActorGfxList;
return sActorGfxList;
}
Array<PackData *> &DynOS_Gfx_GetPacks() {
static Array<PackData *> sPacks;
return sPacks;
}
Array<String> DynOS_Gfx_Init() {
// Alloc and init the actors gfx list
Array<ActorGfx> &pActorGfxList = DynOS_Gfx_GetActorList();
pActorGfxList.Resize(DynOS_Geo_GetActorCount());
for (s32 i = 0; i != DynOS_Geo_GetActorCount(); ++i) {
pActorGfxList[i].mPackIndex = -1;
pActorGfxList[i].mGfxData = NULL;
pActorGfxList[i].mGraphNode = (GraphNode *) DynOS_Geo_GetGraphNode(DynOS_Geo_GetActorLayout(i), false);
}
// Scan the DynOS packs folder
Array<PackData *> &pDynosPacks = DynOS_Gfx_GetPacks();
SysPath _DynosPacksFolder = fstring("%s/%s", DYNOS_EXE_FOLDER, DYNOS_PACKS_FOLDER);
DIR *_DynosPacksDir = opendir(_DynosPacksFolder.c_str());
if (_DynosPacksDir) {
struct dirent *_DynosPacksEnt = NULL;
while ((_DynosPacksEnt = readdir(_DynosPacksDir)) != NULL) {
// Skip . and ..
if (SysPath(_DynosPacksEnt->d_name) == ".") continue;
if (SysPath(_DynosPacksEnt->d_name) == "..") continue;
// If pack folder exists, add it to the pack list
SysPath _PackFolder = fstring("%s/%s", _DynosPacksFolder.c_str(), _DynosPacksEnt->d_name);
if (fs_sys_dir_exists(_PackFolder.c_str())) {
PackData *_Pack = New<PackData>();
// Scan folder for subfolders to convert into .bin files
_Pack->mPath = _PackFolder;
DynOS_Gfx_GeneratePack(_PackFolder);
// Add pack to pack list
pDynosPacks.Add(_Pack);
}
}
closedir(_DynosPacksDir);
}
// Return a list of pack names
Array<String> _PackNames;
for (const auto& _Pack : pDynosPacks) {
u64 _DirSep1 = _Pack->mPath.find_last_of('\\');
u64 _DirSep2 = _Pack->mPath.find_last_of('/');
if (_DirSep1++ == SysPath::npos) _DirSep1 = 0;
if (_DirSep2++ == SysPath::npos) _DirSep2 = 0;
SysPath _DirName = _Pack->mPath.substr(MAX(_DirSep1, _DirSep2));
_PackNames.Add(_DirName.c_str());
}
return _PackNames;
}

278
data/dynos_gfx_load.cpp Normal file
View File

@ -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;
}

1884
data/dynos_gfx_read.cpp Normal file

File diff suppressed because it is too large Load Diff

285
data/dynos_gfx_texture.cpp Normal file
View File

@ -0,0 +1,285 @@
#include "dynos.cpp.h"
extern "C" {
#include "pc/gfx/gfx_rendering_api.h"
}
//
// Conversion
//
#define SCALE_5_8(VAL_) (((VAL_) * 0xFF) / 0x1F)
#define SCALE_8_5(VAL_) ((((VAL_) + 4) * 0x1F) / 0xFF)
#define SCALE_4_8(VAL_) ((VAL_) * 0x11)
#define SCALE_8_4(VAL_) ((VAL_) / 0x11)
#define SCALE_3_8(VAL_) ((VAL_) * 0x24)
#define SCALE_8_3(VAL_) ((VAL_) / 0x24)
static u8 *RGBA16_RGBA32(const u8 *aData, u64 aLength) {
u8 *_Buffer = New<u8>(aLength * 2);
u8 *pBuffer = _Buffer;
for (u64 i = 0; i != aLength; i += 2) {
u16 _Col = (aData[i + 0] << 8) | aData[i + 1];
u8 _Red = (_Col >> 11) & 0x1F;
u8 _Grn = (_Col >> 6) & 0x1F;
u8 _Blu = (_Col >> 1) & 0x1F;
u8 _Alp = (_Col >> 0) & 0x01;
*(pBuffer++) = (SCALE_5_8(_Red));
*(pBuffer++) = (SCALE_5_8(_Grn));
*(pBuffer++) = (SCALE_5_8(_Blu));
*(pBuffer++) = (0xFF * (_Alp));
}
return _Buffer;
}
static u8 *RGBA32_RGBA32(const u8 *aData, u64 aLength) {
u8 *_Buffer = New<u8>(aLength * 1);
memcpy(_Buffer, aData, aLength);
return _Buffer;
}
static u8 *IA4_RGBA32(const u8 *aData, u64 aLength) {
u8 *_Buffer = New<u8>(aLength * 8);
u8 *pBuffer = _Buffer;
for (u64 i = 0; i != aLength; ++i) {
u8 _Half0 = (aData[i] >> 4) & 0xF;
*(pBuffer++) = (SCALE_3_8(_Half0 >> 1));
*(pBuffer++) = (SCALE_3_8(_Half0 >> 1));
*(pBuffer++) = (SCALE_3_8(_Half0 >> 1));
*(pBuffer++) = (0xFF * (_Half0 & 1));
u8 _Half1 = (aData[i] >> 0) & 0xF;
*(pBuffer++) = (SCALE_3_8(_Half1 >> 1));
*(pBuffer++) = (SCALE_3_8(_Half1 >> 1));
*(pBuffer++) = (SCALE_3_8(_Half1 >> 1));
*(pBuffer++) = (0xFF * (_Half1 & 1));
}
return _Buffer;
}
static u8 *IA8_RGBA32(const u8 *aData, u64 aLength) {
u8 *_Buffer = New<u8>(aLength * 4);
u8 *pBuffer = _Buffer;
for (u64 i = 0; i != aLength; ++i) {
u8 _Col = (aData[i] >> 4) & 0xF;
u8 _Alp = (aData[i] >> 0) & 0xF;
*(pBuffer++) = (SCALE_4_8(_Col));
*(pBuffer++) = (SCALE_4_8(_Col));
*(pBuffer++) = (SCALE_4_8(_Col));
*(pBuffer++) = (SCALE_4_8(_Alp));
}
return _Buffer;
}
static u8 *IA16_RGBA32(const u8 *aData, u64 aLength) {
u8 *_Buffer = New<u8>(aLength * 2);
u8 *pBuffer = _Buffer;
for (u64 i = 0; i != aLength; i += 2) {
u8 _Col = aData[i + 0];
u8 _Alp = aData[i + 1];
*(pBuffer++) = (_Col);
*(pBuffer++) = (_Col);
*(pBuffer++) = (_Col);
*(pBuffer++) = (_Alp);
}
return _Buffer;
}
static u8 *CI4_RGBA32(const u8 *aData, u64 aLength, const u8 *aPalette) {
u8 *_Buffer = New<u8>(aLength * 8);
u8 *pBuffer = _Buffer;
for (u64 i = 0; i != aLength; ++i) {
u8 _Idx0 = (aData[i] >> 4) & 0xF;
u16 _Col0 = (aPalette[_Idx0 * 2 + 0] << 8) | aPalette[_Idx0 * 2 + 1];
u8 _Red0 = (_Col0 >> 11) & 0x1F;
u8 _Grn0 = (_Col0 >> 6) & 0x1F;
u8 _Blu0 = (_Col0 >> 1) & 0x1F;
u8 _Alp0 = (_Col0 >> 0) & 0x01;
*(pBuffer++) = (SCALE_5_8(_Red0));
*(pBuffer++) = (SCALE_5_8(_Grn0));
*(pBuffer++) = (SCALE_5_8(_Blu0));
*(pBuffer++) = (0xFF * (_Alp0));
u8 _Idx1 = (aData[i] >> 0) & 0xF;
u16 _Col1 = (aPalette[_Idx1 * 2 + 0] << 8) | aPalette[_Idx1 * 2 + 1];
u8 _Red1 = (_Col1 >> 11) & 0x1F;
u8 _Grn1 = (_Col1 >> 6) & 0x1F;
u8 _Blu1 = (_Col1 >> 1) & 0x1F;
u8 _Alp1 = (_Col1 >> 0) & 0x01;
*(pBuffer++) = (SCALE_5_8(_Red1));
*(pBuffer++) = (SCALE_5_8(_Grn1));
*(pBuffer++) = (SCALE_5_8(_Blu1));
*(pBuffer++) = (0xFF * (_Alp1));
}
return _Buffer;
}
static u8 *CI8_RGBA32(const u8 *aData, u64 aLength, const u8 *aPalette) {
u8 *_Buffer = New<u8>(aLength * 4);
u8 *pBuffer = _Buffer;
for (u64 i = 0; i != aLength; ++i) {
u8 _Idx = aData[i];
u16 _Col = (aPalette[_Idx * 2 + 0] << 8) | aPalette[_Idx * 2 + 1];
u8 _Red = (_Col >> 11) & 0x1F;
u8 _Grn = (_Col >> 6) & 0x1F;
u8 _Blu = (_Col >> 1) & 0x1F;
u8 _Alp = (_Col >> 0) & 0x01;
*(pBuffer++) = (SCALE_5_8(_Red));
*(pBuffer++) = (SCALE_5_8(_Grn));
*(pBuffer++) = (SCALE_5_8(_Blu));
*(pBuffer++) = (0xFF * (_Alp));
}
return _Buffer;
}
static u8 *I4_RGBA32(const u8 *aData, u64 aLength) {
u8 *_Buffer = New<u8>(aLength * 8);
u8 *pBuffer = _Buffer;
for (u64 i = 0; i != aLength; ++i) {
u8 _Half0 = (aData[i] >> 4) & 0xF;
*(pBuffer++) = (SCALE_4_8(_Half0));
*(pBuffer++) = (SCALE_4_8(_Half0));
*(pBuffer++) = (SCALE_4_8(_Half0));
*(pBuffer++) = (255);
u8 _Half1 = (aData[i] >> 0) & 0xF;
*(pBuffer++) = (SCALE_4_8(_Half1));
*(pBuffer++) = (SCALE_4_8(_Half1));
*(pBuffer++) = (SCALE_4_8(_Half1));
*(pBuffer++) = (255);
}
return _Buffer;
}
static u8 *I8_RGBA32(const u8 *aData, u64 aLength) {
u8 *_Buffer = New<u8>(aLength * 4);
u8 *pBuffer = _Buffer;
for (u64 i = 0; i != aLength; ++i) {
*(pBuffer++) = (aData[i]);
*(pBuffer++) = (aData[i]);
*(pBuffer++) = (aData[i]);
*(pBuffer++) = (255);
}
return _Buffer;
}
u8 *DynOS_Gfx_TextureConvertToRGBA32(const u8 *aData, u64 aLength, s32 aFormat, s32 aSize, const u8 *aPalette) {
switch ((aFormat << 8) | aSize ) {
case ((G_IM_FMT_RGBA << 8) | G_IM_SIZ_16b): return RGBA16_RGBA32(aData, aLength);
case ((G_IM_FMT_RGBA << 8) | G_IM_SIZ_32b): return RGBA32_RGBA32(aData, aLength);
case ((G_IM_FMT_IA << 8) | G_IM_SIZ_4b ): return IA4_RGBA32 (aData, aLength);
case ((G_IM_FMT_IA << 8) | G_IM_SIZ_8b ): return IA8_RGBA32 (aData, aLength);
case ((G_IM_FMT_IA << 8) | G_IM_SIZ_16b): return IA16_RGBA32 (aData, aLength);
case ((G_IM_FMT_CI << 8) | G_IM_SIZ_4b ): return CI4_RGBA32 (aData, aLength, aPalette);
case ((G_IM_FMT_CI << 8) | G_IM_SIZ_8b ): return CI8_RGBA32 (aData, aLength, aPalette);
case ((G_IM_FMT_I << 8) | G_IM_SIZ_4b ): return I4_RGBA32 (aData, aLength);
case ((G_IM_FMT_I << 8) | G_IM_SIZ_8b ): return I8_RGBA32 (aData, aLength);
}
return NULL;
}
//
// Upload
//
typedef struct GfxRenderingAPI GRAPI;
static void DynOS_Gfx_UploadTexture(DataNode<TexData> *aNode, GRAPI *aGfxRApi, s32 aTile, s32 aTexId) {
aGfxRApi->select_texture(aTile, aTexId);
aGfxRApi->upload_texture(aNode->mData->mRawData.begin(), aNode->mData->mRawWidth, aNode->mData->mRawHeight);
aNode->mData->mUploaded = true;
}
//
// Cache
//
struct THN {
struct THN *mNext;
const void *mAddr; // Contains the pointer to the DataNode<TexData> struct, NOT the actual texture data
u8 mFmt, mSiz;
s32 mTexId;
u8 mCms, mCmt;
bool mLInf;
};
static bool DynOS_Gfx_CacheTexture(THN **aOutput, DataNode<TexData> *aNode, s32 aTile, GRAPI *aGfxRApi, THN **aHashMap, THN *aPool, u32 *aPoolPos, u32 aPoolSize) {
// Find texture in cache
uintptr_t _Hash = ((uintptr_t) aNode) & ((aPoolSize * 2) - 1);
THN **_Node = &(aHashMap[_Hash]);
while ((*_Node) != NULL && ((*_Node) - aPool) < (*aPoolPos)) {
if ((*_Node)->mAddr == (const void *) aNode) {
aGfxRApi->select_texture(aTile, (*_Node)->mTexId);
if (!aNode->mData->mUploaded) {
DynOS_Gfx_UploadTexture(aNode, aGfxRApi, aTile, (*_Node)->mTexId);
}
(*aOutput) = (*_Node);
return true;
}
_Node = &(*_Node)->mNext;
}
// If cache is full, clear cache
if ((*aPoolPos) == aPoolSize) {
(*aPoolPos) = 0;
_Node = &aHashMap[_Hash];
}
// Add new texture to cache
(*_Node) = &aPool[(*aPoolPos)++];
if (!(*_Node)->mAddr) {
(*_Node)->mTexId = aGfxRApi->new_texture();
}
aGfxRApi->select_texture(aTile, (*_Node)->mTexId);
aGfxRApi->set_sampler_parameters(aTile, false, 0, 0);
(*_Node)->mCms = 0;
(*_Node)->mCmt = 0;
(*_Node)->mLInf = false;
(*_Node)->mNext = NULL;
(*_Node)->mAddr = aNode;
(*_Node)->mFmt = G_IM_FMT_RGBA;
(*_Node)->mSiz = G_IM_SIZ_32b;
(*aOutput) = (*_Node);
return false;
}
//
// Import
//
static DataNode<TexData> *DynOS_Gfx_RetrieveNode(void *aPtr) {
Array<ActorGfx> &pActorGfxList = DynOS_Gfx_GetActorList();
for (auto& _ActorGfx : pActorGfxList) {
if (_ActorGfx.mGfxData) {
for (auto &_Node : _ActorGfx.mGfxData->mTextures) {
if ((void*) _Node == aPtr) {
return _Node;
}
}
}
}
return NULL;
}
static bool DynOS_Gfx_ImportTexture_Typed(THN **aOutput, void *aPtr, s32 aTile, GRAPI *aGfxRApi, THN **aHashMap, THN *aPool, u32 *aPoolPos, u32 aPoolSize) {
DataNode<TexData> *_Node = DynOS_Gfx_RetrieveNode(aPtr);
if (_Node) {
if (!DynOS_Gfx_CacheTexture(aOutput, _Node, aTile, aGfxRApi, aHashMap, aPool, aPoolPos, aPoolSize)) {
DynOS_Gfx_UploadTexture(_Node, aGfxRApi, aTile, (*aOutput)->mTexId);
}
return true;
}
return false;
}
bool DynOS_Gfx_ImportTexture(void **aOutput, void *aPtr, s32 aTile, void *aGfxRApi, void **aHashMap, void *aPool, u32 *aPoolPos, u32 aPoolSize) {
return DynOS_Gfx_ImportTexture_Typed(
(THN **) aOutput,
(void *) aPtr,
(s32) aTile,
(GRAPI *) aGfxRApi,
(THN **) aHashMap,
(THN *) aPool,
(u32 *) aPoolPos,
(u32) aPoolSize
);
}

200
data/dynos_gfx_update.cpp Normal file
View File

@ -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);
}
}
}

318
data/dynos_gfx_write.cpp Normal file
View File

@ -0,0 +1,318 @@
#include "dynos.cpp.h"
//
// Pointers
//
typedef Pair<String, u32> PointerData;
static PointerData GetDataFromPointer(const void* aPtr, GfxData* aGfxData) {
// Lights
for (auto& _Node : aGfxData->mLights) {
if (&_Node->mData->l[0] == aPtr) { // Light *, not Lights1 *
return { _Node->mName, 1 };
}
if (&_Node->mData->a == aPtr) { // Ambient *, not Lights1 *
return { _Node->mName, 2 };
}
}
// Textures
for (auto& _Node : aGfxData->mTextures) {
if (_Node == aPtr) {
return { _Node->mName, 0 };
}
}
// Display lists
for (auto& _Node : aGfxData->mDisplayLists) {
if (_Node == aPtr) {
return { _Node->mName, 0 };
}
}
// Geo layouts
for (auto& _Node : aGfxData->mGeoLayouts) {
if (_Node->mData == aPtr) {
return { _Node->mName, 0 };
}
}
// Vertices
String _VtxArrayName = "";
uintptr_t _VtxArrayStart = 0;
for (auto& _Node : aGfxData->mVertices) {
if (_Node->mData == aPtr) {
return { _Node->mName, 0 };
}
if ((uintptr_t)_Node->mData <= (uintptr_t)aPtr &&
(uintptr_t)_Node->mData >= _VtxArrayStart) {
_VtxArrayName = _Node->mName;
_VtxArrayStart = (uintptr_t)_Node->mData;
}
}
return { _VtxArrayName, (u32)((const Vtx*)aPtr - (const Vtx*)_VtxArrayStart) };
}
static void WritePointer(FILE* aFile, const void* aPtr, GfxData* aGfxData) {
// NULL
if (!aPtr) {
WriteBytes<u32>(aFile, 0);
return;
}
// Geo function
s32 _GeoFunctionIndex = DynOS_Geo_GetFunctionIndex(aPtr);
if (_GeoFunctionIndex != -1) {
WriteBytes<u32>(aFile, FUNCTION_CODE);
WriteBytes<s32>(aFile, _GeoFunctionIndex);
return;
}
// Pointer
PointerData _PtrData = GetDataFromPointer(aPtr, aGfxData);
WriteBytes<u32>(aFile, POINTER_CODE);
_PtrData.first.Write(aFile);
WriteBytes<u32>(aFile, _PtrData.second);
}
//
// Lights
//
static void WriteLightData(FILE* aFile, GfxData* aGfxData, DataNode<Lights1> *aNode) {
if (!aNode->mData) return;
// Header
WriteBytes<u8>(aFile, DATA_TYPE_LIGHT);
aNode->mName.Write(aFile);
// Data
WriteBytes<Lights1>(aFile, *aNode->mData);
}
//
// Textures
//
static void WriteTextureData(FILE* aFile, GfxData* aGfxData, DataNode<TexData> *aNode) {
if (!aNode->mData) return;
// Header
WriteBytes<u8>(aFile, DATA_TYPE_TEXTURE);
aNode->mName.Write(aFile);
// Data
aNode->mData->mPngData.Write(aFile);
}
//
// Vertices
//
static void WriteVertexData(FILE* aFile, GfxData* aGfxData, DataNode<Vtx> *aNode) {
if (!aNode->mData) return;
// Header
WriteBytes<u8>(aFile, DATA_TYPE_VERTEX);
aNode->mName.Write(aFile);
// Data
WriteBytes<u32>(aFile, aNode->mSize);
for (u32 i = 0; i != aNode->mSize; ++i) {
WriteBytes<s16>(aFile, aNode->mData[i].n.ob[0]);
WriteBytes<s16>(aFile, aNode->mData[i].n.ob[1]);
WriteBytes<s16>(aFile, aNode->mData[i].n.ob[2]);
WriteBytes<s16>(aFile, aNode->mData[i].n.flag);
WriteBytes<s16>(aFile, aNode->mData[i].n.tc[0]);
WriteBytes<s16>(aFile, aNode->mData[i].n.tc[1]);
WriteBytes<s8> (aFile, aNode->mData[i].n.n[0]);
WriteBytes<s8> (aFile, aNode->mData[i].n.n[1]);
WriteBytes<s8> (aFile, aNode->mData[i].n.n[2]);
WriteBytes<u8> (aFile, aNode->mData[i].n.a);
}
}
//
// Display lists
//
static void WriteDisplayListData(FILE *aFile, GfxData *aGfxData, DataNode<Gfx> *aNode) {
if (!aNode->mData) return;
// Header
WriteBytes<u8>(aFile, DATA_TYPE_DISPLAY_LIST);
aNode->mName.Write(aFile);
// Data
WriteBytes<u32>(aFile, aNode->mSize);
for (u32 i = 0; i != aNode->mSize; ++i) {
Gfx *_Head = &aNode->mData[i];
if (aGfxData->mPointerList.Find((void *) _Head) != -1) {
WriteBytes<u32>(aFile, _Head->words.w0);
WritePointer(aFile, (const void *) _Head->words.w1, aGfxData);
} else {
WriteBytes<u32>(aFile, _Head->words.w0);
WriteBytes<u32>(aFile, _Head->words.w1);
}
}
}
//
// Geo layouts
//
static void WriteGeoLayoutData(FILE *aFile, GfxData *aGfxData, DataNode<GeoLayout> *aNode) {
if (!aNode->mData) return;
// Header
WriteBytes<u8>(aFile, DATA_TYPE_GEO_LAYOUT);
aNode->mName.Write(aFile);
// Data
WriteBytes<u32>(aFile, aNode->mSize);
for (u32 i = 0; i != aNode->mSize; ++i) {
GeoLayout *_Head = &aNode->mData[i];
if (aGfxData->mPointerList.Find((void *) _Head) != -1) {
WritePointer(aFile, (const void *) (*_Head), aGfxData);
} else {
WriteBytes<u32>(aFile, *((u32 *) _Head));
}
}
}
//
// Animation data
//
static void WriteAnimationData(FILE* aFile, GfxData* aGfxData) {
for (auto& _Node : aGfxData->mAnimations) {
// Value buffer
s32 _ValueBufferIdx = aGfxData->mAnimValues.FindIf([&_Node](const AnimBuffer<s16> *aAnimBuffer) { return aAnimBuffer->first == _Node->mData->mValues.first; });
if (_ValueBufferIdx == -1) {
continue;
}
// Index buffer
s32 _IndexBufferIdx = aGfxData->mAnimIndices.FindIf([&_Node](const AnimBuffer<u16> *aAnimBuffer) { return aAnimBuffer->first == _Node->mData->mIndex.first; });
if (_IndexBufferIdx == -1) {
continue;
}
// Unk0A buffer
s32 _Unk0ABufferIdx = aGfxData->mAnimIndices.FindIf([&_Node](const AnimBuffer<u16> *aAnimBuffer) { return aAnimBuffer->first == _Node->mData->mUnk0A.first; });
if (_Unk0ABufferIdx == -1) {
continue;
}
// Header
WriteBytes<u8>(aFile, DATA_TYPE_ANIMATION);
_Node->mName.Write(aFile);
// Data
WriteBytes<s16>(aFile, _Node->mData->mFlags);
WriteBytes<s16>(aFile, _Node->mData->mUnk02);
WriteBytes<s16>(aFile, _Node->mData->mUnk04);
WriteBytes<s16>(aFile, _Node->mData->mUnk06);
WriteBytes<s16>(aFile, _Node->mData->mUnk08);
WriteBytes<s16>(aFile, (aGfxData->mAnimIndices[_Unk0ABufferIdx]->second.Count() / 6) - 1);
WriteBytes<u32>(aFile, _Node->mData->mLength);
aGfxData->mAnimValues[_ValueBufferIdx]->second.Write(aFile);
aGfxData->mAnimIndices[_IndexBufferIdx]->second.Write(aFile);
}
}
//
// Animation table
//
static void WriteAnimationTable(FILE* aFile, GfxData* aGfxData) {
for (auto& _AnimName : aGfxData->mAnimationTable) {
// Header
WriteBytes<u8>(aFile, DATA_TYPE_ANIMATION_TABLE);
// Data
_AnimName.first.Write(aFile);
}
}
//
// Write
//
bool DynOS_Gfx_WriteBinary(const SysPath &aOutputFilename, GfxData *aGfxData) {
FILE *_File = fopen(aOutputFilename.c_str(), "wb");
if (!_File) {
PrintError(" ERROR: Unable to create file \"%s\"", aOutputFilename.c_str());
return false;
}
for (u64 i = 0; i != aGfxData->mLoadIndex; ++i) {
for (auto &_Node : aGfxData->mLights) {
if (_Node->mLoadIndex == i) {
WriteLightData(_File, aGfxData, _Node);
}
}
for (auto &_Node : aGfxData->mTextures) {
if (_Node->mLoadIndex == i) {
WriteTextureData(_File, aGfxData, _Node);
}
}
for (auto &_Node : aGfxData->mVertices) {
if (_Node->mLoadIndex == i) {
WriteVertexData(_File, aGfxData, _Node);
}
}
for (auto &_Node : aGfxData->mDisplayLists) {
if (_Node->mLoadIndex == i) {
WriteDisplayListData(_File, aGfxData, _Node);
}
}
for (auto &_Node : aGfxData->mGeoLayouts) {
if (_Node->mLoadIndex == i) {
WriteGeoLayoutData(_File, aGfxData, _Node);
}
}
}
WriteAnimationData(_File, aGfxData);
WriteAnimationTable(_File, aGfxData);
fclose(_File);
return true;
}
//
// Free
//
void DynOS_Gfx_Free(GfxData* aGfxData) {
if (aGfxData) {
for (auto& _Node : aGfxData->mLights) {
Delete(_Node->mData);
Delete(_Node);
}
for (auto& _Node : aGfxData->mTextures) {
Delete(_Node->mData);
Delete(_Node);
}
for (auto& _Node : aGfxData->mVertices) {
Delete(_Node->mData);
Delete(_Node);
}
for (auto& _Node : aGfxData->mDisplayLists) {
Delete(_Node->mData);
Delete(_Node);
}
for (auto& _Node : aGfxData->mGeoLayouts) {
Delete(_Node->mData);
Delete(_Node);
}
for (auto& _Node : aGfxData->mAnimations) {
Delete(_Node->mData);
Delete(_Node);
}
Delete(aGfxData);
}
}

826
data/dynos_level.cpp Normal file
View File

@ -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;
}

133
data/dynos_main.cpp Normal file
View File

@ -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;
}

509
data/dynos_misc.cpp Normal file
View File

@ -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;
}

847
data/dynos_opt.cpp Normal file
View File

@ -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

62
data/dynos_opt_config.cpp Normal file
View File

@ -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);
}
}

70
data/dynos_opt_cont.cpp Normal file
View 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;
}

311
data/dynos_opt_render.cpp Normal file
View File

@ -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);
}
}

155
data/dynos_opt_vanilla.cpp Normal file
View File

@ -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;
}

View File

@ -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);
}

34
data/dynos_sanity.c Normal file
View File

@ -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);
}

475
data/dynos_warps.cpp Normal file
View File

@ -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;
}

27
dynos.mk Normal file
View File

@ -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

34
dynos/cheater_menu.txt Normal file
View File

@ -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

View File

View File

View File

234
include/libc/time.h Normal file
View File

@ -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. */

View File

@ -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 & [A]")
#define TEXT_OPT_CANN _("Cannon Anywhere & [C]^")
#define TEXT_OPT_AWK _("AutoWallKick")
#define TEXT_OPT_SHELL _("Get Shell & [R]")
#define TEXT_OPT_BOB _("Get Bobomb & [B]")
#define TEXT_OPT_SPAMBA _("Spamba & [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

215
src/game/cheats_menu.h Normal file
View File

@ -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

1790
src/game/mario_cheats.c Normal file

File diff suppressed because it is too large Load Diff

42
src/game/mario_cheats.h Normal file
View File

@ -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

1283
src/game/time_trials.c Normal file

File diff suppressed because it is too large Load Diff

15
src/game/time_trials.h Normal file
View File

@ -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