summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--koopatlas.yaml6
-rw-r--r--src/koopatlas/core.cpp81
-rw-r--r--src/koopatlas/core.h4
-rw-r--r--src/koopatlas/pathmanager.cpp255
-rw-r--r--src/koopatlas/pathmanager.h16
5 files changed, 359 insertions, 3 deletions
diff --git a/koopatlas.yaml b/koopatlas.yaml
index 5c9c081..377e9eb 100644
--- a/koopatlas.yaml
+++ b/koopatlas.yaml
@@ -98,3 +98,9 @@ hooks:
addr_pal: 0x800D52F0
data: '41820010'
+ - name: ResetAllCompletionCandidates
+ type: branch_insn
+ branch_type: b
+ src_addr_pal: 0x800B2FF0
+ target_func: 'ResetAllCompletionCandidates(void)'
+
diff --git a/src/koopatlas/core.cpp b/src/koopatlas/core.cpp
index 1772724..9666e53 100644
--- a/src/koopatlas/core.cpp
+++ b/src/koopatlas/core.cpp
@@ -10,6 +10,8 @@ dScKoopatlas_c *dScKoopatlas_c::instance = 0;
CREATE_STATE_E(dScKoopatlas_c, Limbo);
CREATE_STATE(dScKoopatlas_c, ContinueWait);
CREATE_STATE_E(dScKoopatlas_c, Normal);
+CREATE_STATE(dScKoopatlas_c, CompletionMsg);
+CREATE_STATE_E(dScKoopatlas_c, CompletionMsgHideWait);
CREATE_STATE_E(dScKoopatlas_c, CSMenu);
CREATE_STATE_E(dScKoopatlas_c, TitleConfirmOpenWait);
CREATE_STATE_E(dScKoopatlas_c, TitleConfirmSelect);
@@ -499,6 +501,12 @@ void dScKoopatlas_c::endState_ContinueWait() {
void dScKoopatlas_c::executeState_Normal() {
+ if (pathManager.completionMessagePending) {
+ OSReport("Going to set CompletionMsg\n");
+ state.setState(&StateID_CompletionMsg);
+ return;
+ }
+
if (pathManager.doingThings())
return;
@@ -1050,6 +1058,79 @@ void dScKoopatlas_c::showSaveWindow() {
}
+void dScKoopatlas_c::beginState_CompletionMsg() {
+ OSReport("CompletionMsg beginning with type %d\n", pathManager.completionMessageType);
+ static const int ynTypes[8] = {
+ /*NULL*/ -1,
+ /*COINS*/ 14,
+ /*EXITS*/ 7,
+ /*WORLD*/ 8,
+ /*COINS EXC W9*/ 9,
+ /*GLOBAL COINS*/ 11,
+ /*GLOBAL EXITS*/ 27,
+ /*EVERYTHING*/ 21
+ };
+ yesNoWindow->type = ynTypes[pathManager.completionMessageType];
+ yesNoWindow->visible = true;
+ mustFixYesNoText = 10; // hacky shit
+}
+
+void dScKoopatlas_c::endState_CompletionMsg() {
+ pathManager.completionMessagePending = false;
+ pathManager.completionMessageType = 0;
+}
+
+void dScKoopatlas_c::executeState_CompletionMsg() {
+ // hacky shit
+ if (mustFixYesNoText > 0) {
+ mustFixYesNoText--;
+
+ int type = pathManager.completionMessageType;
+
+ if (type >= CMP_MSG_COINS && type <= CMP_MSG_WORLD) {
+ // get the stuff we need: base BMG string
+ static const int bmgs[4] = {-1, 65, 58, 59};
+ const wchar_t *baseText = GetBMG()->findStringForMessageID(0, bmgs[type]);
+
+ // title
+ int w = pathManager.completionMessageWorldNum;
+ int l = ((w == 5) || (w == 7)) ? 101 : 100;
+ dLevelInfo_c::entry_s *titleEntry = dLevelInfo_c::s_info.searchByDisplayNum(w, l);
+ const char *title = dLevelInfo_c::s_info.getNameForLevel(titleEntry);
+
+ // assemble the string
+ wchar_t text[512];
+
+ wcscpy(text, baseText);
+ int pos = wcslen(text);
+
+ text[pos++] = ' ';
+
+ while (*title)
+ text[pos++] = *(title++);
+
+ text[pos++] = '!';
+ text[pos++] = 0;
+
+ yesNoWindow->T_question_00->SetString(text);
+ yesNoWindow->T_questionS_00->SetString(text);
+ }
+ }
+
+ if (!yesNoWindow->animationActive) {
+ if (Wiimote_TestButtons(GetActiveWiimote(), WPAD_A | WPAD_TWO)) {
+ yesNoWindow->close = true;
+ state.setState(&StateID_CompletionMsgHideWait);
+ }
+ }
+}
+
+void dScKoopatlas_c::executeState_CompletionMsgHideWait() {
+ if (!yesNoWindow->visible)
+ state.setState(&StateID_Normal);
+}
+
+
void NewerMapDrawFunc() {
Reset3DState();
SetCurrentCameraID(0);
diff --git a/src/koopatlas/core.h b/src/koopatlas/core.h
index 58030b7..f314b82 100644
--- a/src/koopatlas/core.h
+++ b/src/koopatlas/core.h
@@ -58,6 +58,8 @@ class dScKoopatlas_c : public dScene_c {
DECLARE_STATE(Limbo);
DECLARE_STATE(ContinueWait);
DECLARE_STATE(Normal);
+ DECLARE_STATE(CompletionMsg);
+ DECLARE_STATE(CompletionMsgHideWait);
DECLARE_STATE(CSMenu);
DECLARE_STATE(TitleConfirmOpenWait);
DECLARE_STATE(TitleConfirmSelect);
@@ -118,6 +120,8 @@ class dScKoopatlas_c : public dScene_c {
bool warpZoneHacks;
+ int mustFixYesNoText;
+
u32 iterateMapList(u32(*callback)(u32,const char *,int,int), u32 userData, int *ptrIndex = 0);
const char *getMapNameForIndex(int index);
int getIndexForMapName(const char *name);
diff --git a/src/koopatlas/pathmanager.cpp b/src/koopatlas/pathmanager.cpp
index cf3e0eb..8c31d96 100644
--- a/src/koopatlas/pathmanager.cpp
+++ b/src/koopatlas/pathmanager.cpp
@@ -8,6 +8,25 @@
extern "C" void PlaySoundWithFunctionB4(void *spc, nw4r::snd::SoundHandle *handle, int id, int unk);
u8 MaybeFinishingLevel[2] = {0xFF,0xFF};
+u8 LastLevelPlayed[2] = {0xFF,0xFF};
+bool CanFinishCoins = false;
+bool CanFinishExits = false;
+bool CanFinishWorld = false;
+bool CanFinishAlmostAllCoins = false;
+bool CanFinishAllCoins = false;
+bool CanFinishAllExits = false;
+bool CanFinishEverything = false;
+void ResetAllCompletionCandidates() {
+ MaybeFinishingLevel[0] = 0xFF;
+ LastLevelPlayed[0] = 0xFF;
+ CanFinishCoins = false;
+ CanFinishExits = false;
+ CanFinishWorld = false;
+ CanFinishAlmostAllCoins = false;
+ CanFinishAllCoins = false;
+ CanFinishAllExits = false;
+ CanFinishEverything = false;
+}
void dWMPathManager_c::setup() {
dScKoopatlas_c *wm = dScKoopatlas_c::instance;
@@ -147,13 +166,74 @@ void dWMPathManager_c::setup() {
// did we just beat a level?
if (MaybeFinishingLevel[0] != 0xFF) {
- SaveBlock *save = GetSaveFile()->GetBlock(-1);
if (save->CheckLevelCondition(MaybeFinishingLevel[0], MaybeFinishingLevel[1], COND_NORMAL)) {
shouldRequestSave = true;
}
+ }
- MaybeFinishingLevel[0] = 0xFF;
+ // have we got any completions?
+ u32 conds = save->GetLevelCondition(LastLevelPlayed[0], LastLevelPlayed[1]);
+ dLevelInfo_c::entry_s *whatEntry =
+ dLevelInfo_c::s_info.searchBySlot(LastLevelPlayed[0], LastLevelPlayed[1]);
+
+ // how many exits?
+ int exits = 0, maxExits = 0;
+ if (whatEntry->flags & 0x10) {
+ maxExits++;
+ if (conds & COND_NORMAL)
+ exits++;
+ }
+ if (whatEntry->flags & 0x20) {
+ maxExits++;
+ if (conds & COND_SECRET)
+ exits++;
+ }
+
+ completionMessageWorldNum = whatEntry->displayWorld;
+
+ // now do all the message checks
+ int flag = 0, totalFlag = 0;
+ if (CanFinishCoins) {
+ totalFlag |= 1;
+ if ((conds & COND_COIN_ALL) == COND_COIN_ALL) {
+ flag |= 1;
+ completionMessageType = CMP_MSG_COINS;
+ }
+ }
+ if (CanFinishExits) {
+ totalFlag |= 2;
+ if (exits == maxExits) {
+ flag |= 2;
+ completionMessageType = CMP_MSG_EXITS;
+ }
+ }
+ if (CanFinishWorld && flag == totalFlag)
+ completionMessageType = CMP_MSG_WORLD;
+
+ if (CanFinishAlmostAllCoins) {
+ if ((conds & COND_COIN_ALL) == COND_COIN_ALL)
+ completionMessageType = CMP_MSG_GLOBAL_COINS_EXC_W9;
+ }
+
+ int gFlag = 0, gTotalFlag = 0;
+ if (CanFinishAllCoins) {
+ gTotalFlag |= 1;
+ if ((conds & COND_COIN_ALL) == COND_COIN_ALL) {
+ gFlag |= 1;
+ completionMessageType = CMP_MSG_GLOBAL_COINS;
+ }
+ }
+ if (CanFinishAllExits) {
+ gTotalFlag |= 2;
+ if (exits == maxExits) {
+ gFlag |= 2;
+ completionMessageType = CMP_MSG_GLOBAL_EXITS;
+ }
}
+ if (CanFinishEverything && gFlag == gTotalFlag)
+ completionMessageType = CMP_MSG_EVERYTHING;
+
+ ResetAllCompletionCandidates();
if (wm->isAfterKamekCutscene)
copyWorldDefToSave(wm->mapData.findWorldDef(1));
@@ -180,6 +260,135 @@ dWMPathManager_c::~dWMPathManager_c() {
MaybeFinishingLevel[1] = enteredLevel->levelSlot;
}
}
+
+ // Now, a fuckton of checks for the various possible things we can finish!
+ dLevelInfo_c *li = &dLevelInfo_c::s_info;
+ u32 theseConds = save->GetLevelCondition(enteredLevel->worldSlot, enteredLevel->levelSlot);
+
+ int coinCount = 0, exitCount = 0;
+ int globalCoinCount = 0, globalCoinCountExcW9 = 0, globalExitCount = 0;
+
+ int totalCoinCount = 0, totalExitCount = 0;
+ int totalGlobalCoinCount = 0, totalGlobalCoinCountExcW9 = 0, totalGlobalExitCount = 0;
+
+ for (int sIdx = 0; sIdx < li->sectionCount(); sIdx++) {
+ dLevelInfo_c::section_s *sect = li->getSectionByIndex(sIdx);
+
+ for (int lIdx = 0; lIdx < sect->levelCount; lIdx++) {
+ dLevelInfo_c::entry_s *entry = &sect->levels[lIdx];
+ u32 entryConds = save->GetLevelCondition(entry->worldSlot, entry->levelSlot);
+
+ // Only track actual levels
+ if (!(entry->flags & 2))
+ continue;
+
+ // Counts for this world
+ if (entry->displayWorld == enteredLevel->displayWorld) {
+ totalCoinCount++;
+ if ((entryConds & COND_COIN_ALL) == COND_COIN_ALL)
+ coinCount++;
+
+ // Normal exit
+ if (entry->flags & 0x10) {
+ totalExitCount++;
+ if (entryConds & COND_NORMAL)
+ exitCount++;
+ }
+
+ // Secret exit
+ if (entry->flags & 0x20) {
+ totalExitCount++;
+ if (entryConds & COND_SECRET)
+ exitCount++;
+ }
+ }
+
+ // Counts for everywhere
+ totalGlobalCoinCount++;
+ if ((entryConds & COND_COIN_ALL) == COND_COIN_ALL)
+ globalCoinCount++;
+
+ if (entry->displayWorld != 9) {
+ totalGlobalCoinCountExcW9++;
+ if (entryConds & COND_COIN_ALL)
+ globalCoinCountExcW9++;
+ }
+
+ // Normal exit
+ if (entry->flags & 0x10) {
+ totalGlobalExitCount++;
+ if (entryConds & COND_NORMAL)
+ globalExitCount++;
+ }
+
+ // Secret exit
+ if (entry->flags & 0x20) {
+ totalGlobalExitCount++;
+ if (entryConds & COND_SECRET)
+ globalExitCount++;
+ }
+ }
+ }
+
+ // So.. are we candidates for any of these?
+ ResetAllCompletionCandidates();
+
+ LastLevelPlayed[0] = enteredLevel->worldSlot;
+ LastLevelPlayed[1] = enteredLevel->levelSlot;
+
+ int everythingFlag = 0, gEverythingFlag = 0;
+ if (coinCount == totalCoinCount)
+ everythingFlag |= 1;
+ if (exitCount == globalExitCount)
+ everythingFlag |= 2;
+ if (globalCoinCount == totalGlobalCoinCount)
+ gEverythingFlag |= 1;
+ if (globalExitCount == totalGlobalExitCount)
+ gEverythingFlag |= 2;
+
+ // Check if we could obtain every star coin
+ if ((theseConds & COND_COIN_ALL) != COND_COIN_ALL) {
+ if ((coinCount + 1) == totalCoinCount) {
+ CanFinishCoins = true;
+ everythingFlag |= 1;
+ }
+ if ((globalCoinCount + 1) == totalGlobalCoinCount) {
+ CanFinishAllCoins = true;
+ gEverythingFlag |= 1;
+ }
+ if ((globalCoinCountExcW9 + 1) == totalGlobalCoinCountExcW9)
+ CanFinishAlmostAllCoins = true;
+ }
+
+ // Check if we could obtain every exit
+ int elExits = 0, elTotalExits = 0;
+ if (enteredLevel->flags & 0x10) {
+ elTotalExits++;
+ if (theseConds & COND_NORMAL)
+ elExits++;
+ }
+ if (enteredLevel->flags & 0x20) {
+ elTotalExits++;
+ if (theseConds & COND_SECRET)
+ elExits++;
+ }
+
+ if ((elExits + 1) == elTotalExits) {
+ if ((exitCount + 1) == totalExitCount) {
+ CanFinishExits = true;
+ everythingFlag |= 2;
+ }
+ if ((globalExitCount + 1) == totalGlobalExitCount) {
+ CanFinishAllExits = true;
+ gEverythingFlag |= 2;
+ }
+ }
+
+ // And could we obtain EVERYTHING?
+ if ((CanFinishCoins || CanFinishExits) && everythingFlag == 3)
+ CanFinishWorld = true;
+ if ((CanFinishAllCoins || CanFinishAllExits) && gEverythingFlag == 3)
+ CanFinishEverything = true;
}
if (penguinSlideSound.Exists())
@@ -382,7 +591,7 @@ bool dWMPathManager_c::evaluateUnlockCondition(u8 *&in, SaveBlock *save, int sta
bool dWMPathManager_c::doingThings() {
- if (isEnteringLevel || (waitAfterUnlock > 0) ||
+ if (isEnteringLevel || (waitAfterUnlock > 0) || (completionAnimDelay > 0) ||
(waitAtStart > 0) || (waitForAfterDeathAnim > 0) ||
(countdownToFadeIn > 0) || (unlockingAlpha != -1))
return true;
@@ -461,6 +670,46 @@ void dWMPathManager_c::execute() {
return;
}
+ if (completionAnimDelay > 0) {
+ completionAnimDelay--;
+ if (dmGladDuration > 0) {
+ dmGladDuration--;
+ if (dmGladDuration == 0)
+ daWMPlayer_c::instance->startAnimation(wait_select, 1.0f, 0.0f, 0.0f);
+ }
+ if (completionAnimDelay == 0)
+ completionMessagePending = true;
+ return;
+ }
+
+ // just in case
+ if (completionMessagePending)
+ return;
+
+ if (completionMessageType > 0) {
+ OSReport("We have a completion message type: %d\n", completionMessageType);
+
+ int whichSound;
+ if (completionMessageType == CMP_MSG_GLOBAL_COINS) {
+ whichSound = STRM_BGM_STAR_COIN_CMPLT_ALL;
+ completionAnimDelay = 240;
+ } else if (completionMessageType == CMP_MSG_EVERYTHING) {
+ whichSound = STRM_BGM_ALL_CMPLT_5STARS;
+ completionAnimDelay = 216;
+ } else {
+ whichSound = STRM_BGM_STAR_COIN_CMPLT_WORLD;
+ completionAnimDelay = 138;
+ }
+
+ nw4r::snd::SoundHandle something;
+ PlaySoundWithFunctionB4(SoundRelatedClass, &something, whichSound, 1);
+
+ daWMPlayer_c::instance->startAnimation(coin_comp, 1.0f, 0.0f, 0.0f);
+ dmGladDuration = 154;
+
+ return;
+ }
+
if (waitAtStart > 0) {
waitAtStart--;
if (waitAtStart == 0) {
diff --git a/src/koopatlas/pathmanager.h b/src/koopatlas/pathmanager.h
index 156ed7b..522db7f 100644
--- a/src/koopatlas/pathmanager.h
+++ b/src/koopatlas/pathmanager.h
@@ -15,6 +15,17 @@ extern "C" void *SoundRelatedClass;
extern "C" void *MapSoundPlayer(void *SoundClass, int soundID, int unk);
extern "C" bool SpawnEffect(const char*, int, Vec*, S16Vec*, Vec*);
+enum CompletionMessageType {
+ CMP_MSG_NULL = 0,
+ CMP_MSG_COINS = 1,
+ CMP_MSG_EXITS = 2,
+ CMP_MSG_WORLD = 3,
+ CMP_MSG_GLOBAL_COINS_EXC_W9 = 4,
+ CMP_MSG_GLOBAL_COINS = 5,
+ CMP_MSG_GLOBAL_EXITS = 6,
+ CMP_MSG_EVERYTHING = 7
+};
+
class dWMPathManager_c {
public:
void setup();
@@ -76,6 +87,11 @@ class dWMPathManager_c {
public:
bool shouldRequestSave;
bool isEnteringLevel;
+ bool completionMessagePending;
+ int dmGladDuration;
+ int completionAnimDelay;
+ int completionMessageType;
+ int completionMessageWorldNum;
bool calledEnteredNode;
int levelStartWait;