summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/koopatlas/camera.cpp116
-rw-r--r--src/koopatlas/camera.h11
-rw-r--r--src/koopatlas/hud.cpp19
-rw-r--r--src/koopatlas/hud.h3
-rw-r--r--src/koopatlas/pathmanager.cpp202
-rw-r--r--src/koopatlas/pathmanager.h17
6 files changed, 324 insertions, 44 deletions
diff --git a/src/koopatlas/camera.cpp b/src/koopatlas/camera.cpp
index d98bff0..f80ebcc 100644
--- a/src/koopatlas/camera.cpp
+++ b/src/koopatlas/camera.cpp
@@ -31,7 +31,9 @@ dWorldCamera_c::dWorldCamera_c() {
currentX = 416;
currentY = -224;
- zoomLevel = 2.8f;
+ zoomLevel = STD_ZOOM;
+
+ followPlayer = true;
}
@@ -70,7 +72,31 @@ int dWorldCamera_c::onExecute() {
currentX = 2040.0f;
currentY = -1460.0f;
zoomLevel = 3.4f;
- } else {
+
+ } else if (panning) {
+ // Calculate where we are
+#define SMOOTHSTEP(x) ((x) * (x) * (3 - 2 * (x)))
+ float stepRatio = panCurrentStep / panTotalSteps;
+ stepRatio = 1.0f - SMOOTHSTEP(stepRatio);
+ //OSReport("PAN: Step %f / %f ---- Ratio: %f", panCurrentStep, panTotalSteps, stepRatio);
+ //OSReport("From %f, %f to %f, %f --- Zoom: %f to %f\n", panFromX, panFromY, panToX, panToY, panFromZoom, panToZoom);
+
+ currentX = (panFromX * stepRatio) + (panToX * (1.0f - stepRatio));
+ currentY = (panFromY * stepRatio) + (panToY * (1.0f - stepRatio));
+ zoomLevel = (panFromZoom * stepRatio) + (panToZoom * (1.0f - stepRatio));
+ //OSReport("Calculated: %f, %f with zoom %f\n", currentX, currentY, zoomLevel);
+
+ panCurrentStep += 1.0f;
+
+ if (panCurrentStep > panTotalSteps) {
+ // YAY, we reached the end
+ panning = false;
+ currentX = panToX;
+ currentY = panToY;
+ zoomLevel = panToZoom;
+ }
+
+ } else if (followPlayer) {
daWMPlayer_c *player = daWMPlayer_c::instance;
currentX = player->pos.x;
currentY = player->pos.y;
@@ -83,6 +109,92 @@ int dWorldCamera_c::onExecute() {
return true;
}
+void dWorldCamera_c::panToBounds(float left, float top, float right, float bottom) {
+ // Pad it a bit
+ left -= 64.0f;
+ right += 64.0f;
+ top -= 48.0f;
+ bottom += 48.0f;
+
+ //OSReport("Panning camera to bounds %f,%f to %f,%f\n", left, top, right, bottom);
+
+ // Figure out the centre x/y we want
+ float width = right - left;
+ float height = bottom - top;
+
+ float desiredCentreX = left + (width * 0.5f);
+ float desiredCentreY = -(top + (height * 0.5f));
+
+ //OSReport("Size: %f x %f ; Desired Centre: %f, %f\n", width, height, desiredCentreX, desiredCentreY);
+
+ // Our default zoom is 2.8
+ float minScreenWidth = GlobalScreenWidth * 1.2f;
+ float minScreenHeight = GlobalScreenHeight * 1.2f;
+ float maxScreenWidth = GlobalScreenWidth * 4.0f;
+ float maxScreenHeight = GlobalScreenHeight * 4.0f;
+
+ //OSReport("Screen Sizes: Minimum possible %f x %f ; Maximum possible %f x %f\n", minScreenWidth, minScreenHeight, maxScreenWidth, maxScreenHeight);
+
+ // First off, gotta cap it to the ratio
+ float screenRatio = GlobalScreenWidth / GlobalScreenHeight;
+ float boundsRatio = width / height;
+ float correctedWidth = width, correctedHeight = height;
+ float desiredZoomLevel;
+ //OSReport("Actual screen size is %f x %f --- Screen Ratio: %f, Bounds Ratio: %f\n", GlobalScreenWidth, GlobalScreenHeight, screenRatio, boundsRatio);
+
+ float widthScale = width / GlobalScreenWidth;
+ float heightScale = height / GlobalScreenHeight;
+
+ if (heightScale > widthScale) {
+ // Thing is constrained on the top/bottom
+ desiredZoomLevel = heightScale;
+ } else {
+ // Thing is constrained on the left/right
+ desiredZoomLevel = widthScale;
+ }
+
+ //OSReport("Desired zoom level is %f\n", desiredZoomLevel);
+
+ // Cap the zoom
+ if (desiredZoomLevel < 2.0f)
+ desiredZoomLevel = 2.0f;
+ if (desiredZoomLevel > 4.5f)
+ desiredZoomLevel = 4.5f;
+ //OSReport("After capping: %f\n", desiredZoomLevel);
+
+ // And we're almost there YAY
+ panToPosition(desiredCentreX, desiredCentreY, desiredZoomLevel);
+}
+
+
+void dWorldCamera_c::panToPosition(float x, float y, float zoom) {
+ panFromX = currentX;
+ panFromY = currentY;
+ panFromZoom = zoomLevel;
+
+ panToX = x;
+ panToY = y;
+ panToZoom = zoom;
+
+ float xDiff = abs(panToX - panFromX);
+ float yDiff = abs(panToY - panFromY);
+
+ float panLength = sqrtf((xDiff*xDiff) + (yDiff*yDiff));
+ float panSteps = panLength / 2.3f;
+ float scaleSteps = abs(panToZoom - panFromZoom) / 0.1f;
+ float stepCount = max(panSteps, scaleSteps);
+
+ //OSReport("Pan length: %f over %f steps\n", panLength, panSteps);
+ //OSReport("Scale steps: %f\n", scaleSteps);
+ //OSReport("Step Count: %f\n", stepCount);
+
+ panCurrentStep = 0.0f;
+ panTotalSteps = stepCount;
+
+ panning = true;
+ followPlayer = false;
+}
+
int dWorldCamera_c::onDraw() {
GXRenderModeObj *rmode = nw4r::g3d::G3DState::GetRenderModeObj();
diff --git a/src/koopatlas/camera.h b/src/koopatlas/camera.h
index 39e34d0..836c819 100644
--- a/src/koopatlas/camera.h
+++ b/src/koopatlas/camera.h
@@ -3,6 +3,8 @@
#include "koopatlas/core.h"
+#define STD_ZOOM 2.8f
+
class dWorldCamera_c : public dBase_c {
public:
int onCreate();
@@ -20,7 +22,6 @@ class dWorldCamera_c : public dBase_c {
Vec camPos, camTarget, camUp;
-
float currentX, currentY, zoomLevel;
void calculateScreenGeometry();
@@ -28,6 +29,14 @@ class dWorldCamera_c : public dBase_c {
float zoomDivisor, screenLeft, screenTop, screenWidth, screenHeight;
+ bool followPlayer;
+ void panToBounds(float left, float top, float right, float bottom);
+ void panToPosition(float x, float y, float zoom=STD_ZOOM);
+ bool panning;
+ float panFromX, panFromY, panToX, panToY;
+ float panFromZoom, panToZoom;
+ float panCurrentStep;
+ float panTotalSteps;
void doStuff(float);
void generateCameraMatrices();
diff --git a/src/koopatlas/hud.cpp b/src/koopatlas/hud.cpp
index ce54d8f..22928a5 100644
--- a/src/koopatlas/hud.cpp
+++ b/src/koopatlas/hud.cpp
@@ -110,11 +110,6 @@ int dWMHud_c::onCreate() {
willShowFooter = false;
loadFooterInfo();
- SaveBlock *save = GetSaveFile()->GetBlock(-1);
- willShowFooter = (save->newerWorldName[0] != 0) && (save->hudHintH != 2000);
-
- if (!dScKoopatlas_c::instance->pathManager.isMoving)
- enteredNode();
setupLives();
}
@@ -123,6 +118,20 @@ int dWMHud_c::onCreate() {
}
+void dWMHud_c::loadInitially() {
+ if (doneFirstShow)
+ return;
+
+ doneFirstShow = true;
+
+ SaveBlock *save = GetSaveFile()->GetBlock(-1);
+ willShowFooter = (save->newerWorldName[0] != 0) && (save->hudHintH != 2000);
+
+ if (!dScKoopatlas_c::instance->pathManager.isMoving)
+ enteredNode();
+}
+
+
int dWMHud_c::onDelete() {
dWMHud_c::instance = 0;
diff --git a/src/koopatlas/hud.h b/src/koopatlas/hud.h
index 982b38a..2fd194e 100644
--- a/src/koopatlas/hud.h
+++ b/src/koopatlas/hud.h
@@ -19,6 +19,9 @@ class dWMHud_c : public dBase_c {
static dWMHud_c *build();
static dWMHud_c *instance;
+ bool doneFirstShow;
+ void loadInitially();
+
void enteredNode(dKPNode_s *node = 0);
void leftNode();
diff --git a/src/koopatlas/pathmanager.cpp b/src/koopatlas/pathmanager.cpp
index 89b9f59..48590f9 100644
--- a/src/koopatlas/pathmanager.cpp
+++ b/src/koopatlas/pathmanager.cpp
@@ -50,12 +50,14 @@ void dWMPathManager_c::setup() {
levelStartWait = -1;
unlockPaths();
- waitForAfterDeathAnim = -1;
- mustPlayAfterDeathAnim = false;
+ waitAfterInitialPlayerAnim = -1;
if (LastPowerupStoreType == LOSE_LEVEL) {
mustPlayAfterDeathAnim = true;
daWMPlayer_c::instance->visible = false;
LastPowerupStoreType = BEAT_LEVEL;
+ } else if (LastPowerupStoreType == BEAT_LEVEL && LastLevelPlayed[0] != 0xFF) {
+ mustPlayAfterWinAnim = true;
+ daWMPlayer_c::instance->visible = false;
}
SpammyReport("done\n");
@@ -78,7 +80,7 @@ void dWMPathManager_c::setup() {
found = true;
currentNode = node;
- //OSReport("Found CHANGE node: %d %p\n", changeID, node);
+ SpammyReport("Found CHANGE node: %d %p\n", changeID, node);
// figure out where we should move to
dKPPath_s *exitTo = 0;
@@ -237,6 +239,8 @@ void dWMPathManager_c::setup() {
if (wm->isAfterKamekCutscene)
copyWorldDefToSave(wm->mapData.findWorldDef(1));
+
+ finalisePathUnlocks();
}
static u8 *PathAvailabilityData = 0;
@@ -505,10 +509,13 @@ void dWMPathManager_c::unlockPaths() {
node->setLayerAlpha((node->isUnlocked() & !node->isNew) ? 255 : 0);
}
+}
+void dWMPathManager_c::finalisePathUnlocks() {
// if anything was new, set it as such
if (newlyAvailablePaths || newlyAvailableNodes) {
countdownToFadeIn = 30;
+ findCameraBoundsForUnlockedPaths();
}
unlockingAlpha = -1;
}
@@ -592,7 +599,9 @@ bool dWMPathManager_c::evaluateUnlockCondition(u8 *&in, SaveBlock *save, int sta
bool dWMPathManager_c::doingThings() {
if (isEnteringLevel || (waitAfterUnlock > 0) || (completionAnimDelay > 0) ||
- (waitAtStart > 0) || (waitForAfterDeathAnim > 0) ||
+ (waitAtStart > 0) || (waitAfterInitialPlayerAnim > 0) ||
+ panningCameraToPaths || panningCameraFromPaths ||
+ (waitBeforePanBack > 0) ||
(countdownToFadeIn > 0) || (unlockingAlpha != -1))
return true;
@@ -613,11 +622,52 @@ void dWMPathManager_c::execute() {
return;
}
+ if (waitAtStart > 0) {
+ waitAtStart--;
+ if (waitAtStart == 0) {
+ if (mustPlayAfterDeathAnim) {
+ daWMPlayer_c::instance->visible = true;
+ daWMPlayer_c::instance->startAnimation(ending_wait, 1.0f, 0.0f, 0.0f);
+ waitAfterInitialPlayerAnim = 60;
+
+ nw4r::snd::SoundHandle something;
+ PlaySoundWithFunctionB4(SoundRelatedClass, &something, SE_VOC_MA_CS_COURSE_MISS, 1);
+ } else if (mustPlayAfterWinAnim) {
+ daWMPlayer_c::instance->visible = true;
+ daWMPlayer_c::instance->startAnimation(dm_surp_wait, 1.0f, 0.0f, 0.0f);
+ waitAfterInitialPlayerAnim = 38;
+
+ nw4r::snd::SoundHandle something;
+ PlaySoundWithFunctionB4(SoundRelatedClass, &something, SE_VOC_MA_CS_JUMP, 1);
+ }
+ }
+ return;
+ }
+
+ if (waitAfterInitialPlayerAnim > 0) {
+ waitAfterInitialPlayerAnim--;
+ if (waitAfterInitialPlayerAnim == 0)
+ daWMPlayer_c::instance->startAnimation(wait_select, 1.0f, 0.0f, 0.0f);
+ if (mustPlayAfterWinAnim && (waitAfterInitialPlayerAnim == 9)) {
+ nw4r::snd::SoundHandle something;
+ PlaySoundWithFunctionB4(SoundRelatedClass, &something, SE_PLY_LAND_ROCK, 1);
+ }
+ return;
+ }
+
+
// handle path fading
if (countdownToFadeIn > 0) {
countdownToFadeIn--;
if (countdownToFadeIn <= 0) {
- unlockingAlpha = 0;
+ if (camBoundsValid) {
+ dWorldCamera_c::instance->currentX = currentNode->x;
+ dWorldCamera_c::instance->currentY = -currentNode->y;
+ dWorldCamera_c::instance->panToBounds(camMinX, camMinY, camMaxX, camMaxY);
+
+ panningCameraToPaths = true;
+ } else
+ unlockingAlpha = 0;
nw4r::snd::SoundHandle something;
PlaySoundWithFunctionB4(SoundRelatedClass, &something, SE_OBJ_GEN_LOAD, 1);
@@ -626,6 +676,13 @@ void dWMPathManager_c::execute() {
}
}
+ if (panningCameraToPaths) {
+ if (dWorldCamera_c::instance->panning)
+ return;
+ panningCameraToPaths = false;
+ unlockingAlpha = 0;
+ }
+
if (unlockingAlpha != -1) {
unlockingAlpha += 3;
@@ -648,6 +705,7 @@ void dWMPathManager_c::execute() {
unlockingAlpha = -1;
nw4r::snd::SoundHandle something;
PlaySoundWithFunctionB4(SoundRelatedClass, &something, SE_OBJ_GEN_NEW_COURSE, 1);
+
waitAfterUnlock = 15;
for (int i = 0; i < pathLayer->nodeCount; i++) {
@@ -667,16 +725,36 @@ void dWMPathManager_c::execute() {
if (waitAfterUnlock > 0) {
waitAfterUnlock--;
+ if (waitAfterUnlock == 0)
+ waitBeforePanBack = 20;
return;
}
+ if (waitBeforePanBack > 0) {
+ waitBeforePanBack--;
+ if (waitBeforePanBack == 0 && camBoundsValid) {
+ dWorldCamera_c::instance->panToPosition(
+ currentNode->x, -currentNode->y,
+ STD_ZOOM);
+ panningCameraFromPaths = true;
+ }
+ }
+
+ if (panningCameraFromPaths) {
+ if (dWorldCamera_c::instance->panning)
+ return;
+ panningCameraFromPaths = false;
+ dWorldCamera_c::instance->followPlayer = true;
+ }
+
+ if (dmGladDuration > 0) {
+ dmGladDuration--;
+ if (dmGladDuration == 0)
+ daWMPlayer_c::instance->startAnimation(wait_select, 1.0f, 0.0f, 0.0f);
+ }
+
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;
@@ -710,35 +788,17 @@ void dWMPathManager_c::execute() {
return;
}
- if (waitAtStart > 0) {
- waitAtStart--;
- if (waitAtStart == 0) {
- if (mustPlayAfterDeathAnim) {
- daWMPlayer_c::instance->visible = true;
- daWMPlayer_c::instance->startAnimation(ending_wait, 1.0f, 0.0f, 0.0f);
- waitForAfterDeathAnim = 60;
-
- nw4r::snd::SoundHandle something;
- PlaySoundWithFunctionB4(SoundRelatedClass, &something, SE_VOC_MA_CS_COURSE_MISS, 1);
- }
-
- dScKoopatlas_c::instance->startMusic();
- }
- return;
- }
-
- if (waitForAfterDeathAnim > 0) {
- waitForAfterDeathAnim--;
- if (waitForAfterDeathAnim == 0)
- daWMPlayer_c::instance->startAnimation(wait_select, 1.0f, 0.0f, 0.0f);
- return;
- }
-
if (shouldRequestSave) {
dScKoopatlas_c::instance->showSaveWindow();
shouldRequestSave = false;
}
+ if (!initialLoading) {
+ dScKoopatlas_c::instance->startMusic();
+ dWMHud_c::instance->loadInitially();
+ initialLoading = true;
+ }
+
int nowPressed = Remocon_GetPressed(GetActiveRemocon());
// Left, right, up, down
@@ -1191,7 +1251,7 @@ void dWMPathManager_c::moveThroughPath(int pressedDir) {
} else if (reallyStop) {
// Stop here
- player->startAnimation(0, 1.2, 10.0, 0.0);
+ player->startAnimation(wait_select, 1.2, 10.0, 0.0);
player->hasEffect = false;
player->hasSound = false;
@@ -1314,3 +1374,75 @@ void dWMPathManager_c::unlockAllPaths(char type) {
}
+
+
+void dWMPathManager_c::findCameraBoundsForUnlockedPaths() {
+ dKPMapData_c *data = &dScKoopatlas_c::instance->mapData;
+
+ camMinX = 10000;
+ camMaxX = 0;
+ camMinY = 10000;
+ camMaxY = 0;
+
+ nodeStackLength = 0;
+ for (int i = 0; i < data->pathLayer->nodeCount; i++)
+ data->pathLayer->nodes[i]->reserved1 = false;
+
+ visitNodeForCamCheck(currentNode);
+ OSReport("Worked out camera bounds: %d,%d to %d,%d with validity %d\n", camMinX, camMinY, camMaxX, camMaxY, camBoundsValid);
+}
+
+void dWMPathManager_c::visitNodeForCamCheck(dKPNode_s *node) {
+ // Yay.
+ nodeStackLength++;
+ node->reserved1 = true;
+
+ for (int i = 0; i < 4; i++) {
+ dKPPath_s *path = node->exits[i];
+ if (!path)
+ continue;
+
+ OSReport("Checking path %p, whose status is %d\n", path, path->isAvailable);
+ if (path->isAvailable == dKPPath_s::NEWLY_AVAILABLE) {
+ addNodeToCameraBounds(path->start);
+ addNodeToCameraBounds(path->end);
+ }
+
+ // Should we follow the other node?
+ dKPNode_s *otherNode = path->getOtherNodeTo(node);
+
+ if (otherNode->reserved1)
+ continue;
+ if (otherNode->type == otherNode->LEVEL) {
+ OSReport("Not travelling to %p because it's level %d-%d\n", otherNode, otherNode->levelNumber[0], otherNode->levelNumber[1]);
+ continue;
+ }
+ if (otherNode->type == otherNode->CHANGE) {
+ OSReport("Not travelling to %p because it's a change\n", otherNode);
+ continue;
+ }
+ if (otherNode->type == otherNode->WORLD_CHANGE) {
+ OSReport("Not travelling to %p because it's a world change\n", otherNode);
+ continue;
+ }
+
+ visitNodeForCamCheck(otherNode);
+ }
+
+ nodeStackLength--;
+}
+
+void dWMPathManager_c::addNodeToCameraBounds(dKPNode_s *node) {
+ camBoundsValid = true;
+ OSReport("Adding node to camera bounds: %p at %d,%d\n", node, node->x, node->y);
+
+ if (node->x < camMinX)
+ camMinX = node->x;
+ if (node->x > camMaxX)
+ camMaxX = node->x;
+ if (node->y < camMinY)
+ camMinY = node->y;
+ if (node->y > camMaxY)
+ camMaxY = node->y;
+}
+
diff --git a/src/koopatlas/pathmanager.h b/src/koopatlas/pathmanager.h
index 522db7f..27fcfd6 100644
--- a/src/koopatlas/pathmanager.h
+++ b/src/koopatlas/pathmanager.h
@@ -74,12 +74,16 @@ class dWMPathManager_c {
int newlyAvailablePaths;
int newlyAvailableNodes;
+ bool panningCameraToPaths;
+ bool panningCameraFromPaths;
int unlockingAlpha; // -1 if not used
int countdownToFadeIn;
int waitAfterUnlock;
+ int waitBeforePanBack;
private:
void unlockPaths();
+ void finalisePathUnlocks();
bool evaluateUnlockCondition(u8 *&in, SaveBlock *save, int stack);
int cachedTotalStarCoinCount;
int cachedUnspentStarCoinCount;
@@ -97,11 +101,22 @@ class dWMPathManager_c {
int levelStartWait;
int waitAtStart;
bool mustPlayAfterDeathAnim;
- int waitForAfterDeathAnim;
+ bool mustPlayAfterWinAnim;
+ int waitAfterInitialPlayerAnim;
+ bool initialLoading;
bool doingThings();
dLevelInfo_c::entry_s *enteredLevel;
+
+
+ private:
+ int camMinX, camMinY, camMaxX, camMaxY;
+ int nodeStackLength;
+ bool camBoundsValid;
+ void visitNodeForCamCheck(dKPNode_s *node);
+ void findCameraBoundsForUnlockedPaths();
+ void addNodeToCameraBounds(dKPNode_s *node);
};
#endif