diff options
author | Treeki <treeki@gmail.com> | 2012-07-25 19:01:07 +0200 |
---|---|---|
committer | Treeki <treeki@gmail.com> | 2012-07-25 19:01:07 +0200 |
commit | c01d2d5df5c0bca7b8714f54e8efbd3456b1182e (patch) | |
tree | 32e300afd926ba181a8a0b1c5a2199d075e0e258 /src/koopatlas/pathmanager.cpp | |
parent | aea689a23e1390d62896ba96667631add5c33018 (diff) | |
parent | 6895c831ad320c14b01ccabe1c8adcec354e3f9f (diff) | |
download | kamek-c01d2d5df5c0bca7b8714f54e8efbd3456b1182e.tar.gz kamek-c01d2d5df5c0bca7b8714f54e8efbd3456b1182e.zip |
Merge branch 'freeform-unlocks' into level-select
Diffstat (limited to 'src/koopatlas/pathmanager.cpp')
-rw-r--r-- | src/koopatlas/pathmanager.cpp | 198 |
1 files changed, 195 insertions, 3 deletions
diff --git a/src/koopatlas/pathmanager.cpp b/src/koopatlas/pathmanager.cpp index b2d649d..de2a584 100644 --- a/src/koopatlas/pathmanager.cpp +++ b/src/koopatlas/pathmanager.cpp @@ -61,11 +61,161 @@ void dWMPathManager_c::setup() { } } - // unlock all needed paths SpammyReport("Unlocking paths\n"); + isEnteringLevel = false; + unlockPaths(); SpammyReport("done\n"); } +static u8 *PathAvailabilityData = 0; +static u8 *NodeAvailabilityData = 0; + +dWMPathManager_c::~dWMPathManager_c() { + if (PathAvailabilityData && !isEnteringLevel) { + delete[] PathAvailabilityData; + PathAvailabilityData = 0; + + delete[] NodeAvailabilityData; + NodeAvailabilityData = 0; + } +} + +void dWMPathManager_c::unlockPaths() { + u8 *oldPathAvData = PathAvailabilityData; + PathAvailabilityData = new u8[pathLayer->pathCount]; + + u8 *oldNodeAvData = NodeAvailabilityData; + NodeAvailabilityData = new u8[pathLayer->nodeCount]; + + OSReport("Unlocking paths\n"); + + // unlock all needed paths + for (int i = 0; i < pathLayer->pathCount; i++) { + dKPPath_s *path = pathLayer->paths[i]; + + PathAvailabilityData[i] = path->isAvailable; + + //OSReport("Path %d: %d\n", i, path->isAvailable); + // if this path is not "always available", then nuke its alpha + path->setLayerAlpha((path->isAvailable == dKPPath_s::ALWAYS_AVAILABLE) ? 255 : 0); + } + + for (int i = 0; i < pathLayer->nodeCount; i++) + NodeAvailabilityData[i] = pathLayer->nodes[i]->isUnlocked(); + + SaveBlock *save = GetSaveFile()->GetBlock(-1); + + u8 *in = (u8*)dScKoopatlas_c::instance->mapData.data->unlockData; + + while (*in != 0) { + // begin processing a block + bool value = evaluateUnlockCondition(in, save); + //OSReport("Unlock condition: %d\n", value); + + // get what it's supposed to affect + // for now we'll assume that it affects one or more paths + u8 affectedCount = *(in++); + + for (int i = 0; i < affectedCount; i++) { + u8 one = *(in++); + u8 two = *(in++); + u16 pathID = (one << 8) | two; + + dKPPath_s *path = pathLayer->paths[pathID]; + path->isAvailable = value ? dKPPath_s::AVAILABLE : dKPPath_s::NOT_AVAILABLE; + PathAvailabilityData[pathID] = value ? dKPPath_s::AVAILABLE : dKPPath_s::NOT_AVAILABLE; + //OSReport("Applied to path %p[%d]\n", path, pathID); + // NEWLY_AVAILABLE is set later, when that stuff is figured out + + path->setLayerAlpha(value ? 255 : 0); + } + } + + // did anything become newly available?! + newlyAvailablePaths = 0; + newlyAvailableNodes = 0; + + if (oldPathAvData) { + for (int i = 0; i < pathLayer->pathCount; i++) { + if ((PathAvailabilityData[i] > 0) && (oldPathAvData[i] == 0)) { + dKPPath_s *path = pathLayer->paths[i]; + path->isAvailable = dKPPath_s::NEWLY_AVAILABLE; + newlyAvailablePaths++; + + // set this path's alpha to 0, we'll fade it in later + path->setLayerAlpha(0); + } + } + delete[] oldPathAvData; + + // check nodes too + for (int i = 0; i < pathLayer->nodeCount; i++) { + if ((NodeAvailabilityData[i] > 0) && (oldNodeAvData[i] == 0)) { + dKPNode_s *node = pathLayer->nodes[i]; + node->isNew = true; + newlyAvailableNodes++; + } + } + delete[] oldNodeAvData; + } + + // now set all node alphas + for (int i = 0; i < pathLayer->nodeCount; i++) { + dKPNode_s *node = pathLayer->nodes[i]; + + node->setLayerAlpha((node->isUnlocked() & !node->isNew) ? 255 : 0); + } + + // if anything was new, set it as such + if (newlyAvailablePaths || newlyAvailableNodes) { + countdownToFadeIn = 30; + } + unlockingAlpha = -1; +} + +bool dWMPathManager_c::evaluateUnlockCondition(u8 *&in, SaveBlock *save) { + u8 controlByte = *(in++); + + u8 conditionType = (controlByte >> 6); + + if (conditionType == 0) + return true; + + if (conditionType == 1) { + // Simple level + + bool isSecret = (controlByte & 0x10); + u8 worldNumber = controlByte & 0xF; + u8 levelNumber = *(in++); + + u32 conds = save->GetLevelCondition(worldNumber, levelNumber); + + if (isSecret) + return (conds & COND_SECRET) != 0; + else + return (conds & COND_NORMAL) != 0; + } + + // Type: 2 = AND, 3 = OR + bool isAnd = (conditionType == 2); + bool isOr = (conditionType == 3); + + bool value = isOr ? false : true; + + u8 termCount = (controlByte & 0x3F) + 1; + + for (int i = 0; i < termCount; i++) { + bool what = evaluateUnlockCondition(in, save); + + if (isOr) + value |= what; + else + value &= what; + } + + return value; +} + void dWMPathManager_c::execute() { int nowPressed = Remocon_GetPressed(GetActiveRemocon()); @@ -84,6 +234,36 @@ void dWMPathManager_c::execute() { else if (nowPressed & WPAD_TWO) activatePoint(); } + + // handle path fading + if (countdownToFadeIn > 0) { + countdownToFadeIn--; + if (countdownToFadeIn <= 0) + unlockingAlpha = 0; + } + + if (unlockingAlpha != -1) { + unlockingAlpha += 3; + + for (int i = 0; i < pathLayer->pathCount; i++) { + dKPPath_s *path = pathLayer->paths[i]; + + if (path->isAvailable == dKPPath_s::NEWLY_AVAILABLE) + path->setLayerAlpha(unlockingAlpha); + } + + for (int i = 0; i < pathLayer->nodeCount; i++) { + dKPNode_s *node = pathLayer->nodes[i]; + + if (node->isNew) + node->setLayerAlpha(unlockingAlpha); + } + + if (unlockingAlpha == 255) { + // we've reached the end + unlockingAlpha = -1; + } + } } @@ -302,6 +482,16 @@ void dWMPathManager_c::moveThroughPath() { SpammyReport("reached path end (%p)\n", to); + // Quick check: do we *actually* need to stop on this node? + // If it's a junction with more than two exits, but only two are open, + // take the opposite open one + bool stopOverride = false; + + if (to->type == dKPNode_s::STOP) { + if (to->getExitCount() > 2 && to->getAvailableExitCount() == 2) + stopOverride = true; + } + if (to->type == dKPNode_s::CHANGE) { // Go to another map isMoving = false; @@ -313,7 +503,7 @@ void dWMPathManager_c::moveThroughPath() { DoSceneChange(WORLD_MAP, 0x10000000 | to->foreignID, 0); - } else if (to->type != dKPNode_s::PASS_THROUGH) { + } else if (to->type != dKPNode_s::PASS_THROUGH && !stopOverride) { // Stop here player->startAnimation(0, 1.2, 10.0, 0.0); player->hasEffect = false; @@ -329,7 +519,7 @@ void dWMPathManager_c::moveThroughPath() { dWMHud_c::instance->showPointBar(); SpammyReport("Point bar shown\n"); } else { - startMovementTo(to->getOppositeExitTo(currentPath)); + startMovementTo(to->getOppositeAvailableExitTo(currentPath)); SpammyReport("passthrough node, continuing to next path\n"); } } @@ -360,6 +550,8 @@ void dWMPathManager_c::activatePoint() { MapSoundPlayer(SoundRelatedClass, SE_SYS_GAME_START, 1); daWMPlayer_c::instance->startAnimation(170, 1.2, 10.0, 0.0); + isEnteringLevel = true; + dLevelInfo_c::entry_s *level = dScKoopatlas_c::instance->levelInfo.search(w, l); dScKoopatlas_c::instance->startLevel(level); } |