diff options
-rw-r--r-- | fileselect.yaml | 1 | ||||
-rwxr-xr-x | include/game.h | 275 | ||||
-rw-r--r-- | include/newer.h | 27 | ||||
-rw-r--r-- | kamek_pal.x | 17 | ||||
-rw-r--r-- | src/fileselect.S | 88 | ||||
-rw-r--r-- | src/koopatlas/hud.cpp | 630 | ||||
-rw-r--r-- | src/koopatlas/hud.h | 69 | ||||
-rw-r--r-- | src/koopatlas/mapdata.cpp | 16 | ||||
-rw-r--r-- | src/koopatlas/mapdata.h | 17 | ||||
-rw-r--r-- | src/koopatlas/pathmanager.cpp | 69 | ||||
-rw-r--r-- | src/koopatlas/pathmanager.h | 2 | ||||
-rw-r--r-- | src/koopatlas/shop.cpp | 22 | ||||
-rw-r--r-- | src/koopatlas/starcoin.cpp | 26 | ||||
-rw-r--r-- | src/newer.cpp | 85 | ||||
-rw-r--r-- | src/palaceDude.cpp | 2 | ||||
-rw-r--r-- | src/replay.S | 6 | ||||
-rw-r--r-- | src/switchblock.S | 6 |
17 files changed, 864 insertions, 494 deletions
diff --git a/fileselect.yaml b/fileselect.yaml index 90c18f9..eb8c107 100644 --- a/fileselect.yaml +++ b/fileselect.yaml @@ -147,6 +147,7 @@ hooks: - {name: DFNiceTitle, type: branch_insn, branch_type: bl, src_addr_pal: 0x8077D044, target_func: 'DFNiceTitle'} - {name: DFNiceWorldName, type: branch_insn, branch_type: bl, src_addr_pal: 0x8077DA10, target_func: 'DFNiceWorldName'} + - {name: DefaultSavefileInfo, type: branch_insn, branch_type: b, src_addr_pal: 0x800CE100, target_func: 'DefaultSavefileInfo'} # - {name: FSDebugStates, type: add_func_pointer, src_addr_pal: 0x80943E38, target_func: 'FSDebugStates'} diff --git a/include/game.h b/include/game.h index 4695ea6..071d93e 100755 --- a/include/game.h +++ b/include/game.h @@ -26,6 +26,7 @@ extern "C" { int wcslen(const wchar_t *str);
int strlen(const char *str);
char *strcpy(char *dest, const char *src);
+char *strncpy(char *dest, const char *src, int num);
int strncmp(const char *str1, const char *str2, int num);
float atan(float x);
@@ -80,9 +81,60 @@ struct StartLevelInfo { unsigned char level2; // 0x0F
};
-extern void *GameMgr;
+class GMgr8 {
+ public:
+ virtual ~GMgr8();
+
+ int _4;
+ float _8, _C;
+ u32 _10, _14;
+ u8 _18, _19, _1A, _1B, _1C;
+ u32 _20, _24, _28, _2C, _30;
+};
+
+struct GMgrA0 {
+ u32 _0, _4, _8;
+ u8 _C;
+};
+
+class GameMgr {
+ public:
+ virtual ~GameMgr();
+
+ u32 _4;
+ GMgr8 eight;
+ u32 _3C, _40, _44, _48, _4C, _50, _54, _58;
+ u32 _5C, _60, _64, _68, _6C;
+ u32 _70[10];
+ u8 _98;
+ u32 _9C;
+ GMgrA0 _A0[40];
+ u32 _320[10], _348[10];
+ u32 _370, _374, _378, _37C;
+ u8 switchPalaceFlag;
+ u32 CharIDs[4];
+ u8 _394;
+ u8 _395[10];
+ u8 _39F[10];
+ u8 _3A9[10];
+ u8 _3B3;
+ u32 numberToInsertInThing[7];
+ u32 msgCategory, msgID;
+ u8 _3D8;
+ u8 currentControllerType, layoutShadowFlag;
+ u32 numberToInsertInThing10, numberToInsertInThing11;
+ u32 _3E4, _3E8, _3EC, _3F0, _3F4, _3F8;
+ // unmapped data from 3FC..AEC (0x6F0)
+ u8 _3FC[0x6F0];
+ u32 _AEC, _AF0, _AF4, _AF8;
+ u8 _AFC, _AFD, _AFE[88];
+ u8 _B56[4];
+ u8 _B5A, _B5B;
+};
+
+extern GameMgr *GameMgrP;
inline void *GetGameMgr() {
- return GameMgr;
+ return GameMgrP;
}
bool QueryPlayerAvailability(int id);
@@ -101,6 +153,31 @@ bool IsWideScreen(); #define COND_SGNORMAL 0x80
#define COND_SGSECRET 0x100
+
+// All of these are set by "SetWorldCompleteionBitfield" (I didn't name it)
+// at 801028D0. It's called by ScStage so it doesn't depend on Nintendo maps.
+
+#define SAVE_BIT_EXISTS_MAYBE 1
+
+// Controls whether you can QUICK SAVE or not.
+// Set if 8-Castle is complete.
+#define SAVE_BIT_GAME_COMPLETE 2
+
+// Set when all exits are complete.
+// This is defined by "ReturnWhetherConditionMaskIsValid" / "SetSomeConditionShit"
+// TODO: Need to RE and fix this for Newer...
+#define SAVE_BIT_ALL_EXITS 4
+
+// Set when all star coins in worlds 1-8 are obtained.
+// Valid levels are chosen by the condition crap as above.
+#define SAVE_BIT_ALL_STAR_COINS 8
+
+#define SAVE_BIT_ALL_STAR_COINS_W9 0x10
+
+// Set when, well... EVERYTHING is done.
+#define SAVE_BIT_EVERYTHING_TRULY_DONE 0x20
+
+
class SaveFirstBlock {
public:
char titleID[4]; // 0x00
@@ -149,7 +226,13 @@ public: struct {
// ALL Newer additions should go here
// This array has been verified as safe to replace
- u8 currentNewerWorld; // 0x6FC
+ char newerWorldName[36]; // 0x6FC
+ GXColor fsTextColours[2]; // 0x720
+ GXColor fsHintColours[2]; // 0x728
+ GXColor hudTextColours[2]; // 0x730
+ s16 hudHintH, hudHintS, hudHintL; // 0x738
+ u8 currentMapMusic; // 0x73E
+ u8 _padding; // 0x73F
};
};
u8 toad_location[10]; // 0x742
@@ -219,9 +302,31 @@ inline SaveHandler *GetSaveHandler() { #define WPAD_MINUS 0x1000
#define WPAD_HOME 0x8000
+struct Remocon {
+ virtual ~Remocon();
+ int id;
+ int controllerType;
+ u32 untouchedButtons;
+ u32 lastUntouchedButtons;
+ u32 heldButtons;
+ u32 lastHeldButtons;
+ u32 nowPressed;
+ u32 _20, _24, _28, _2C, _30;
+ Vec acc, lastAcc;
+ Vec2 accVertical, lastAccVertical;
+ Vec2 vec_5C, lastVec_5C;
+ Vec2 vec_6C;
+ Vec2 vec_74, lastVec_74;
+ float wiimoteMoveDistanceOrSomething;
+ float lastWiimoteMoveDistanceOrSomething;
+ u8 isShaking, _8D;
+ u16 tiltAmount;
+ u8 _90, _91, _92;
+};
+
struct RemoconMngClass {
void *vtable;
- void *controllers[4];
+ Remocon *controllers[4];
};
/*
@@ -246,7 +351,7 @@ inline int GetActiveWiimoteID() { return ActiveWiimoteID;
}
-inline void *GetActiveRemocon() {
+inline Remocon *GetActiveRemocon() {
return GetRemoconMng()->controllers[GetActiveWiimoteID()];
}
@@ -254,11 +359,11 @@ inline void *GetActiveWiimote() { return ActiveWiimote;
}
-inline unsigned int Remocon_GetButtons(void *self) {
+inline unsigned int Remocon_GetButtons(Remocon *self) {
return *((unsigned int*)((u32)self+0x18));
}
-inline unsigned int Remocon_GetPressed(void *self) {
+inline unsigned int Remocon_GetPressed(Remocon *self) {
return *((unsigned int*)((u32)self+0x1C));
}
@@ -480,7 +585,13 @@ namespace ut { LinkListNode initialNode;
};
- class Color : public GXColor { };
+ class Color : public GXColor {
+ public:
+ GXColor& operator=(const GXColor &other) {
+ *((u32*)this) = *((u32*)&other);
+ return *this;
+ }
+ };
class Rect {
public:
@@ -505,6 +616,20 @@ namespace lyt { class Group;
class GroupContainer;
+ namespace detail {
+ class TexCoordAry {
+ public:
+ TexCoordAry();
+ void Free();
+ void Reserve(u8 count);
+ void SetSize(u8 count);
+ void Copy(const void *source, u8 count);
+
+ u8 reservedSize, usedSize;
+ void *data;
+ };
+ }
+
class Layout {
public:
Layout();
@@ -557,9 +682,35 @@ namespace lyt { };
+ class TexMap {
+ public:
+ void *image, *palette;
+ u16 width, height;
+ f32 minLOD, magLOD;
+ u16 lodBias, palEntryNum;
+ struct
+ {
+ u32 textureFormat: 4;
+ u32 mipmap: 1;
+ u32 wrapS: 2;
+ u32 wrapT: 2;
+ u32 minFilter: 3;
+ u32 magFilter: 1;
+ u32 biasClampEnable: 1;
+ u32 edgeLODEnable: 1;
+ u32 anisotropy: 2;
+ u32 paletteFormat: 2;
+ } mBits;
+ };
+
class Material {
public:
- // ...
+ virtual ~Material();
+
+ // cheating a bit here
+ u8 _[0x3C];
+ // this is actually a pointer to more stuff, not just texmaps
+ TexMap *texMaps;
};
class Pane {
@@ -636,11 +787,17 @@ namespace lyt { u8 flag;
char name[0x11];
- char userdata[8];
+ char userdata[9];
- u8 _D5;
u8 paneIsOwnedBySomeoneElse;
u8 _D7;
+
+ void SetVisible(bool value) {
+ if (value)
+ flag |= 1;
+ else
+ flag &= ~1;
+ }
};
class TextBox : public Pane {
@@ -657,7 +814,7 @@ namespace lyt { uchar GetVtxColorElement(ulong id) const;
void SetVtxColorElement(ulong id, uchar value);
- virtual void LoadMtx(const DrawInfo &info);
+ void LoadMtx(const DrawInfo &info);
virtual void AllocStringBuffer(u16 size);
virtual void FreeStringBuffer();
@@ -681,6 +838,26 @@ namespace lyt { u8 alignment;
u8 flags;
};
+
+ class Picture : public Pane {
+ public:
+ Picture(void *, void *); // todo: Picture((res::Picture const *,ResBlockSet const &))
+ ~Picture();
+
+ void *GetRuntimeTypeInfo() const;
+
+ void DrawSelf(const DrawInfo &info);
+
+ ut::Color GetVtxColor(ulong id) const;
+ void SetVtxColor(ulong id, ut::Color color);
+ uchar GetVtxColorElement(ulong id) const;
+ void SetVtxColorElement(ulong id, uchar value);
+
+ virtual void Append(const GXTexObj &obj);
+
+ ut::Color colours[4];
+ detail::TexCoordAry texCoords;
+ };
}
@@ -2487,7 +2664,10 @@ namespace nw4r { void SetupGXWithColorMapping(Color c1, Color c2);
public:
- Color colors[8]; // todo: document
+ Color minColMapping, maxColMapping;
+ Color vtxColours[4];
+ Color topColour, bottomColour;
+
u32 modeOfSomeKind;
float scaleX;
float scaleY;
@@ -2522,12 +2702,12 @@ namespace nw4r { bool IsDrawFlagSet(ulong, ulong) const;
- float _4C;
+ float widthLimit;
float charSpace;
- float somethingRelatedToLineHeight;
- u32 _58;
+ float lineSpace;
+ u32 tabWidth;
u32 drawFlag;
- void *tagProcessorMaybe;
+ void *tagProcessor;
};
}
}
@@ -2667,7 +2847,7 @@ namespace m2d { nw4r::lyt::Pane *getRootPane();
nw4r::lyt::Pane *findPaneByName(const char *name) const;
nw4r::lyt::TextBox *findTextBoxByName(const char *name) const;
- nw4r::lyt::Pane *findPictureByName(const char *name) const; // TODO: change to others
+ nw4r::lyt::Picture *findPictureByName(const char *name) const;
nw4r::lyt::Pane *findWindowByName(const char *name) const;
void animate();
@@ -2705,10 +2885,10 @@ namespace m2d { // does NSMBW even use consts? I have no idea. maybe not
- void getPanes(const char **names, nw4r::lyt::Pane *output, int count) const;
- void getWindows(const char **names, nw4r::lyt::Pane *output, int count) const; // TODO: change to others
- void getPictures(const char **names, nw4r::lyt::Pane *output, int count) const;
- void getTextBoxes(const char **names, nw4r::lyt::TextBox *output, int count) const;
+ void getPanes(const char **names, nw4r::lyt::Pane **output, int count) const;
+ void getWindows(const char **names, nw4r::lyt::Pane **output, int count) const; // TODO: change to others
+ void getPictures(const char **names, nw4r::lyt::Picture **output, int count) const;
+ void getTextBoxes(const char **names, nw4r::lyt::TextBox **output, int count) const;
void setLangStrings(const char **names, const int *msgIDs, int category, int count);
@@ -3072,6 +3252,57 @@ namespace mHeap { };
void WriteNumberToTextBox(int *number, const int *fieldLength, nw4r::lyt::TextBox *textBox, bool unk); // 800B3B60
+
+namespace EGG {
+ class MsgRes {
+ private:
+ const u8 *bmg, *INF1, *DAT1, *STR1, *MID1, *FLW1, *FLI1;
+ public:
+ MsgRes(const u8 *bmgFile, u32 unusedParam); // 802D7970
+ virtual ~MsgRes();
+
+ static void parseFormatCode(wchar_t initialTag, const wchar_t *string, u8 *outArgsSize, u32 *outCmd, const wchar_t **args); // 802D7B10
+
+ const wchar_t *findStringForMessageID(int category, int message) const; // 0x802D7B50
+
+ private:
+ void setBMG(const u8 *ptr); // 802D7B90
+ void setINF(const u8 *ptr); // 802D7BA0
+ void setDAT(const u8 *ptr); // 802D7BB0
+ void setSTR(const u8 *ptr); // 802D7BC0
+ void setMID(const u8 *ptr); // 802D7BD0
+ void setFLW(const u8 *ptr); // 802D7BE0
+ void setFLI(const u8 *ptr); // 802D7BF0
+ int identifySectionByMagic(u32 magic) const; // 802D7C00
+
+ protected:
+ struct INFEntry {
+ u32 stringOffset;
+ };
+ const INFEntry *findINFForMessageID(int category, int message) const; // 802D7C90
+ u32 getEntryFromMID(int index) const; // 802D7D70
+ };
+}
+namespace dScript {
+ class Res_c : public EGG::MsgRes {
+ public:
+ Res_c(const u8 *bmgFile, u32 unusedParam); // 800CE7F0
+ ~Res_c();
+
+ u16 getCharScaleForMessageID(int category, int message) const; // 800CE890
+ u8 getFontIDForMessageID(int category, int message) const; // 800CE8C0
+ };
+}
+class MessageClass {
+ public:
+ dDvdLoader_c loader;
+ void *rawBmgPointer;
+ dScript::Res_c *msgRes;
+};
+
+dScript::Res_c *GetBMG(); // 800CDD50
+void WriteBMGToTextBox(nw4r::lyt::TextBox *textBox, dScript::Res_c *res, int category, int message, int argCount, ...); // 0x800C9B50
+
extern "C" dAc_Py_c* GetSpecificPlayerActor(int number);
extern "C" dStageActor_c *CreateActor(u16 classID, int settings, Vec pos, char rot, char layer);
extern "C" dStageActor_c *Actor_SearchByID(u32 actorID);
diff --git a/include/newer.h b/include/newer.h index 4f34f81..cf21cbb 100644 --- a/include/newer.h +++ b/include/newer.h @@ -1,31 +1,6 @@ #ifndef NEWER_H #define NEWER_H -enum NWRWorld { - ISLAND = 0, YOSHI_ISLAND = 0, - DESERT = 1, RUBBLE_RUINS = 1, - SEWER = 2, SOGGY_SEWERS = 2, - MOUNTAIN = 3, MUSHROOM_PEAKS = 3, - SAKURA = 4, SAKURA_VILLAGE = 4, - FREEZEFLAME = 5, FREEZEFLAME_GLACIER = 5, - VOLCANO = 6, FREEZEFLAME_VOLCANO = 6, - PUMPKIN = 7, PUMPKIN_BONEYARD = 7, - SKY_MOUNTAIN = 8, - SKY = 9, STARRY_SKIES = 9, - PLANET = 10, KOOPA_PLANET = 10, - CORE = 11, KOOPA_CORE = 11, - BONUS_LAND = 12, - GOLDWOOD = 13, GOLDWOOD_FOREST = 13, - MINIMEGA = 14, MINIMEGA_ISLAND = 14, - CRYSTAL = 15, CRYSTAL_CAVES = 15, - BOMBARD = 16, BOMBARD_CLIFFS = 16, - SKY_CITY = 17, - WORLD_COUNT = 18, - UNKNOWN_WORLD = 255 -}; - -NWRWorld NewerWorldForLevelID(int world, int level); - -const wchar_t *NewerWorldName(NWRWorld world); +int getStarCoinCount(); #endif /* NEWER_H */ diff --git a/kamek_pal.x b/kamek_pal.x index 6f7db85..75613ad 100644 --- a/kamek_pal.x +++ b/kamek_pal.x @@ -11,12 +11,17 @@ SECTIONS { __dt__18BGGMEffectRendererFv = 0x80092E30; __vt__18BGGMEffectRenderer = 0x80311908; __construct_array = 0x802DCC90; + + GetBMG__Fv = 0x800CDD50; + WriteBMGToTextBox__FPQ34nw4r3lyt7TextBoxPQ27dScript5Res_ciiie = 0x800C9B50; + m2d__Anm_c__Load = 0x801644F0; m2d__AnmResHandler_c__Load = 0x80163FA0; RealAcPyDtor = 0x80144820; InsertIntIntoTextBox1 = 0x800B3BE0; + WriteNumberToTextBox__FPiPCiPQ34nw4r3lyt7TextBoxb = 0x800B3B60; __ct__20daJrClownForPlayer_cFv = 0x80810480; __dt__20daJrClownForPlayer_cFv = 0x80810540; /* Beans indeed. */ @@ -747,9 +752,15 @@ SECTIONS { findTextBoxByName__Q23m2d17EmbedLayoutBase_cCFPCc = 0x80007320; findPictureByName__Q23m2d17EmbedLayoutBase_cCFPCc = 0x800073D0; findWindowByName__Q23m2d17EmbedLayoutBase_cCFPCc = 0x80007470; + __ct__Q23m2d13EmbedLayout_cFv = 0x800C89A0; __dt__Q23m2d13EmbedLayout_cFv = 0x800C89F0; loadArc__Q23m2d13EmbedLayout_cFPCcb = 0x800C8D00; + getPanes__Q23m2d13EmbedLayout_cCFPPCcPPQ34nw4r3lyt4Panei = 0x800C8E50; + getWindows__Q23m2d13EmbedLayout_cCFPPCcPPQ34nw4r3lyt6Windowi = 0x800C8EC0; + getPictures__Q23m2d13EmbedLayout_cCFPPCcPPQ34nw4r3lyt7Picturei = 0x800C8F30; + getTextBoxes__Q23m2d13EmbedLayout_cCFPPCcPPQ34nw4r3lyt7TextBoxi = 0x800C8FA0; + setLangStrings__Q23m2d13EmbedLayout_cFPPCcPCiii = 0x800C9010; loadAnimations__Q23m2d13EmbedLayout_cFPPCci = 0x800C90A0; loadGroups__Q23m2d13EmbedLayout_cFPPCcPii = 0x800C91E0; enableNonLoopAnim__Q23m2d13EmbedLayout_cFib = 0x800C93E0; @@ -760,7 +771,11 @@ SECTIONS { isAnyAnimOn__Q23m2d13EmbedLayout_cFv = 0x800C9730; free__Q23m2d13EmbedLayout_cFv = 0x800C9A20; execAnimations__Q23m2d13EmbedLayout_cFv = 0x800C9650; + attachArc__Q23m2d8ResAcc_cFPvPCc = 0x801637A0; + + setSpeed__Q23m2d11FrameCtrl_cFf = 0x80163920; + scheduleForDrawing__Q23m2d6Base_cFv = 0x80163990; RenderEffects__Fii = 0x80093F10; @@ -968,7 +983,7 @@ SECTIONS { ArchiveHeap = 0x8042A72C; DVDClass = 0x8042A318; - GameMgr = 0x8042A25C; + GameMgrP = 0x8042A25C; SaveFileInstance = 0x8042A320; SaveHandlerInstance = 0x8042A298; RemoconMng = 0x8042A230; diff --git a/src/fileselect.S b/src/fileselect.S index 9f7f396..6ee1c39 100644 --- a/src/fileselect.S +++ b/src/fileselect.S @@ -54,8 +54,7 @@ DFNiceTitle: bctr .extern findTextBoxByName__Q23m2d17EmbedLayoutBase_cCFPCc -.extern NewerWorldNames -.extern NewerWorldCount +.extern findPictureByName__Q23m2d17EmbedLayoutBase_cCFPCc .extern InsertIntIntoTextBox1 .global DFNiceWorldName DFNiceWorldName: @@ -71,22 +70,21 @@ DFNiceWorldName: stw r25, 0x14(r1) mr r20, r4 - # get Newer map number - lbz r6, 0x6FC(r31) - lis r8, NewerWorldCount@h - ori r8, r8, NewerWorldCount@l - lwz r8, 0(r8) - cmpw r6, r8 - bge invalidThing - slwi r6, r6, 2 - lis r7, NewerWorldNames@h - ori r7, r7, NewerWorldNames@l - lwzx r4, r7, r6 - b gotName -invalidThing: - lis r4, InvalidWorld@h - ori r4, r4, InvalidWorld@l -gotName: + # Savefile is in r31 + # World Name field is in r20 + + lis r4, ConvertedWorldName@h + ori r4, r4, ConvertedWorldName@l + mr r3, r4 + mr r5, r31 + li r6, 36 + mtctr r6 +convWNameLoop: + lbz r6, 0x6FC(r5) + sth r6, 0(r3) + addi r3, r3, 2 + addi r5, r5, 1 + bdnz convWNameLoop mr r3, r20 li r5, 0 @@ -95,6 +93,24 @@ gotName: mtctr r12 bctrl + # now set the colours + # Text colours: 0x720, hint colours: 0x728 + lwz r3, 0x720(r31) + stw r3, 0xDC(r20) + lwz r3, 0x724(r31) + stw r3, 0xE0(r20) + + addi r3, r30, 0x74 + lis r4, Picture_00@h + ori r4, r4, Picture_00@l + bl findPictureByName__Q23m2d17EmbedLayoutBase_cCFPCc + lwz r4, 0x728(r31) + stw r4, 0xD8(r3) + stw r4, 0xDC(r3) + lwz r4, 0x72C(r31) + stw r4, 0xE0(r3) + stw r4, 0xE4(r3) + # While we're at it, take care of some other things # r21 shall hold our star coin count; r22 shall hold our exit count # r23 shall hold the level pointer @@ -231,6 +247,22 @@ FSDebugStates: addi r1, r1, 0x10 blr +.global DefaultSavefileInfo +DefaultSavefileInfo: + addi r4, r3, 0x6FC + lis r5, DefaultSavefileInfoData@h + ori r5, r5, DefaultSavefileInfoData@l + lis r6, DefaultSavefileInfoDataEnd@h + ori r6, r6, DefaultSavefileInfoDataEnd@l +DSFICopyLoop: + lwz r7, 0(r5) + stw r7, 0(r4) + addi r4, r4, 4 + addi r5, r5, 4 + cmpw r5, r6 + blt DSFICopyLoop + blr + .align 4 .data @@ -255,10 +287,26 @@ NormalExitStr: .string "<Normal> %d-%d\n" SecretExitStr: .string "<Secret> %d-%d\n" StarCoinCount: .string "StarCoinCount" ExitCount: .string "ExitCount" +Picture_00: .string "Picture_00" .align 4 DFTitle: .short 'F','i','l','e',' ','X',0 -InvalidWorld: -.short '<','I','n','v','a','l','i','d',' ','W','o','r','l','d','>',0 +ConvertedWorldName: +.short 0,0,0,0,0,0,0,0,0,0,0,0 # 12 +.short 0,0,0,0,0,0,0,0,0,0,0,0 # 12 +.short 0,0,0,0,0,0,0,0,0,0,0,0 # 12 +.align 4 +DefaultSavefileInfoData: +.string "Yoshi's Island" #15 +.byte 0,0,0,0,0,0,0,0,0,0,0 # 11 +.byte 0,0,0,0,0,0,0,0,0,0 # 10 +.long 0xFFFF99FF,0x1FB423FF +.long 0x173714FF,0x3C9135FF +.long 0xFFFF99FF,0x1FB423FF +.short 0x75,0x2E,0xB +.byte 0,0 + +DefaultSavefileInfoDataEnd: +.long 0 diff --git a/src/koopatlas/hud.cpp b/src/koopatlas/hud.cpp index 44b0fce..90e769e 100644 --- a/src/koopatlas/hud.cpp +++ b/src/koopatlas/hud.cpp @@ -1,25 +1,143 @@ #include "koopatlas/hud.h" -void CharToWChar(const char *input, wchar_t *output, int length) { for (int i = 0; i < length; i++) output[i] = input[i]; } -int getStarCoinCount() { +dTexMapColouriser_c::dTexMapColouriser_c() { + texmap = 0; + original = 0; + mine = 0; +} - SaveBlock *save = GetSaveFile()->GetBlock(-1); - int coinsSpent = save->credits_hiscore; - int coinsEarned = 0; +void *EGG__Heap__alloc(unsigned long size, int unk, void *heap); +void EGG__Heap__free(void *ptr, void *heap); - for (int w = 0; w < 10; w++) { - for (int l = 0; l < 10; l++) { - u32 conds = save->GetLevelCondition(w, l); +dTexMapColouriser_c::~dTexMapColouriser_c() { + resetAndClear(); +} - if (conds & COND_COIN1) { coinsEarned++; } - if (conds & COND_COIN2) { coinsEarned++; } - if (conds & COND_COIN3) { coinsEarned++; } - } +void dTexMapColouriser_c::resetAndClear() { + texmap = 0; + if (mine) { + EGG__Heap__free(mine, 0); + mine = 0; + } +} + +void dTexMapColouriser_c::setTexMap(nw4r::lyt::TexMap *tm) { + OSReport("Colourising TexMap: %p (w:%d h:%d)\n", tm, tm->width, tm->height); + if (texmap) + resetAndClear(); + + if (tm->mBits.textureFormat != GX_TF_IA8) { + OSReport("Warning: Trying to colourise image whose format is %d not GX_TF_IA8\n", tm->mBits.textureFormat); } - int coinsLeft = coinsEarned - coinsSpent; - return coinsLeft; + texmap = tm; + original = (u16*)tm->image; + mine = (u16*)EGG__Heap__alloc(tm->width * tm->height * 4, 0x20, mHeap::gameHeaps[2]); + tm->image = mine; + tm->mBits.textureFormat = GX_TF_RGBA8; +} + +void dTexMapColouriser_c::applyAlso(nw4r::lyt::TexMap *tm) { + if (!texmap) { + setTexMap(tm); + } else { + tm->image = mine; + tm->mBits.textureFormat = GX_TF_RGBA8; + } +} + +inline static float hslValue(float n1, float n2, float hue) { + if (hue > 6.0f) + hue -= 6.0f; + else if (hue < 0.0f) + hue += 6.0f; + + if (hue < 1.0f) + return n1 + (n1 - n1) * hue; + else if (hue < 3.0f) + return n2; + else if (hue < 4.0f) + return n1 + (n2 - n1) * (4.0f - hue); + else + return n1; +} + +void dTexMapColouriser_c::colourise(int h, int s, int l) { + if (!mine) + return; + + int width = texmap->width, height = texmap->height; + int texelW = width / 4, texelH = height / 4; + + u16 *source = original, *dest = mine; + + float hueParam = h / 360.0f; + float satParam = s / 100.0f; + float lumParam = l / 100.0f; + + for (int texelY = 0; texelY < texelH; texelY++) { + for (int texelX = 0; texelX < texelW; texelX++) { + for (int y = 0; y < 4; y++) { + for (int x = 0; x < 4; x++) { + u8 intensity = *source & 0xFF; + u8 alpha = *source >> 8; + + u8 r, g, b; + + // This is a hack + if (alpha < 250) { + r = g = b = intensity; + } else { + // converting from GIMP's colourise code... + // h and s are always the same + // l is the only thing we need to touch: + // we get the luminance from the source pixel + // (which, conveniently, is the intensity) + // manipulate it using the passed l and then + // convert the whole thing to RGB + + float lum = intensity / 255.0f; + + // manipulate it + if (l > 0) { + lum = lum * (1.0f - lumParam); + lum += (1.0f - (1.0f - lumParam)); + } else if (l < 0) { + lum = lum * (lumParam + 1.0f); + } + + // make it RGB + + if (s == 0) { + r = g = b = lum*255.0f; + } else { + float m1, m2; + if (lum <= 0.5f) + m2 = lum * (1.0f + satParam); + else + m2 = lum + satParam - lum * satParam; + + m1 = 2.0f * lum - m2; + + r = hslValue(m1, m2, hueParam * 6.0f + 2.0) * 255.0f; + g = hslValue(m1, m2, hueParam * 6.0f) * 255.0f; + b = hslValue(m1, m2, hueParam * 6.0f - 2.0) * 255.0f; + } + } + + // now write it + dest[0] = (alpha<<8)|r; + dest[16] = (g<<8)|b; + + source++; + dest++; + } + } + + dest += 16; + } + } } @@ -37,27 +155,22 @@ dWMHud_c *dWMHud_c::build() { dWMHud_c::dWMHud_c() { layoutLoaded = false; + displayedControllerType = -1; } +enum WMHudAnimation { + SHOW_LIVES = 0, + SHOW_HEADER, + SHOW_FOOTER +}; -// TODO: Need to define these in a better way, somehow -#define ANIM_BUTTON_1 0 -#define ANIM_BUTTON_2 1 -#define ANIM_BOTTOM_SHOW 2 -#define ANIM_BOTTOM_HIDE 3 -#define ANIM_TOP_SHOW 4 -#define ANIM_TOP_HIDE 5 int dWMHud_c::onCreate() { if (!layoutLoaded) { - bool gotFile = layout.loadArc("maphud.arc", false); + bool gotFile = layout.loadArc("MapHUD.arc", false); if (!gotFile) return false; - //static const char *brlanNames[3] = {"maphud_hitbutton.brlan", "maphud_in.brlan", "maphud_out.brlan"}; - static const char *brlanNames[5] = {"maphud_hitbutton.brlan", "bottom_in.brlan", "bottom_out.brlan", "top_in.brlan", "top_out.brlan"}; - static const char *groupNames[6] = {"B01_Button", "B02_Button", "A00_Window", "A00_Window", "A01_Window", "A01_Window"}; - bool output = layout.build("maphud.brlyt"); if (!IsWideScreen()) { @@ -70,19 +183,62 @@ int dWMHud_c::onCreate() { layout.layout.rootPane->scale.y = 0.7711f; } - layout.loadAnimations(brlanNames, 5); - layout.loadGroups(groupNames, (int[6]){0, 0, 1, 2, 3, 4}, 6); - layout.disableAllAnimations(); - layout.enableNonLoopAnim(ANIM_BOTTOM_SHOW); + static const char *brlanNames[2] = {"MapHUD_ShowMain.brlan", "MapHUD_ShowHeader.brlan"}; + static const char *groupNames[3] = {"G_Lives", "G_Header", "G_Footer"}; - hidePointBar(); - setWorldText(" "); - setWorldName(); + layout.loadAnimations(brlanNames, 2); + layout.loadGroups(groupNames, (int[3]){0, 1, 0}, 3); + layout.disableAllAnimations(); - if (dScKoopatlas_c::instance->pathManager.mustComplainToMapCreator) - dWMHud_c::instance->setLevelText("Please Fix Your Missing Entrance. Thanks"); + layout.enableNonLoopAnim(SHOW_LIVES); + layout.enableNonLoopAnim(SHOW_FOOTER); + layout.resetAnim(SHOW_HEADER); + + static const char *tbNames[2] = {"MenuButtonInfo", "ItemsButtonInfo"}; + layout.setLangStrings(tbNames, (int[2]){12, 15}, 4, 2); + + static const char *paneNames[] = { + "N_IconPos1P_00", "N_IconPos2P_00", + "N_IconPos3P_00", "N_IconPos4P_00" + }; + layout.getPanes(paneNames, &N_IconPosXP_00[0], 4); + + static const char *pictureNames[] = { + "Header_Centre", "Header_Right", "Footer", + "NormalExitFlag", "SecretExitFlag", + "StarCoinOn0", "StarCoinOn1", "StarCoinOn2", + "P_marioFace_00", "P_luigiFace_00", + "P_BkinoFace_00", "P_YkinoFace_00" + }; + layout.getPictures(pictureNames, &Header_Centre, 12); + + static const char *textBoxNames[] = { + "LevelName", "LevelNameS", + "LevelNumber", "LevelNumberS", + "WorldName", "WorldNameS", + "StarCoinCounter", + "T_lifeNumber_00", "T_lifeNumber_01", + "T_lifeNumber_02", "T_lifeNumber_03" + }; + layout.getTextBoxes(textBoxNames, &LevelName, 11); + + headerCol.setTexMap(Header_Right->material->texMaps); + headerCol.applyAlso(Header_Centre->material->texMaps); + footerCol.setTexMap(Footer->material->texMaps); layoutLoaded = true; + + layout.drawOrder = 0; + + willShowHeader = false; + willShowFooter = false; + + loadFooterInfo(); + + if (!dScKoopatlas_c::instance->pathManager.isMoving) + enteredNode(); + + setupLives(); } return true; @@ -90,15 +246,37 @@ int dWMHud_c::onCreate() { int dWMHud_c::onDelete() { + dWMHud_c::instance = 0; + + if (!layoutLoaded) + return true; + return layout.free(); } int dWMHud_c::onExecute() { - updateLives(); - setWorldName(); - checkPointStatus(); - setPointName(); + if (!layoutLoaded) + return true; + + if (willShowHeader && (!(layout.isAnimOn(SHOW_HEADER)))) { + willShowHeader = false; + loadHeaderInfo(); + playShowAnim(SHOW_HEADER); + } + + if (willShowFooter && (!(layout.isAnimOn(SHOW_FOOTER)))) { + willShowFooter = false; + loadFooterInfo(); + playShowAnim(SHOW_FOOTER); + } + + setupLives(); // FUCK IT + updatePressableButtonThingies(); + + int scCount = getStarCoinCount(); + int scLength = 3; + WriteNumberToTextBox(&scCount, &scLength, StarCoinCounter, false); layout.execAnimations(); layout.update(); @@ -108,303 +286,207 @@ int dWMHud_c::onExecute() { int dWMHud_c::onDraw() { + if (!layoutLoaded) + return true; + layout.scheduleForDrawing(); return true; } -void dWMHud_c::updateLives() { - - static const char *textID[4] = {"M", "L", "B", "Y"}; - static const char *picID[4] = {"P_mariopic", "P_luigipic", "P_toadBlue", "P_toadyellow"}; - - for (int i = 0; i < 4; i++) { - char boxName [13]; - sprintf(boxName, "T_%slifes_01", textID[i]); - nw4r::lyt::TextBox *box = layout.findTextBoxByName(boxName); - nw4r::lyt::Pane *pic = layout.findPictureByName(picID[i]); - if (Player_Active[i] != 0) { - box->alpha = 0xFF; - pic->alpha = 0xFF; +void dWMHud_c::playShowAnim(int id) { + if (!this || !this->layoutLoaded) return; - char lives [3]; - sprintf(lives, "%02d", Player_Lives[Player_ID[i]]); - const char *loaves = lives; - wchar_t life; + layout.enableNonLoopAnim(id); +} - CharToWChar(loaves, &life, 3); +void dWMHud_c::playHideAnim(int id) { + if (!this || !this->layoutLoaded) return; - box->SetString(&life); - } - else { - box->alpha = 0; - pic->alpha = 0; - } + if (!layout.isAnimOn(id)) { + layout.enableNonLoopAnim(id, true); } + layout.grpHandlers[id].frameCtrl.flags = 3; // NO_LOOP | REVERSE +} - nw4r::lyt::TextBox *coinbox = layout.findTextBoxByName("T_coin_count_01"); - - char stars [4]; - int starCoinCount = getStarCoinCount(); - sprintf(stars, "%03d", starCoinCount); - const char *scoins = stars; - wchar_t wcoins; - CharToWChar(scoins, &wcoins, 4); +void dWMHud_c::loadHeaderInfo() { + dLevelInfo_c *levelInfo = &dScKoopatlas_c::instance->levelInfo; - coinbox->SetString(&wcoins); -} + dLevelInfo_c::entry_s *infEntry = levelInfo->search( + nodeForHeader->levelNumber[0]-1, nodeForHeader->levelNumber[1]-1); -void dWMHud_c::setLevelText(const char *str, int length) { - if (str == 0) { - setLevelText("--NULL STRING--"); + if (infEntry == 0) { + LevelName->SetString(L"Unknown Level Name!"); + LevelNameS->SetString(L"Unknown Level Name!"); return; } - if (length == -1) { - length = strlen(str); + // LEVEL NAME + wchar_t convertedLevelName[100]; + const char *sourceLevelName = levelInfo->getNameForLevel(infEntry); + int charCount = 0; + + while (*sourceLevelName != 0 && charCount < 99) { + convertedLevelName[charCount] = *sourceLevelName; + sourceLevelName++; + charCount++; } - - wchar_t newString[128]; - - int i; - for (i = 0; i < length && i < 128; i++) { - newString[i] = str[i]; + convertedLevelName[charCount] = 0; + + LevelName->SetString(convertedLevelName); + LevelNameS->SetString(convertedLevelName); + + // LEVEL NUMBER + wchar_t levelNumber[6]; + levelNumber[0] = '0' + nodeForHeader->levelNumber[0]; + levelNumber[1] = '-'; + if (nodeForHeader->levelNumber[1] >= 10) { + levelNumber[2] = '0' + (nodeForHeader->levelNumber[1] / 10); + levelNumber[3] = '0' + (nodeForHeader->levelNumber[1] % 10); + levelNumber[4] = 0; + } else { + levelNumber[2] = '0' + nodeForHeader->levelNumber[1]; + levelNumber[3] = 0; } - newString[i] = 0; - setLevelText(newString, i); -} + LevelNumber->SetString(levelNumber); + LevelNumberS->SetString(levelNumber); -void dWMHud_c::setLevelText(const wchar_t *str, int length) { - if (str == 0) { - setLevelText("--NULL STRING--"); - return; - } + // INFO + int w = nodeForHeader->levelNumber[0] - 1; + int l = nodeForHeader->levelNumber[1] - 1; - if (length == -1) { - length = wcslen(str); - } - - nw4r::lyt::TextBox *box = layout.findTextBoxByName("T_levelname_01"); + u32 conds = GetSaveFile()->GetBlock(-1)->GetLevelCondition(w, l); + NormalExitFlag->SetVisible(conds & COND_NORMAL); + SecretExitFlag->SetVisible(conds & COND_SECRET); + StarCoinOn[0]->SetVisible(conds & COND_COIN1); + StarCoinOn[1]->SetVisible(conds & COND_COIN2); + StarCoinOn[2]->SetVisible(conds & COND_COIN3); + // SIZE THING nw4r::ut::TextWriter tw; - tw.font = box->font; - tw.SetFontSize(box->fontSizeX, box->fontSizeY); - tw.somethingRelatedToLineHeight = box->lineSpace; - tw.charSpace = box->charSpace; - if (box->tagProc != 0) - tw.tagProcessorMaybe = box->tagProc; - - float width = tw.CalcStringWidth(str, length); - //SpammyReport("Text width: %f\n", width); - - layout.findWindowByName("W_levelname")->size.x = width + 22; - layout.findPictureByName("P_topleftboxbg")->size.x = width; - layout.findPictureByName("P_topthinboxbg")->size.x = 597 - width; + tw.font = LevelName->font; + tw.SetFontSize(LevelName->fontSizeX, LevelName->fontSizeY); + tw.lineSpace = LevelName->lineSpace; + tw.charSpace = LevelName->charSpace; + if (LevelName->tagProc != 0) + tw.tagProcessor = LevelName->tagProc; + + float width = tw.CalcStringWidth(convertedLevelName, charCount); + float totalWidth = width + LevelName->trans.x - 20.0f; + if (totalWidth < 270.0f) + totalWidth = 270.0f; + Header_Centre->size.x = totalWidth; + Header_Right->trans.x = totalWidth; - box->SetString(str); + SaveBlock *save = GetSaveFile()->GetBlock(-1); + headerCol.colourise(save->hudHintH, save->hudHintS, save->hudHintL); } -void dWMHud_c::setPointName() { - // figure this out... - dKPNode_s *node = dScKoopatlas_c::instance->pathManager.currentNode; - - if (node->type == dKPNode_s::LEVEL) { - dLevelInfo_c *li = &dScKoopatlas_c::instance->levelInfo; - dLevelInfo_c::entry_s *entry = li->search(node->levelNumber[0] - 1, node->levelNumber[1] - 1); +void dWMHud_c::loadFooterInfo() { + SaveBlock *save = GetSaveFile()->GetBlock(-1); - setLevelText(li->getNameForLevel(entry)); - } else { - setLevelText(" "); - hidePointBar(); + wchar_t convertedWorldName[36]; + int i; + for (i = 0; i < 36; i++) { + convertedWorldName[i] = save->newerWorldName[i]; + if (convertedWorldName[i] == 0) + break; } -} - -void dWMHud_c::checkPointStatus() { - dKPNode_s *node = dScKoopatlas_c::instance->pathManager.currentNode; - - if ((node->type == dKPNode_s::LEVEL) && ((node->levelNumber[1] < 30) || (node->levelNumber[1] > 37))) { - SaveBlock *save = GetSaveFile()->GetBlock(-1); - - int world = node->levelNumber[0]; - int level = node->levelNumber[1]; - - u32 conds = save->GetLevelCondition(world-1, level-1); - nw4r::lyt::Pane *pic; - - if (conds & COND_COIN1) { - pic = layout.findPictureByName("P_coin_on_01"); - pic->alpha = 0xFF; - - pic = layout.findPictureByName("P_coin_off_01"); - pic->alpha = 0; - } - else { - pic = layout.findPictureByName("P_coin_on_01"); - pic->alpha = 0; - - pic = layout.findPictureByName("P_coin_off_01"); - pic->alpha = 0xFF; - } + convertedWorldName[35] = 0; - if (conds & COND_COIN2) { - pic = layout.findPictureByName("P_coin_on_02"); - pic->alpha = 0xFF; + WorldName->SetString(convertedWorldName); + WorldNameS->SetString(convertedWorldName); - pic = layout.findPictureByName("P_coin_off_02"); - pic->alpha = 0; - } - else { - pic = layout.findPictureByName("P_coin_on_02"); - pic->alpha = 0; - - pic = layout.findPictureByName("P_coin_off_02"); - pic->alpha = 0xFF; - } - - if (conds & COND_COIN3) { - pic = layout.findPictureByName("P_coin_on_03"); - pic->alpha = 0xFF; - - pic = layout.findPictureByName("P_coin_off_03"); - pic->alpha = 0; - } - else { - pic = layout.findPictureByName("P_coin_on_03"); - pic->alpha = 0; - - pic = layout.findPictureByName("P_coin_off_03"); - pic->alpha = 0xFF; - } - - if (conds & COND_NORMAL) { - pic = layout.findPictureByName("P_normalexitflag"); - pic->alpha = 0xFF; - } - else { - pic = layout.findPictureByName("P_normalexitflag"); - pic->alpha = 0; - } - - if (conds & COND_SECRET) { - pic = layout.findPictureByName("P_secretexitflag"); - pic->alpha = 0xFF; - } - else { - pic = layout.findPictureByName("P_secretexitflag"); - pic->alpha = 0; - } + WorldName->colour1 = save->hudTextColours[0]; + WorldName->colour2 = save->hudTextColours[1]; - u8 deaths = save->death_counts[world-1][level-1]; - nw4r::lyt::TextBox *deathbox = layout.findTextBoxByName("T_death_01"); - - char die [4]; - sprintf(die, "%03d", deaths); - const char *dies = die; - wchar_t wdie; - CharToWChar(dies, &wdie, 4); - deathbox->SetString(&wdie); + footerCol.colourise(save->hudHintH, save->hudHintS, save->hudHintL); +} - } else { - nw4r::lyt::Pane *pic; - static const char *picNames[8] = {"P_coin_on_01", "P_coin_off_01", "P_coin_on_02", "P_coin_off_02", - "P_coin_on_03", "P_coin_off_03", "P_normalexitflag", "P_secretexitflag"}; - for (int i = 0; i < 8; i++) { - pic = layout.findPictureByName(picNames[i]); - pic->alpha = 0; - } +void dWMHud_c::enteredNode(dKPNode_s *node) { + if (node == 0) + node = dScKoopatlas_c::instance->pathManager.currentNode; - nw4r::lyt::TextBox *deathbox = layout.findTextBoxByName("T_death_01"); - wchar_t noDie; - CharToWChar("---", &noDie, 4); - deathbox->SetString(&noDie); + if (node->type == dKPNode_s::LEVEL) { + willShowHeader = true; + nodeForHeader = node; } } -void dWMHud_c::setWorldText(const char *str, int length) { - if (str == 0) { - setWorldText("--NULL STRING--"); - return; - } +void dWMHud_c::leftNode() { + if (layout.grpHandlers[SHOW_HEADER].frameCtrl.currentFrame > 0.1f) { + // not hidden - if (length == -1) { - length = strlen(str); + if ((layout.isAnimOn(SHOW_HEADER) && (layout.grpHandlers[SHOW_HEADER].frameCtrl.flags & 2)) + || (!layout.isAnimOn(SHOW_HEADER))) { + // currently being shown, OR fully shown already + playHideAnim(SHOW_HEADER); + } } +} - wchar_t newString[128]; - int i; - for (i = 0; i < length && i < 128; i++) { - newString[i] = str[i]; - } - newString[i] = 0; - - setWorldText(newString, i); +void dWMHud_c::hideAndShowFooter() { + willShowFooter = true; + playHideAnim(SHOW_FOOTER); } -void dWMHud_c::setWorldText(const wchar_t *str, int length) { - if (str == 0) { - setWorldText("--NULL STRING--"); - return; - } - - if (length == -1) { - length = wcslen(str); - } - nw4r::lyt::TextBox *box = layout.findTextBoxByName("T_area_01"); +void dWMHud_c::setupLives() { + static const int LogicalPlayerIDs[] = {0,1,3,2}; - nw4r::ut::TextWriter tw; - tw.font = box->font; - tw.SetFontSize(box->fontSizeX, box->fontSizeY); - tw.somethingRelatedToLineHeight = box->lineSpace; - tw.charSpace = box->charSpace; - if (box->tagProc != 0) - tw.tagProcessorMaybe = box->tagProc; + P_marioFace_00->SetVisible(false); + P_luigiFace_00->SetVisible(false); + P_BkinoFace_00->SetVisible(false); + P_YkinoFace_00->SetVisible(false); - float width = tw.CalcStringWidth(str, length); - //SpammyReport("Text width: %f\n", width); + int playerCount = 0; - box->SetString(str); -} + for (int i = 0; i < 4; i++) { + // The part in setupLives() + int playerID = LogicalPlayerIDs[i]; + int slotID = SearchForIndexOfPlayerID(playerID); + int lives = Player_Lives[slotID]; + int length = 2; -void dWMHud_c::setWorldName() { - // figure this out... - dKPNode_s *node = dScKoopatlas_c::instance->pathManager.currentNode; + WriteNumberToTextBox(&lives, &length, T_lifeNumber[slotID], true); - if (node->type == dKPNode_s::LEVEL) { - int world = node->levelNumber[0]; - int level = node->levelNumber[1]; + // The part in setupIconThings() + if (QueryPlayerAvailability(slotID)) { + playerCount++; - setWorldText(NewerWorldName(NewerWorldForLevelID(world, level))); + nw4r::lyt::Pane *facePane = (&P_marioFace_00)[playerID]; + facePane->trans = N_IconPosXP_00[i]->trans; + facePane->SetVisible(true); + } } -} - -void dWMHud_c::showPointBar() { - dKPNode_s *node = dScKoopatlas_c::instance->pathManager.currentNode; - - if (node->type == dKPNode_s::LEVEL) { - isPointBarShown = true; - layout.enableNonLoopAnim(ANIM_TOP_SHOW); - } + for (int i = 0; i < 4; i++) + N_IconPosXP_00[i]->SetVisible(false); + N_IconPosXP_00[playerCount - 1]->SetVisible(true); } +void dWMHud_c::updatePressableButtonThingies() { + int cntType = RemoconMng->controllers[0]->controllerType; + + if (cntType != displayedControllerType) { + displayedControllerType = cntType; -void dWMHud_c::hidePointBar() { - if (isPointBarShown) { - isPointBarShown = false; + int beef = (cntType == 0) ? 0 : 1; + GameMgrP->currentControllerType = beef; - layout.enableNonLoopAnim(ANIM_TOP_HIDE); + WriteBMGToTextBox( + layout.findTextBoxByName("ItemsButtonInfo"), + GetBMG(), 4, 15, 0); } } - diff --git a/src/koopatlas/hud.h b/src/koopatlas/hud.h index 347fcb4..c0079af 100644 --- a/src/koopatlas/hud.h +++ b/src/koopatlas/hud.h @@ -3,6 +3,23 @@ #include "koopatlas/core.h" +// Colourises an IA8 texture +class dTexMapColouriser_c { + public: + dTexMapColouriser_c(); + ~dTexMapColouriser_c(); + + void resetAndClear(); + void setTexMap(nw4r::lyt::TexMap *tm); + void applyAlso(nw4r::lyt::TexMap *tm); + void colourise(int h, int s, int l); + + private: + nw4r::lyt::TexMap *texmap; + u16 *original; + u16 *mine; +}; + class dWMHud_c : public dBase_c { public: dWMHud_c(); @@ -15,25 +32,49 @@ class dWMHud_c : public dBase_c { bool layoutLoaded; m2d::EmbedLayout_c layout; - void updateLives(); + static dWMHud_c *build(); + static dWMHud_c *instance; - void showPointBar(); - void hidePointBar(); + void enteredNode(dKPNode_s *node = 0); + void leftNode(); - void setPointName(); - void checkPointStatus(); - void setLevelText(const char *str, int length = -1); - void setLevelText(const wchar_t *str, int length = -1); + void hideAndShowFooter(); - void setWorldName(); - void setWorldText(const char *str, int length = -1); - void setWorldText(const wchar_t *str, int length = -1); - - static dWMHud_c *build(); - static dWMHud_c *instance; + void setupLives(); private: - bool isPointBarShown; + void playShowAnim(int id); + void playHideAnim(int id); + void loadHeaderInfo(); + + bool willShowHeader; + dKPNode_s *nodeForHeader; + + int displayedControllerType; + void updatePressableButtonThingies(); + + void loadFooterInfo(); + bool willShowFooter; + + dTexMapColouriser_c headerCol, footerCol; + + + nw4r::lyt::Pane + *N_IconPosXP_00[4]; + + nw4r::lyt::Picture + *Header_Centre, *Header_Right, *Footer, + *NormalExitFlag, *SecretExitFlag, + *StarCoinOn[3], + *P_marioFace_00, *P_luigiFace_00, + *P_BkinoFace_00, *P_YkinoFace_00; + + nw4r::lyt::TextBox + *LevelName, *LevelNameS, + *LevelNumber, *LevelNumberS, + *WorldName, *WorldNameS, + *StarCoinCounter, + *T_lifeNumber[4]; }; #endif diff --git a/src/koopatlas/mapdata.cpp b/src/koopatlas/mapdata.cpp index cbd0c69..d766bed 100644 --- a/src/koopatlas/mapdata.cpp +++ b/src/koopatlas/mapdata.cpp @@ -205,6 +205,12 @@ void dKPMapData_c::fixup() { fixRef(data->unlockData); fixRef(data->sectors); fixRef(data->backgroundName); + if (data->version >= 2) { + fixRef(data->worlds); + for (int i = 0; i < data->worldCount; i++) { + fixRef(data->worlds[i].name); + } + } for (int iLayer = 0; iLayer < data->layerCount; iLayer++) { dKPLayer_s *layer = fixRef(data->layers[iLayer]); @@ -280,6 +286,16 @@ void dKPMapData_c::fixup() { } +const dKPWorldDef_s *dKPMapData_c::findWorldDef(int id) const { + for (int i = 0; i < data->worldCount; i++) { + if (data->worlds[i].key == id) + return &data->worlds[i]; + } + + return 0; +} + + /****************************************************************************** * Generic Layer ******************************************************************************/ diff --git a/src/koopatlas/mapdata.h b/src/koopatlas/mapdata.h index bc0c599..f7194ef 100644 --- a/src/koopatlas/mapdata.h +++ b/src/koopatlas/mapdata.h @@ -53,7 +53,7 @@ struct dKPPath_s; struct dKPNode_s { enum NodeTypes { - PASS_THROUGH, STOP, LEVEL, CHANGE + PASS_THROUGH, STOP, LEVEL, CHANGE, WORLD_CHANGE }; short x, y; @@ -79,6 +79,7 @@ struct dKPNode_s { union { struct { u8 levelNumber[2]; bool hasSecret; }; struct { const char *destMap; u8 thisID, foreignID, transition, _; }; + struct { u8 worldID, __[3]; }; }; dKPPath_s *getAnyExit() { @@ -187,6 +188,15 @@ struct dKPLayer_s { int findNodeID(dKPNode_s *node); }; +struct dKPWorldDef_s { + const char *name; + GXColor fsTextColours[2]; + GXColor fsHintColours[2]; + GXColor hudTextColours[2]; + s16 hudHintH, hudHintS, hudHintL; + u8 key, trackID; +}; + struct dKPMapFile_s { u32 magic; int version; @@ -202,6 +212,9 @@ struct dKPMapFile_s { dKPLayer_s::sector_s *sectors; const char *backgroundName; + + dKPWorldDef_s *worlds; + int worldCount; }; class dKPMapData_c { @@ -253,6 +266,8 @@ class dKPMapData_c { dKPNodeExtra_c *levelNodeExtraArray; + const dKPWorldDef_s *findWorldDef(int id) const; + dKPMapData_c(); bool load(const char *filename); ~dKPMapData_c(); diff --git a/src/koopatlas/pathmanager.cpp b/src/koopatlas/pathmanager.cpp index 2b85aaa..8a05ea4 100644 --- a/src/koopatlas/pathmanager.cpp +++ b/src/koopatlas/pathmanager.cpp @@ -372,10 +372,12 @@ void dWMPathManager_c::execute() { void dWMPathManager_c::startMovementTo(dKPPath_s *path) { SpammyReport("moving to path %p [%d,%d to %d,%d]\n", path, path->start->x, path->start->y, path->end->x, path->end->y); - dWMHud_c::instance->hidePointBar(); - SpammyReport("point bar hidden\n"); if (!path->isAvailable) { return; } + if (currentNode && dWMHud_c::instance) + dWMHud_c::instance->leftNode(); + + calledEnteredNode = false; SpammyReport("a\n"); isMoving = true; @@ -549,6 +551,18 @@ void dWMPathManager_c::moveThroughPath() { player->pos.x += move.x; player->pos.y -= move.y; + // what distance is left? + if (to->type == dKPNode_s::LEVEL && !calledEnteredNode) { + Vec toEndVec = {to->x - player->pos.x, to->y + player->pos.y, 0.0f}; + float distToEnd = VECMag(&toEndVec); + //OSReport("Distance: %f; To:%d,%d; Player:%f,%f; Diff:%f,%f\n", distToEnd, to->x, to->y, player->pos.x, player->pos.y, toEndVec.x, toEndVec.y); + + if (distToEnd < 64.0f && dWMHud_c::instance) { + calledEnteredNode = true; + dWMHud_c::instance->enteredNode(to); + } + } + // Check if we've reached the end yet if ( (((move.x > 0) ? (player->pos.x >= to->x) : (player->pos.x <= to->x)) && @@ -564,15 +578,15 @@ void dWMPathManager_c::moveThroughPath() { isJumping = false; timer = 0.0; - SpammyReport("reached path end (%p)\n", to); + SpammyReport("reached path end (%p) with type %d\n", to, to->type); bool reallyStop = false; if (to->type == dKPNode_s::LEVEL) { // Always stop on levels reallyStop = true; - } else if (to->type == dKPNode_s::CHANGE) { - // Never stop on entrances + } else if (to->type == dKPNode_s::CHANGE || to->type == dKPNode_s::WORLD_CHANGE) { + // Never stop on entrances or on world changes reallyStop = false; } else if (to->type == dKPNode_s::PASS_THROUGH) { // If there's only one exit here, then stop even though @@ -588,6 +602,39 @@ void dWMPathManager_c::moveThroughPath() { reallyStop = true; } + if (to->type == dKPNode_s::WORLD_CHANGE) { + // Set the current world info + SaveBlock *save = GetSaveFile()->GetBlock(-1); + + OSReport("Activating world change %d\n", to->worldID); + const dKPWorldDef_s *world = dScKoopatlas_c::instance->mapData.findWorldDef(to->worldID); + if (world) { + if (strncmp(save->newerWorldName, world->name, 36) == 0) { + OSReport("Already here\n"); + } else { + OSReport("Found!\n"); + strncpy(save->newerWorldName, world->name, 36); + save->newerWorldName[35] = 0; + save->currentMapMusic = world->trackID; + + for (int i = 0; i < 2; i++) { + save->fsTextColours[i] = world->fsTextColours[i]; + save->fsHintColours[i] = world->fsHintColours[i]; + save->hudTextColours[i] = world->hudTextColours[i]; + } + + save->hudHintH = world->hudHintH; + save->hudHintS = world->hudHintS; + save->hudHintL = world->hudHintL; + + if (dWMHud_c::instance) + dWMHud_c::instance->hideAndShowFooter(); + } + } else { + OSReport("Not found!\n"); + } + } + if (to->type == dKPNode_s::CHANGE) { // Go to another map @@ -621,16 +668,8 @@ void dWMPathManager_c::moveThroughPath() { SaveBlock *save = GetSaveFile()->GetBlock(-1); save->current_path_node = pathLayer->findNodeID(to); - - if (to->type == dKPNode_s::LEVEL) { - NWRWorld nWorld = NewerWorldForLevelID(to->levelNumber[0], to->levelNumber[1]); - if (nWorld != UNKNOWN_WORLD) { - save->currentNewerWorld = (u8)nWorld; - } - } - - dWMHud_c::instance->showPointBar(); - SpammyReport("Point bar shown\n"); + if (!calledEnteredNode && dWMHud_c::instance) + dWMHud_c::instance->enteredNode(); } else { startMovementTo(to->getOppositeAvailableExitTo(currentPath)); SpammyReport("passthrough node, continuing to next path\n"); diff --git a/src/koopatlas/pathmanager.h b/src/koopatlas/pathmanager.h index 4604fc7..5579f66 100644 --- a/src/koopatlas/pathmanager.h +++ b/src/koopatlas/pathmanager.h @@ -62,6 +62,8 @@ class dWMPathManager_c { bool evaluateUnlockCondition(u8 *&in, SaveBlock *save, int stack); bool isEnteringLevel; + + bool calledEnteredNode; int levelStartWait; dLevelInfo_c::entry_s *enteredLevel; }; diff --git a/src/koopatlas/shop.cpp b/src/koopatlas/shop.cpp index 211ab49..cd20ddb 100644 --- a/src/koopatlas/shop.cpp +++ b/src/koopatlas/shop.cpp @@ -1,26 +1,6 @@ #include "koopatlas/shop.h" -int getStarCoinCountShop() { - SaveBlock *save = GetSaveFile()->GetBlock(-1); - int coinsSpent = save->credits_hiscore; - int coinsEarned = 0; - - for (int w = 0; w < 10; w++) { - for (int l = 0; l < 10; l++) { - u32 conds = save->GetLevelCondition(w, l); - - if (conds & COND_COIN1) { coinsEarned++; } - if (conds & COND_COIN2) { coinsEarned++; } - if (conds & COND_COIN3) { coinsEarned++; } - } - } - - int coinsLeft = coinsEarned - coinsSpent; - return coinsLeft; -} - - const char* Produce[10][4] = { { "I_kinoko", "g3d/I_kinoko.brres", "I_kinoko", "wait2" }, { "I_fireflower", "g3d/I_fireflower.brres", "I_fireflower", "wait2" }, @@ -381,7 +361,7 @@ void dWMShop_c::BuyItem(int item) { layout.enableNonLoopAnim(item-1); - int cash = getStarCoinCountShop(); + int cash = getStarCoinCount(); int cost; int Powerups[10]; diff --git a/src/koopatlas/starcoin.cpp b/src/koopatlas/starcoin.cpp index 54b7218..3842f87 100644 --- a/src/koopatlas/starcoin.cpp +++ b/src/koopatlas/starcoin.cpp @@ -1,26 +1,6 @@ #include "koopatlas/starcoin.h" #include <game.h> -int getStarCoinCountCoins() { - SaveBlock *save = GetSaveFile()->GetBlock(-1); - int coinsSpent = save->credits_hiscore; - int coinsEarned = 0; - - for (int w = 0; w < 10; w++) { - for (int l = 0; l < 10; l++) { - u32 conds = save->GetLevelCondition(w, l); - - if (conds & COND_COIN1) { coinsEarned++; } - if (conds & COND_COIN2) { coinsEarned++; } - if (conds & COND_COIN3) { coinsEarned++; } - } - } - - int coinsLeft = coinsEarned - coinsSpent; - return coinsLeft; -} - - /*****************************************************************************/ // Starcoin Layout // @@ -227,7 +207,7 @@ void dWMStarCoin::LoadCoinsForWorld(int world) { // Display Total Star Coin Count - int myCoins = getStarCoinCountCoins(); + int myCoins = getStarCoinCount(); char myCoinsStr [4]; sprintf(myCoinsStr, "%03d", myCoins); @@ -346,10 +326,10 @@ void dWMStarCoin::setText(const char *str, const char *name) { nw4r::ut::TextWriter tw; tw.font = box->font; tw.SetFontSize(box->fontSizeX, box->fontSizeY); - tw.somethingRelatedToLineHeight = box->lineSpace; + tw.lineSpace = box->lineSpace; tw.charSpace = box->charSpace; if (box->tagProc != 0) - tw.tagProcessorMaybe = box->tagProc; + tw.tagProcessor = box->tagProc; float width = tw.CalcStringWidth(newString, wlength); SpammyReport("Text width: %f\n", width); diff --git a/src/newer.cpp b/src/newer.cpp index 6d672e2..0b53fa6 100644 --- a/src/newer.cpp +++ b/src/newer.cpp @@ -1,77 +1,22 @@ #include <newer.h> +#include <game.h> -NWRWorld NewerWorldForLevelID(int w, int l) { - switch (w) { - case 1: return YOSHI_ISLAND; - case 2: - if (((l>1) && (l<5)) || (l==15) || (l==33) || (l==34)) - return SOGGY_SEWERS; - else - return RUBBLE_RUINS; - case 3: return MUSHROOM_PEAKS; - case 4: return SAKURA_VILLAGE; - case 5: - if (l<7 || l==15 || l==33 || l==34) - return FREEZEFLAME_GLACIER; - else - return FREEZEFLAME_VOLCANO; - case 6: return PUMPKIN_BONEYARD; - case 7: - if (l<4) - return SKY_MOUNTAIN; - else - return STARRY_SKIES; - case 8: - if (l<6 || l==15 || l==25 || l==33 || l==34) - return KOOPA_PLANET; - else - return KOOPA_CORE; - case 9: return BONUS_LAND; - case 10: - if (l<6 || l==30 || l==41) - return GOLDWOOD_FOREST; - else if (l<11 || l==32) - return MINIMEGA_ISLAND; - else if (l<16 || l==33 || l==34 || l==31) - return CRYSTAL_CAVES; - else if (l<19) - return BOMBARD_CLIFFS; - else - return SKY_CITY; - } - - return UNKNOWN_WORLD; -} +int getStarCoinCount() { + SaveBlock *save = GetSaveFile()->GetBlock(-1); + int coinsSpent = save->credits_hiscore; + int coinsEarned = 0; -const wchar_t *NewerWorldNames[] = { - L"Yoshi's Island", - L"Rubble Ruins", - L"Soggy Sewers", - L"Mushroom Peaks", - L"Sakura Village", - L"Freezeflame Glacier", - L"Freezeflame Volcano", - L"Pumpkin Boneyard", - L"Sky Mountain", - L"Starry Skies", - L"Koopa Planet", - L"Koopa Core", - L"Bonus Land", - L"Goldwood Forest", - L"Mini-Mega Island", - L"Crystal Caves", - L"Bombard Cliffs", - L"Sky City" -}; + for (int w = 0; w < 10; w++) { + for (int l = 0; l < 10; l++) { + u32 conds = save->GetLevelCondition(w, l); -// This is an array so it can be accessed from fileselect.S -int NewerWorldCount[] = { - 18 -}; + if (conds & COND_COIN1) { coinsEarned++; } + if (conds & COND_COIN2) { coinsEarned++; } + if (conds & COND_COIN3) { coinsEarned++; } + } + } -const wchar_t *NewerWorldName(NWRWorld world) { - if (world < 0 || world >= WORLD_COUNT) - return L"Unknown World"; - return NewerWorldNames[world]; + int coinsLeft = coinsEarned - coinsSpent; + return coinsLeft; } diff --git a/src/palaceDude.cpp b/src/palaceDude.cpp index 6a8d7ff..8eb4a99 100644 --- a/src/palaceDude.cpp +++ b/src/palaceDude.cpp @@ -29,7 +29,7 @@ int dPalaceDude_c::onExecute() { dMsgBoxManager_c::instance->showMessage(settings & 0xFFFFFFF); SaveBlock *save = GetSaveFile()->GetBlock(-1); - *((u8*)(((u32)GameMgr)+0x380)) |= (1 << (settings >> 28)); + GameMgrP->switchPalaceFlag|= (1 << (settings >> 28)); } } diff --git a/src/replay.S b/src/replay.S index 8c3f6c7..89868cf 100644 --- a/src/replay.S +++ b/src/replay.S @@ -27,7 +27,7 @@ .extern EGG__Heap__free__FPvPv .extern GameHeap2 .extern EggControllerClassPtrMaybe -.extern GameMgr +.extern GameMgrP .extern StrangeReplayValue1 .extern StrangeReplayValue2 .extern StrangeReplayValue3 @@ -192,8 +192,8 @@ replayStartLoop: lwzx r3, r3, r6 stw r3, 0x18(r4) - lis r3, GameMgr@h - ori r3, r3, GameMgr@l + lis r3, GameMgrP@h + ori r3, r3, GameMgrP@l lwz r3, 0(r3) lbz r3, 0x380(r3) stb r3, 0x21(r4) diff --git a/src/switchblock.S b/src/switchblock.S index b86d5e2..4df2433 100644 --- a/src/switchblock.S +++ b/src/switchblock.S @@ -11,14 +11,14 @@ #endif .align 4 -.extern GameMgr +.extern GameMgrP .extern BG_GM_ptr .extern _restgpr_27 .global BG_GM_InitRedSwitchFlag_Patch BG_GM_InitRedSwitchFlag_Patch: - lis r5, GameMgr@h - ori r5, r5, GameMgr@l + lis r5, GameMgrP@h + ori r5, r5, GameMgrP@l lwz r5, 0(r5) addis r4, r3, 9 |