diff options
-rw-r--r-- | bugfixes.yaml | 7 | ||||
-rw-r--r-- | fileselect.yaml | 1 | ||||
-rwxr-xr-x | include/game.h | 83 | ||||
-rw-r--r-- | include/newer.h | 26 | ||||
-rw-r--r-- | kamek_pal.x | 2 | ||||
-rw-r--r-- | src/fileselect.S | 88 | ||||
-rw-r--r-- | src/koopatlas/core.cpp | 11 | ||||
-rw-r--r-- | src/koopatlas/core.h | 2 | ||||
-rw-r--r-- | src/koopatlas/hud.cpp | 323 | ||||
-rw-r--r-- | src/koopatlas/hud.h | 33 | ||||
-rw-r--r-- | src/koopatlas/mapdata.cpp | 16 | ||||
-rw-r--r-- | src/koopatlas/mapdata.h | 20 | ||||
-rw-r--r-- | src/koopatlas/pathmanager.cpp | 59 | ||||
-rw-r--r-- | src/koopatlas/pathmanager.h | 1 | ||||
-rw-r--r-- | src/koopatlas/starcoin.cpp | 2 | ||||
-rw-r--r-- | src/levelinfo.cpp | 6 | ||||
-rw-r--r-- | src/levelinfo.h | 10 | ||||
-rw-r--r-- | src/levelinfo_old.cpp | 4 | ||||
-rw-r--r-- | src/levelinfo_old.h | 10 | ||||
-rw-r--r-- | src/levelnames.cpp | 2 | ||||
-rw-r--r-- | src/newer.cpp | 76 |
21 files changed, 591 insertions, 191 deletions
diff --git a/bugfixes.yaml b/bugfixes.yaml index 336a524..3af6148 100644 --- a/bugfixes.yaml +++ b/bugfixes.yaml @@ -153,3 +153,10 @@ hooks: type: add_func_pointer
src_addr_pal: 0x80B00234
target_func: 'ReturnNone'
+
+
+ - {name: AlwaysDrawPictureFontWhite1, type: patch, addr_pal: 0x800E596C, data: '3800FFFF'}
+ - {name: AlwaysDrawPictureFontWhite2, type: patch, addr_pal: 0x800E5974, data: '3800FFFF'}
+ - {name: AlwaysDrawPictureFontWhite3, type: patch, addr_pal: 0x800E597C, data: '3800FFFF'}
+ - {name: AlwaysDrawPictureFontWhite4, type: patch, addr_pal: 0x800E5984, data: '3800FFFF'}
+
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 e31e675..ef6aba4 100755 --- a/include/game.h +++ b/include/game.h @@ -24,8 +24,10 @@ inline T clamp(T value, T one, T two) { return (value < one) ? one : ((value > t extern "C" {
int wcslen(const wchar_t *str);
+wchar_t *wcscpy(wchar_t *dest, const wchar_t *src);
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);
@@ -138,6 +140,17 @@ inline void *GetGameMgr() { bool QueryPlayerAvailability(int id);
void DoStartLevel(void *gameMgr, StartLevelInfo *sl);
+
+
+// Level Conditions
+// 1 : Has Toad Block
+// 2 : Is Regular Level (has star coins, etc)
+// 0x10 : Has Normal Exit
+// 0x20 : Has Secret Exit
+// 0x40 : Warp Cannon
+// 0x80 : 1up/Green Mushroom House
+// 0x100 : Red Mushroom House
+// 0x200 : Star/Yellow Mushroom House
void SetSomeConditionShit(int world, int level, unsigned int bits);
bool IsWideScreen();
@@ -152,6 +165,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
@@ -200,7 +238,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
@@ -553,7 +597,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:
@@ -644,9 +694,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 {
@@ -3188,6 +3264,7 @@ namespace mHeap { };
void WriteNumberToTextBox(int *number, const int *fieldLength, nw4r::lyt::TextBox *textBox, bool unk); // 800B3B60
+void WriteNumberToTextBox(int *number, nw4r::lyt::TextBox *textBox, bool unk); // 800B3BE0
namespace EGG {
class MsgRes {
diff --git a/include/newer.h b/include/newer.h index d98f290..cf21cbb 100644 --- a/include/newer.h +++ b/include/newer.h @@ -1,32 +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 75613ad..78ff6bf 100644 --- a/kamek_pal.x +++ b/kamek_pal.x @@ -22,6 +22,7 @@ SECTIONS { InsertIntIntoTextBox1 = 0x800B3BE0; WriteNumberToTextBox__FPiPCiPQ34nw4r3lyt7TextBoxb = 0x800B3B60; + WriteNumberToTextBox__FPiPQ34nw4r3lyt7TextBoxb = 0x800B3BE0; __ct__20daJrClownForPlayer_cFv = 0x80810480; __dt__20daJrClownForPlayer_cFv = 0x80810540; /* Beans indeed. */ @@ -974,6 +975,7 @@ SECTIONS { strrchr = 0x802E1F30; wcslen = 0x802E470C; + wcscpy = 0x802E4728; IOS_Open = 0x80224DB0; IOS_Close = 0x80224FA0; 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/core.cpp b/src/koopatlas/core.cpp index c20d715..a48a565 100644 --- a/src/koopatlas/core.cpp +++ b/src/koopatlas/core.cpp @@ -970,13 +970,10 @@ void dScKoopatlas_c::startLevel(dLevelInfo_c::entry_s *entry) { sl.unk4 = 0; sl.purpose = 0; - sl.world1 = entry->world; - sl.world2 = entry->world; - sl.level1 = entry->level; - sl.level2 = entry->level; - - // hopefully this will fix the Star Coin issues - SetSomeConditionShit(entry->world, entry->level, 2); + sl.world1 = entry->worldSlot; + sl.world2 = entry->worldSlot; + sl.level1 = entry->levelSlot; + sl.level2 = entry->levelSlot; ActivateWipe(WIPE_MARIO); diff --git a/src/koopatlas/core.h b/src/koopatlas/core.h index 41fba45..cfac014 100644 --- a/src/koopatlas/core.h +++ b/src/koopatlas/core.h @@ -18,7 +18,7 @@ #include "koopatlas/pathmanager.h" #define WM_DEBUGGING -#define WM_SPAMMY_DEBUGGING +//#define WM_SPAMMY_DEBUGGING #ifdef WM_DEBUGGING #define MapReport OSReport diff --git a/src/koopatlas/hud.cpp b/src/koopatlas/hud.cpp index c9124d2..2401a04 100644 --- a/src/koopatlas/hud.cpp +++ b/src/koopatlas/hud.cpp @@ -1,5 +1,146 @@ #include "koopatlas/hud.h" + +dTexMapColouriser_c::dTexMapColouriser_c() { + texmap = 0; + original = 0; + mine = 0; +} + +void *EGG__Heap__alloc(unsigned long size, int unk, void *heap); +void EGG__Heap__free(void *ptr, void *heap); + +dTexMapColouriser_c::~dTexMapColouriser_c() { + resetAndClear(); +} + +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); + } + + 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; + } + } +} + + dWMHud_c *dWMHud_c::instance = 0; dWMHud_c *dWMHud_c::build() { @@ -15,6 +156,7 @@ dWMHud_c *dWMHud_c::build() { dWMHud_c::dWMHud_c() { layoutLoaded = false; displayedControllerType = -1; + isFooterVisible = false; } enum WMHudAnimation { @@ -50,7 +192,7 @@ int dWMHud_c::onCreate() { layout.disableAllAnimations(); layout.enableNonLoopAnim(SHOW_LIVES); - layout.enableNonLoopAnim(SHOW_FOOTER); + layout.resetAnim(SHOW_FOOTER); layout.resetAnim(SHOW_HEADER); static const char *tbNames[2] = {"MenuButtonInfo", "ItemsButtonInfo"}; @@ -63,13 +205,14 @@ int dWMHud_c::onCreate() { layout.getPanes(paneNames, &N_IconPosXP_00[0], 4); static const char *pictureNames[] = { - "Header_Centre", "Header_Right", + "Header_Centre", "Header_Right", "Footer", "NormalExitFlag", "SecretExitFlag", + "StarCoinOff0", "StarCoinOff1", "StarCoinOff2", "StarCoinOn0", "StarCoinOn1", "StarCoinOn2", "P_marioFace_00", "P_luigiFace_00", "P_BkinoFace_00", "P_YkinoFace_00" }; - layout.getPictures(pictureNames, &Header_Centre, 11); + layout.getPictures(pictureNames, &Header_Centre, 15); static const char *textBoxNames[] = { "LevelName", "LevelNameS", @@ -81,9 +224,20 @@ int dWMHud_c::onCreate() { }; 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(); + SaveBlock *save = GetSaveFile()->GetBlock(-1); + willShowFooter = (save->newerWorldName[0] != 0); if (!dScKoopatlas_c::instance->pathManager.isMoving) enteredNode(); @@ -96,6 +250,8 @@ int dWMHud_c::onCreate() { int dWMHud_c::onDelete() { + dWMHud_c::instance = 0; + if (!layoutLoaded) return true; @@ -110,11 +266,22 @@ int dWMHud_c::onExecute() { if (willShowHeader && (!(layout.isAnimOn(SHOW_HEADER)))) { willShowHeader = false; loadHeaderInfo(); - playShowHeaderAnim(); + playShowAnim(SHOW_HEADER); + } + + if (willShowFooter && (!(layout.isAnimOn(SHOW_FOOTER)))) { + willShowFooter = false; + isFooterVisible = true; + loadFooterInfo(); + playShowAnim(SHOW_FOOTER); } + setupLives(); // FUCK IT updatePressableButtonThingies(); + int scCount = getStarCoinCount(); + WriteNumberToTextBox(&scCount, StarCoinCounter, false); + layout.execAnimations(); layout.update(); @@ -134,26 +301,28 @@ int dWMHud_c::onDraw() { -void dWMHud_c::playShowHeaderAnim() { +void dWMHud_c::playShowAnim(int id) { if (!this || !this->layoutLoaded) return; - layout.enableNonLoopAnim(SHOW_HEADER); + layout.enableNonLoopAnim(id); } -void dWMHud_c::playHideHeaderAnim() { +void dWMHud_c::playHideAnim(int id) { if (!this || !this->layoutLoaded) return; - if (!layout.isAnimOn(SHOW_HEADER)) { - layout.enableNonLoopAnim(SHOW_HEADER, true); + if (!layout.isAnimOn(id)) { + layout.enableNonLoopAnim(id, true); } - layout.grpHandlers[SHOW_HEADER].frameCtrl.flags = 3; // NO_LOOP | REVERSE + layout.grpHandlers[id].frameCtrl.flags = 3; // NO_LOOP | REVERSE + if (id == SHOW_FOOTER) + isFooterVisible = false; } void dWMHud_c::loadHeaderInfo() { dLevelInfo_c *levelInfo = &dScKoopatlas_c::instance->levelInfo; - dLevelInfo_c::entry_s *infEntry = levelInfo->search( + dLevelInfo_c::entry_s *infEntry = levelInfo->searchBySlot( nodeForHeader->levelNumber[0]-1, nodeForHeader->levelNumber[1]-1); if (infEntry == 0) { @@ -177,32 +346,102 @@ void dWMHud_c::loadHeaderInfo() { LevelName->SetString(convertedLevelName); LevelNameS->SetString(convertedLevelName); + // a hack because I don't feel like editing the rlyt + LevelName->size.x = LevelNameS->size.x = 400.0f; + // LEVEL NUMBER - wchar_t levelNumber[6]; - levelNumber[0] = '0' + nodeForHeader->levelNumber[0]; + static const wchar_t *numberKinds[] = { + // 0-19 are handled by code + // To insert a picturefont character: + // \x0B\x01YY\xZZZZ + // YY is the character code, ZZZZ is ignored + L"A", // 20, alternate + L"\x0B\x012F\xBEEF", // 21, tower + L"\x0B\x012F\xBEEF" L"2", // 22, tower 2 + L"\x0B\x012E\xBEEF", // 23, castle + L"\x0B\x012F\xBEEF", // 24, fortress + L"\x0B\x013D\xBEEF", // 25, final castle + L"Train", // 26, train + L"\x0B\x0132\xBEEF", // 27, airship + L"Palace", // 28, switch palace + L"House", // 29, yoshi's house + L"Key1", // 30, key 1 + L"Key2", // 31, key 2 + L"Key3", // 32, key 3 + L"Key4", // 33, key 4 + L"Key5", // 34, key 5 + L"Key6", // 35, key 6 + }; + + int origWN = infEntry->displayWorld; + int origWL = infEntry->displayLevel; + + wchar_t levelNumber[16]; + levelNumber[0] = (origWN >= 10) ? (origWN-10+'A') : (origWN+'0'); levelNumber[1] = '-'; - if (nodeForHeader->levelNumber[1] >= 10) { - levelNumber[2] = '0' + (nodeForHeader->levelNumber[1] / 10); - levelNumber[3] = '0' + (nodeForHeader->levelNumber[1] % 10); + if (origWL > 20) { + wcscpy(&levelNumber[2], numberKinds[origWL-20]); + } else if (origWL >= 10) { + levelNumber[2] = '1'; + levelNumber[3] = ('0' - 10) + origWL; levelNumber[4] = 0; } else { - levelNumber[2] = '0' + nodeForHeader->levelNumber[1]; + levelNumber[2] = '0' + origWL; levelNumber[3] = 0; } LevelNumber->SetString(levelNumber); + + // make the picture shadowy + int sidx = 0; + while (levelNumber[sidx]) { + if (levelNumber[sidx] == 11) { + levelNumber[sidx+1] = 0x200 | (levelNumber[sidx+1]&0xFF); + sidx += 2; + } + sidx++; + } LevelNumberS->SetString(levelNumber); + nw4r::ut::TextWriter tw2; + tw2.font = LevelNumber->font; + tw2.SetFontSize(LevelNumber->fontSizeX, LevelNumber->fontSizeY); + tw2.lineSpace = LevelNumber->lineSpace; + tw2.charSpace = LevelNumber->charSpace; + if (LevelNumber->tagProc != 0) + tw2.tagProcessor = LevelNumber->tagProc; + + float currentPos = tw2.CalcStringWidth(levelNumber, wcslen(levelNumber)); + currentPos += LevelNumber->trans.x + 12.0f; + // INFO int w = nodeForHeader->levelNumber[0] - 1; int l = nodeForHeader->levelNumber[1] - 1; u32 conds = GetSaveFile()->GetBlock(-1)->GetLevelCondition(w, l); + + NormalExitFlag->trans.x = currentPos; NormalExitFlag->SetVisible(conds & COND_NORMAL); + if (conds & COND_NORMAL) + currentPos += NormalExitFlag->size.x; + + SecretExitFlag->trans.x = currentPos; SecretExitFlag->SetVisible(conds & COND_SECRET); - StarCoinOn[0]->SetVisible(conds & COND_COIN1); - StarCoinOn[1]->SetVisible(conds & COND_COIN2); - StarCoinOn[2]->SetVisible(conds & COND_COIN3); + if (conds & COND_SECRET) + currentPos += SecretExitFlag->size.x; + + // are star coins enabled or not? + bool haveSC = (infEntry->flags & 2); + + for (int i = 0; i < 3; i++) { + bool flag = (conds & (COND_COIN1 << i)); + StarCoinOn[i]->SetVisible(flag); + StarCoinOff[i]->SetVisible(haveSC); + if (haveSC) { + StarCoinOff[i]->trans.x = currentPos; + currentPos += StarCoinOff[i]->size.x + 4.0f; + } + } // SIZE THING nw4r::ut::TextWriter tw; @@ -215,10 +454,35 @@ void dWMHud_c::loadHeaderInfo() { float width = tw.CalcStringWidth(convertedLevelName, charCount); float totalWidth = width + LevelName->trans.x - 20.0f; - if (totalWidth < 270.0f) - totalWidth = 270.0f; + if (totalWidth < currentPos) + totalWidth = currentPos; Header_Centre->size.x = totalWidth; Header_Right->trans.x = totalWidth; + + SaveBlock *save = GetSaveFile()->GetBlock(-1); + headerCol.colourise(save->hudHintH, save->hudHintS, save->hudHintL); +} + + +void dWMHud_c::loadFooterInfo() { + SaveBlock *save = GetSaveFile()->GetBlock(-1); + + wchar_t convertedWorldName[36]; + int i; + for (i = 0; i < 36; i++) { + convertedWorldName[i] = save->newerWorldName[i]; + if (convertedWorldName[i] == 0) + break; + } + convertedWorldName[35] = 0; + + WorldName->SetString(convertedWorldName); + WorldNameS->SetString(convertedWorldName); + + WorldName->colour1 = save->hudTextColours[0]; + WorldName->colour2 = save->hudTextColours[1]; + + footerCol.colourise(save->hudHintH, save->hudHintS, save->hudHintL); } @@ -237,15 +501,26 @@ void dWMHud_c::leftNode() { if (layout.grpHandlers[SHOW_HEADER].frameCtrl.currentFrame > 0.1f) { // not hidden - if ((layout.isAnimOn(SHOW_HEADER) && (layout.grpHandlers[SHOW_HEADER].frameCtrl.flags & 2)) + if ((layout.isAnimOn(SHOW_HEADER) && !(layout.grpHandlers[SHOW_HEADER].frameCtrl.flags & 2)) || (!layout.isAnimOn(SHOW_HEADER))) { // currently being shown, OR fully shown already - playHideHeaderAnim(); + playHideAnim(SHOW_HEADER); } } } +void dWMHud_c::hideFooter() { + if (isFooterVisible) + playHideAnim(SHOW_FOOTER); +} + +void dWMHud_c::showFooter() { + willShowFooter = true; + if (isFooterVisible) + playHideAnim(SHOW_FOOTER); +} + void dWMHud_c::setupLives() { static const int LogicalPlayerIDs[] = {0,1,3,2}; diff --git a/src/koopatlas/hud.h b/src/koopatlas/hud.h index e507aea..5996b88 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(); @@ -21,11 +38,14 @@ class dWMHud_c : public dBase_c { void enteredNode(dKPNode_s *node = 0); void leftNode(); + void hideFooter(); + void showFooter(); + void setupLives(); private: - void playShowHeaderAnim(); - void playHideHeaderAnim(); + void playShowAnim(int id); + void playHideAnim(int id); void loadHeaderInfo(); bool willShowHeader; @@ -34,13 +54,20 @@ class dWMHud_c : public dBase_c { int displayedControllerType; void updatePressableButtonThingies(); + void loadFooterInfo(); + bool willShowFooter; + bool isFooterVisible; + + dTexMapColouriser_c headerCol, footerCol; + nw4r::lyt::Pane *N_IconPosXP_00[4]; nw4r::lyt::Picture - *Header_Centre, *Header_Right, + *Header_Centre, *Header_Right, *Footer, *NormalExitFlag, *SecretExitFlag, + *StarCoinOff[3], *StarCoinOn[3], *P_marioFace_00, *P_luigiFace_00, *P_BkinoFace_00, *P_YkinoFace_00; 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..a0beb4d 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,18 @@ struct dKPLayer_s { int findNodeID(dKPNode_s *node); }; +struct dKPWorldDef_s { + const char *name; + GXColor fsTextColours[2]; + GXColor fsHintColours[2]; + GXColor hudTextColours[2]; + u8 hudHintH; + s8 hudHintS, hudHintL; + u8 key, trackID; + u8 worldID; + u8 padding1, padding2; +}; + struct dKPMapFile_s { u32 magic; int version; @@ -202,6 +215,9 @@ struct dKPMapFile_s { dKPLayer_s::sector_s *sectors; const char *backgroundName; + + dKPWorldDef_s *worlds; + int worldCount; }; class dKPMapData_c { @@ -253,6 +269,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 536b43a..c691a89 100644 --- a/src/koopatlas/pathmanager.cpp +++ b/src/koopatlas/pathmanager.cpp @@ -374,7 +374,7 @@ 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); if (!path->isAvailable) { return; } - if (currentNode) + if (currentNode && dWMHud_c::instance) dWMHud_c::instance->leftNode(); calledEnteredNode = false; @@ -557,7 +557,7 @@ void dWMPathManager_c::moveThroughPath() { 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) { + if (distToEnd < 64.0f && dWMHud_c::instance) { calledEnteredNode = true; dWMHud_c::instance->enteredNode(to); } @@ -578,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 @@ -602,6 +602,44 @@ 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->showFooter(); + } + } else if (to->worldID == 0) { + OSReport("No world\n"); + save->newerWorldName[0] = 0; + if (dWMHud_c::instance) + dWMHud_c::instance->hideFooter(); + } else { + OSReport("Not found!\n"); + } + } + if (to->type == dKPNode_s::CHANGE) { // Go to another map @@ -635,15 +673,8 @@ void dWMPathManager_c::moveThroughPath() { SaveBlock *save = GetSaveFile()->GetBlock(-1); save->current_path_node = pathLayer->findNodeID(to); - if (!calledEnteredNode) + if (!calledEnteredNode && dWMHud_c::instance) dWMHud_c::instance->enteredNode(); - - if (to->type == dKPNode_s::LEVEL) { - NWRWorld nWorld = NewerWorldForLevelID(to->levelNumber[0], to->levelNumber[1]); - if (nWorld != UNKNOWN_WORLD) { - save->currentNewerWorld = (u8)nWorld; - } - } } else { startMovementTo(to->getOppositeAvailableExitTo(currentPath)); SpammyReport("passthrough node, continuing to next path\n"); @@ -684,7 +715,7 @@ void dWMPathManager_c::activatePoint() { isEnteringLevel = true; levelStartWait = 40; - enteredLevel = dScKoopatlas_c::instance->levelInfo.search(w, l); + enteredLevel = dScKoopatlas_c::instance->levelInfo.searchBySlot(w, l); } } diff --git a/src/koopatlas/pathmanager.h b/src/koopatlas/pathmanager.h index 5579f66..a1d916d 100644 --- a/src/koopatlas/pathmanager.h +++ b/src/koopatlas/pathmanager.h @@ -9,6 +9,7 @@ #endif #include "koopatlas/mapdata.h" +#include "levelinfo.h" extern "C" void *SoundRelatedClass; extern "C" void *MapSoundPlayer(void *SoundClass, int soundID, int unk); diff --git a/src/koopatlas/starcoin.cpp b/src/koopatlas/starcoin.cpp index 3842f87..4366895 100644 --- a/src/koopatlas/starcoin.cpp +++ b/src/koopatlas/starcoin.cpp @@ -238,7 +238,7 @@ void dWMStarCoin::LoadCoinsForWorld(int world) { if (levelArray[world][l][i]) { levelNum--; dLevelInfo_c *li = &dScKoopatlas_c::instance->levelInfo; - dLevelInfo_c::entry_s *entry = li->search(world, levelNum); + dLevelInfo_c::entry_s *entry = li->searchBySlot(world, levelNum); setText(li->getNameForLevel(entry), levelPane); totalCoins += 3; diff --git a/src/levelinfo.cpp b/src/levelinfo.cpp index 3a0ef6f..8ce2845 100644 --- a/src/levelinfo.cpp +++ b/src/levelinfo.cpp @@ -12,6 +12,8 @@ void dLevelInfo_c::load(void *buffer) { for (int lev = 0; lev < thisSect->levelCount; lev++) {
entry_s *level = &levels[lev];
+ SetSomeConditionShit(level->worldSlot, level->levelSlot, level->flags);
+
char *name = (char*)getNameForLevel(level);
for (int i = 0; i < level->nameLength+1; i++) {
@@ -21,13 +23,13 @@ void dLevelInfo_c::load(void *buffer) { }
}
-dLevelInfo_c::entry_s *dLevelInfo_c::search(int world, int level) {
+dLevelInfo_c::entry_s *dLevelInfo_c::searchBySlot(int world, int level) {
for (int i = 0; i < sectionCount(); i++) {
section_s *sect = getSectionByIndex(i);
for (int j = 0; j < sect->levelCount; j++) {
entry_s *entry = &getLevelsForSection(sect)[j];
- if (entry->world == world && entry->level == level)
+ if (entry->worldSlot == world && entry->levelSlot == level)
return entry;
}
}
diff --git a/src/levelinfo.h b/src/levelinfo.h index 470992b..20628d9 100644 --- a/src/levelinfo.h +++ b/src/levelinfo.h @@ -16,10 +16,10 @@ public: };
struct entry_s {
- u8 world;
- u8 level;
- u8 reserved1;
- u8 reserved2;
+ u8 worldSlot;
+ u8 levelSlot;
+ u8 displayWorld;
+ u8 displayLevel;
u8 nameLength;
u8 reserved3;
u16 flags;
@@ -32,7 +32,7 @@ private: public:
void load(void *buffer);
- entry_s *search(int world, int level);
+ entry_s *searchBySlot(int world, int level);
u32 sectionCount() {
return data->sectionCount;
diff --git a/src/levelinfo_old.cpp b/src/levelinfo_old.cpp index 01dda85..bd5a2eb 100644 --- a/src/levelinfo_old.cpp +++ b/src/levelinfo_old.cpp @@ -21,13 +21,13 @@ void LevelInfo_Prepare(FileHandle *fh) { } } -LevelInfo_Entry *LevelInfo_Search(void *file, int world, int level) { +LevelInfo_Entry *LevelInfo_SearchSlot(void *file, int world, int level) { for (int i = 0; i < LevelInfo_GetSectionCount(file); i++) { LevelInfo_Section *sect = LevelInfo_GetSection(file, i); for (int j = 0; j < sect->levelCount; j++) { LevelInfo_Entry *entry = &LevelInfo_GetLevels(file, sect)[j]; - if (entry->world == world && entry->level == level) + if (entry->worldSlot == world && entry->levelSlot == level) return entry; } } diff --git a/src/levelinfo_old.h b/src/levelinfo_old.h index d8cb888..ed43757 100644 --- a/src/levelinfo_old.h +++ b/src/levelinfo_old.h @@ -14,10 +14,10 @@ struct LevelInfo_Section { }; struct LevelInfo_Entry { - u8 world; - u8 level; - u8 reserved1; - u8 reserved2; + u8 worldSlot; + u8 levelSlot; + u8 displayWorld; + u8 displayLevel; u8 nameLength; u8 reserved3; u16 flags; @@ -50,7 +50,7 @@ inline char *LevelInfo_GetName(void *file, LevelInfo_Entry *entry) { } void LevelInfo_Prepare(FileHandle *fh); -LevelInfo_Entry *LevelInfo_Search(void *file, int world, int level); +LevelInfo_Entry *LevelInfo_SearchSlot(void *file, int world, int level); #endif diff --git a/src/levelnames.cpp b/src/levelnames.cpp index 1f05386..7c64c0b 100644 --- a/src/levelnames.cpp +++ b/src/levelnames.cpp @@ -38,7 +38,7 @@ int DoNames(int state) { void *info = LoadFile(&fh, "/NewerRes/LevelInfo.bin"); LevelInfo_Prepare(&fh); - LevelInfo_Entry *entry = LevelInfo_Search(info, wnum, lnum); + LevelInfo_Entry *entry = LevelInfo_SearchSlot(info, wnum, lnum); char *worldname = LevelInfo_GetName(info, entry); char *levelname = ""; diff --git a/src/newer.cpp b/src/newer.cpp index 2bad8a0..0b53fa6 100644 --- a/src/newer.cpp +++ b/src/newer.cpp @@ -1,82 +1,6 @@ #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; -} - - -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" -}; - -// This is an array so it can be accessed from fileselect.S -int NewerWorldCount[] = { - 18 -}; - -const wchar_t *NewerWorldName(NWRWorld world) { - if (world < 0 || world >= WORLD_COUNT) - return L"Unknown World"; - return NewerWorldNames[world]; -} - int getStarCoinCount() { SaveBlock *save = GetSaveFile()->GetBlock(-1); |