summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--fileselect.yaml1
-rwxr-xr-xinclude/game.h275
-rw-r--r--include/newer.h27
-rw-r--r--kamek_pal.x17
-rw-r--r--src/fileselect.S88
-rw-r--r--src/koopatlas/hud.cpp630
-rw-r--r--src/koopatlas/hud.h69
-rw-r--r--src/koopatlas/mapdata.cpp16
-rw-r--r--src/koopatlas/mapdata.h17
-rw-r--r--src/koopatlas/pathmanager.cpp69
-rw-r--r--src/koopatlas/pathmanager.h2
-rw-r--r--src/koopatlas/shop.cpp22
-rw-r--r--src/koopatlas/starcoin.cpp26
-rw-r--r--src/newer.cpp85
-rw-r--r--src/palaceDude.cpp2
-rw-r--r--src/replay.S6
-rw-r--r--src/switchblock.S6
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