summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--koopatlas.yaml2
-rw-r--r--src/koopatlas/camera.cpp63
-rw-r--r--src/koopatlas/camera.h4
-rw-r--r--src/koopatlas/core.cpp55
-rw-r--r--src/koopatlas/core.h8
-rw-r--r--src/koopatlas/hud.cpp23
-rw-r--r--src/koopatlas/hud.h5
-rw-r--r--src/koopatlas/map.cpp2
-rw-r--r--src/koopatlas/map.h5
-rw-r--r--src/koopatlas/mapdata.cpp35
-rw-r--r--src/koopatlas/mapdata.h34
-rw-r--r--src/koopatlas/pathmanager.cpp130
-rw-r--r--src/koopatlas/pathmanager.h29
-rw-r--r--src/koopatlas/player.h4
-rw-r--r--src/levelinfo.cpp37
-rw-r--r--src/levelinfo.h56
16 files changed, 414 insertions, 78 deletions
diff --git a/koopatlas.yaml b/koopatlas.yaml
index 9c4af7b..37c4a3d 100644
--- a/koopatlas.yaml
+++ b/koopatlas.yaml
@@ -3,6 +3,7 @@ source_files:
- ../src/fileload.cpp
- ../src/scene.S
- ../src/levelinfo.cpp
+ - ../src/levelinfo_old.cpp # backwards compatibility for LevelNames
- ../src/player.cpp
- ../src/effects.cpp
- ../src/koopatlas/core.cpp
@@ -11,6 +12,7 @@ source_files:
- ../src/koopatlas/camera.cpp
- ../src/koopatlas/map.cpp
- ../src/koopatlas/mapdata.cpp
+ - ../src/koopatlas/pathmanager.cpp
hooks:
- name: BuildWorldMap
diff --git a/src/koopatlas/camera.cpp b/src/koopatlas/camera.cpp
index bfcc674..9efbcd6 100644
--- a/src/koopatlas/camera.cpp
+++ b/src/koopatlas/camera.cpp
@@ -31,8 +31,8 @@ dWorldCamera_c::dWorldCamera_c() {
projection2d.near = 1.0;
projection2d.far = 20000.0;
- currentX = 0;
- currentY = 0;
+ currentX = 416;
+ currentY = -224;
zoomLevel = 2.0f;
}
@@ -68,34 +68,37 @@ int dWorldCamera_c::onDelete() {
int dWorldCamera_c::onExecute() {
- int nowPressed = Remocon_GetPressed(GetActiveRemocon());
- bool change = false;
- if (nowPressed & WPAD_LEFT) {
- currentX -= 16;
- change = true;
- }
- if (nowPressed & WPAD_RIGHT) {
- currentX += 16;
- change = true;
- }
- if (nowPressed & WPAD_UP) {
- currentY += 16;
- change = true;
- }
- if (nowPressed & WPAD_DOWN) {
- currentY -= 16;
- change = true;
- }
- if (nowPressed & WPAD_B) {
- zoomLevel -= 0.02;
- change = true;
- }
- if (nowPressed & WPAD_A) {
- zoomLevel += 0.02;
- change = true;
- }
- if (change) {
- OSReport("%f, %f (%f)\n", currentX, currentY, zoomLevel);
+ int heldButtons = Remocon_GetButtons(GetActiveRemocon());
+ if (heldButtons & WPAD_MINUS) {
+ int nowPressed = Remocon_GetPressed(GetActiveRemocon());
+ bool change = false;
+ if (nowPressed & WPAD_LEFT) {
+ currentX -= 16;
+ change = true;
+ }
+ if (nowPressed & WPAD_RIGHT) {
+ currentX += 16;
+ change = true;
+ }
+ if (nowPressed & WPAD_UP) {
+ currentY += 16;
+ change = true;
+ }
+ if (nowPressed & WPAD_DOWN) {
+ currentY -= 16;
+ change = true;
+ }
+ if (nowPressed & WPAD_B) {
+ zoomLevel -= 0.02;
+ change = true;
+ }
+ if (nowPressed & WPAD_A) {
+ zoomLevel += 0.02;
+ change = true;
+ }
+ if (change) {
+ OSReport("%f, %f (%f)\n", currentX, currentY, zoomLevel);
+ }
}
calculateScreenGeometry();
doStuff(10000.0);
diff --git a/src/koopatlas/camera.h b/src/koopatlas/camera.h
index f057374..39e34d0 100644
--- a/src/koopatlas/camera.h
+++ b/src/koopatlas/camera.h
@@ -1,3 +1,6 @@
+#ifndef __KOOPATLAS_CAMERA_H
+#define __KOOPATLAS_CAMERA_H
+
#include "koopatlas/core.h"
class dWorldCamera_c : public dBase_c {
@@ -34,4 +37,5 @@ class dWorldCamera_c : public dBase_c {
static dWorldCamera_c *instance;
};
+#endif
diff --git a/src/koopatlas/core.cpp b/src/koopatlas/core.cpp
index fb1e865..03b64dc 100644
--- a/src/koopatlas/core.cpp
+++ b/src/koopatlas/core.cpp
@@ -158,10 +158,9 @@ bool WMInit_LoadResources(void *ptr) {
SpammyReport("WMInit_LoadResources returning true\n");
dScKoopatlas_c *wm = (dScKoopatlas_c*)ptr;
- return wm->mapData.load("/Maps/yat.kpbin");
- //TODO
- //return wm->resMng.loadSet("MMFullWorld");
- //return true;
+ return
+ wm->mapData.load("/Maps/yat.kpbin") &&
+ wm->levelInfoLoader.load("/NewerRes/LevelInfo.bin");
}
bool WMInit_SetupWait(void *ptr) {
@@ -203,21 +202,24 @@ bool WMInit_SetupExtra(void *ptr) {
}
// since we've got all the resources, set up the path data too
- //wm->pathManager->setup();
- //wm->pathManager->computeEvents();
+ SpammyReport("preparing level info\n");
+ wm->levelInfo.load(wm->levelInfoLoader.buffer);
+ wm->pathManager.setup();
// and now Player setup
wm->player = (daWMPlayer_c*)CreateParentedObject(WM_PLAYER, wm, 0, 2);
wm->player->modelHandler->mdlClass->setPowerup(2);
wm->player->modelHandler->mdlClass->startAnimation(0, 1.2f, 10.0f, 0.0f);
- //wm->player->pos = wm->pathManager->currentPoint->position;
+
+ dKPNode_s *cNode = wm->pathManager.currentNode;
+ wm->player->pos = (Vec){cNode->x, -cNode->y, wm->player->pos.y};
// is last param correct? must check :/
wm->map = (dWMMap_c*)CreateParentedObject(WM_MAP, wm, 0, 0);
wm->hud = (dWMHud_c*)CreateParentedObject(WM_HUD, wm, 0, 0);
- // note: world_camera and wm_path_manager are not created here
- // because we require them earlier
- // they are created in dScKoopatlas_c::onCreate
+ // note: world_camera is not created here
+ // because we require it earlier
+ // it is created in dScKoopatlas_c::onCreate
return true;
}
@@ -334,8 +336,6 @@ int dScKoopatlas_c::onCreate() {
SpammyReport("world camera\n");
CreateParentedObject(WORLD_CAMERA, this, 0, 0);
- /*pathManager = (dWMPathManager_c*)CreateParentedObject(WM_PATH_MANAGER, this, 0, 0);*/
-
SpammyReport("setting NewerMapDrawFunc\n");
*CurrentDrawFunc = NewerMapDrawFunc;
@@ -411,6 +411,8 @@ void dScKoopatlas_c::executeState_Normal() {
CSMENU_ACTIVE(this->csMenu) = true;
state.setState(&StateID_CSMenu);
}
+
+ pathManager.execute();
}
void dScKoopatlas_c::executeState_CSMenu() {
@@ -798,6 +800,35 @@ void dScKoopatlas_c::executeState_QuickSaveEndCloseWait() {
void dScKoopatlas_c::executeState_SaveError() { }
+void dScKoopatlas_c::startLevel(dLevelInfo_c::entry_s *entry) {
+ for (int i = 0; i < 4; i++) {
+ bool isThere = QueryPlayerAvailability(i);
+ int id = Player_ID[i];
+ Player_Active[i] = isThere ? 1 : 0;
+ if (!isThere) Player_Flags[i] = 0;
+ }
+
+ StartLevelInfo sl;
+ sl.unk1 = 0;
+ sl.unk2 = 0xFF;
+ sl.unk3 = 0;
+ 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);
+
+ ActivateWipe(WIPE_MARIO);
+
+ DoStartLevel(GetGameMgr(), &sl);
+}
+
+
void NewerMapDrawFunc() {
Reset3DState();
SetCurrentCameraID(0);
diff --git a/src/koopatlas/core.h b/src/koopatlas/core.h
index cfe5bde..9ca1935 100644
--- a/src/koopatlas/core.h
+++ b/src/koopatlas/core.h
@@ -9,7 +9,9 @@
#include <game.h>
#include <g3dhax.h>
+#include "levelinfo.h"
#include "koopatlas/mapdata.h"
+#include "koopatlas/pathmanager.h"
#define WM_DEBUGGING
//#define WM_SPAMMY_DEBUGGING
@@ -89,8 +91,14 @@ class dScKoopatlas_c : public dScene_c {
daWMPlayer_c *player;
dWMHud_c *hud;
dWMMap_c *map;
+
dKPMapData_c mapData;
+ dWMPathManager_c pathManager;
+
+ dDvdLoader_c levelInfoLoader;
+ dLevelInfo_c levelInfo;
+ void startLevel(dLevelInfo_c::entry_s *level);
bool canDoStuff();
};
diff --git a/src/koopatlas/hud.cpp b/src/koopatlas/hud.cpp
index c5b2c6e..183e85f 100644
--- a/src/koopatlas/hud.cpp
+++ b/src/koopatlas/hud.cpp
@@ -95,13 +95,14 @@ void dWMHud_c::setPointName() {
int length;
// figure this out...
- /*WMPathPoint *point = dWMPathManager_c::instance->currentPoint;
+ dKPNode_s *node = dScKoopatlas_c::instance->pathManager.currentNode;
- if (point->type == WMPathPoint::LEVEL_TYPE) {
- LevelInfo *li = &dScNewerWorldMap_c::instance->levelInfo;
- LevelInfo::Entry *entry = li->search(point->params[0] - 1, point->params[1] - 1);
+ if (node->type == dKPNode_s::LEVEL) {
+ OSReport("Trying level %d-%d\n", node->levelNumber[0], node->levelNumber[1]);
+ dLevelInfo_c *li = &dScKoopatlas_c::instance->levelInfo;
+ dLevelInfo_c::entry_s *entry = li->search(node->levelNumber[0] - 1, node->levelNumber[1] - 1);
- char *levelName = li->getNameForLevel(entry);
+ const char *levelName = li->getNameForLevel(entry);
// copy it
// I need to make this into a function.
@@ -114,13 +115,7 @@ void dWMHud_c::setPointName() {
} else {
newPointName[0] = 0;
length = 0;
- }*/
-
- const char *str = "This needs to be done\0";
- length = 21;
- for (int i = 0; i < length; i++)
- newPointName[i] = str[i];
- newPointName[length] = 0;
+ }
nw4r::lyt::TextBox *box = layout.findTextBoxByName("T_levelname_01");
@@ -144,9 +139,9 @@ void dWMHud_c::setPointName() {
void dWMHud_c::showPointBar() {
- //WMPathPoint *point = dWMPathManager_c::instance->currentPoint;
+ dKPNode_s *node = dScKoopatlas_c::instance->pathManager.currentNode;
- if (true) {//point->type == WMPathPoint::LEVEL_TYPE) {
+ if (node->type == dKPNode_s::LEVEL) {
isPointBarShown = true;
updateText();
diff --git a/src/koopatlas/hud.h b/src/koopatlas/hud.h
index 71dacdd..1ef94ce 100644
--- a/src/koopatlas/hud.h
+++ b/src/koopatlas/hud.h
@@ -1,3 +1,6 @@
+#ifndef __KOOPATLAS_HUD_H
+#define __KOOPATLAS_HUD_H
+
#include "koopatlas/core.h"
class dWMHud_c : public dBase_c {
@@ -26,3 +29,5 @@ class dWMHud_c : public dBase_c {
bool isPointBarShown;
};
+#endif
+
diff --git a/src/koopatlas/map.cpp b/src/koopatlas/map.cpp
index 35aadab..ac7cc51 100644
--- a/src/koopatlas/map.cpp
+++ b/src/koopatlas/map.cpp
@@ -81,7 +81,7 @@ void dWMMap_c::renderer_c::drawLayers() {
dKPMapData_c *dataCls = &dScKoopatlas_c::instance->mapData;
dKPMapFile_s *data = dataCls->data;
- baseZ = -(2 * data->layerCount);
+ baseZ = -100 - (2 * data->layerCount);
beginRendering();
diff --git a/src/koopatlas/map.h b/src/koopatlas/map.h
index 2e7b7b6..c74384f 100644
--- a/src/koopatlas/map.h
+++ b/src/koopatlas/map.h
@@ -1,3 +1,6 @@
+#ifndef __KOOPATLAS_MAP_H
+#define __KOOPATLAS_MAP_H
+
#include "koopatlas/core.h"
// Can't remember why I had this. Who cares
@@ -60,3 +63,5 @@ class dWMMap_c : public dBase_c {
static dWMMap_c *instance;
};
+#endif
+
diff --git a/src/koopatlas/mapdata.cpp b/src/koopatlas/mapdata.cpp
index 37565ea..a6031b1 100644
--- a/src/koopatlas/mapdata.cpp
+++ b/src/koopatlas/mapdata.cpp
@@ -1,6 +1,31 @@
#include "koopatlas/mapdata.h"
+// HELPER FUNCTIONS
+dKPPath_s *dKPNode_s::getOppositeExitTo(dKPPath_s *path) {
+ for (int i = 0; i < 4; i++) {
+ dKPPath_s *check = exits[i];
+
+ if (check != 0 && check != path)
+ return check;
+ }
+
+ return 0;
+}
+
+
+int dKPLayer_s::findNodeID(dKPNode_s *node) {
+ for (int i = 0; i < nodeCount; i++)
+ if (nodes[i] == node)
+ return i;
+
+ return -1;
+}
+
+
+
+
+
dKPMapData_c::dKPMapData_c() {
data = 0;
fixedUp = false;
@@ -83,6 +108,8 @@ void dKPMapData_c::fixup() {
break;
case dKPLayer_s::PATHS:
+ pathLayer = layer;
+
fixRef(layer->paths);
fixRef(layer->nodes);
@@ -112,14 +139,6 @@ void dKPMapData_c::fixup() {
}
}
- fixRef(data->unlocks);
-
- for (int iUnlock = 0; iUnlock < data->unlockCount; iUnlock++) {
- dKPUnlock_s *unlock = &data->unlocks[iUnlock];
-
- fixRef(unlock->targetPath);
- }
-
fixRef(data->tilesets);
}
diff --git a/src/koopatlas/mapdata.h b/src/koopatlas/mapdata.h
index b6d1838..f9aa545 100644
--- a/src/koopatlas/mapdata.h
+++ b/src/koopatlas/mapdata.h
@@ -1,3 +1,6 @@
+#ifndef __KOOPATLAS_MAPDATA_H
+#define __KOOPATLAS_MAPDATA_H
+
#include <game.h>
// forward declarations
@@ -50,22 +53,34 @@ struct dKPNode_s {
};
short x, y;
- dKPPath_s *exits[4];
+ union {
+ dKPPath_s *exits[4];
+ struct {
+ dKPPath_s *leftExit;
+ dKPPath_s *rightExit;
+ dKPPath_s *upExit;
+ dKPPath_s *downExit;
+ };
+ };
dKPLayer_s *tileLayer, *doodadLayer;
- int type;
+ NodeTypes type;
union {
struct { u8 levelNumber[2]; };
struct { char *destMap; u8 thisID, foreignID, transition; };
};
+
+
+ dKPPath_s *getOppositeExitTo(dKPPath_s *path);
};
struct dKPPath_s {
dKPNode_s *start, *end;
dKPLayer_s *tileLayer, *doodadLayer;
- u8 unlockType; // 0 = always, 1 = start, 2 = end
- u8 unlockIsSecret;
+ u8 unlockType; // 0 = always, 1 = normal, 2 = secret
+ u8 unlockLevelNumber[2];
+ bool isAvailable; // computed on-the-fly - default from Koopatlas is true
float speed;
int animation;
};
@@ -118,23 +133,15 @@ struct dKPLayer_s {
dKPPath_s **paths;
};
};
-};
-struct dKPUnlock_s {
- u8 isSecret;
- u8 level[2];
- u8 _;
- dKPPath_s *targetPath;
+ int findNodeID(dKPNode_s *node);
};
struct dKPMapFile_s {
int layerCount;
dKPLayer_s **layers;
- int unlockCount;
- dKPUnlock_s *unlocks;
-
int tilesetCount;
GXTexObj *tilesets;
@@ -191,4 +198,5 @@ class dKPMapData_c {
~dKPMapData_c();
};
+#endif
diff --git a/src/koopatlas/pathmanager.cpp b/src/koopatlas/pathmanager.cpp
new file mode 100644
index 0000000..30f4920
--- /dev/null
+++ b/src/koopatlas/pathmanager.cpp
@@ -0,0 +1,130 @@
+#include "koopatlas/pathmanager.h"
+#include "koopatlas/core.h"
+#include "koopatlas/hud.h"
+#include "koopatlas/player.h"
+
+void dWMPathManager_c::setup() {
+ isMoving = false;
+ currentPath = 0;
+ reverseThroughPath = false;
+
+ pathLayer = dScKoopatlas_c::instance->mapData.pathLayer;
+
+ SaveBlock *save = GetSaveFile()->GetBlock(-1);
+ if (save->current_path_node >= pathLayer->nodeCount) {
+ currentNode = pathLayer->nodes[0];
+ } else {
+ currentNode = pathLayer->nodes[save->current_path_node];
+ }
+
+ // unlock all needed paths
+ for (int i = 0; i < pathLayer->pathCount; i++) {
+ dKPPath_s *path = pathLayer->paths[i];
+
+ if (path->unlockType > 0) {
+ u32 conds = save->GetLevelCondition(path->unlockLevelNumber[0] - 1, path->unlockLevelNumber[1] - 1);
+
+ if (path->unlockType == 1 && (conds & COND_NORMAL))
+ path->isAvailable = true;
+ else if (path->unlockType == 2 && (conds & COND_SECRET))
+ path->isAvailable = true;
+ }
+ }
+}
+
+
+void dWMPathManager_c::execute() {
+ int nowPressed = Remocon_GetPressed(GetActiveRemocon());
+
+ if (isMoving) {
+ moveThroughPath();
+ } else {
+ if (nowPressed & WPAD_LEFT && canUseExit(currentNode->leftExit))
+ startMovementTo(currentNode->leftExit);
+ else if (nowPressed & WPAD_RIGHT && canUseExit(currentNode->rightExit))
+ startMovementTo(currentNode->rightExit);
+ else if (nowPressed & WPAD_UP && canUseExit(currentNode->upExit))
+ startMovementTo(currentNode->upExit);
+ else if (nowPressed & WPAD_DOWN && canUseExit(currentNode->downExit))
+ startMovementTo(currentNode->downExit);
+ else if (nowPressed & WPAD_TWO)
+ activatePoint();
+ }
+}
+
+
+void dWMPathManager_c::startMovementTo(dKPPath_s *path) {
+ dWMHud_c::instance->hidePointBar();
+
+ isMoving = true;
+ reverseThroughPath = (path->end == currentNode);
+
+ currentPath = path;
+
+ // calculate direction of the path
+ short deltaX = path->end->x - path->start->x;
+ short deltaY = path->end->y - path->start->y;
+ u16 direction = (u16)(atan2(deltaX, deltaY) / ((M_PI * 2) / 65536.0));
+
+ if (reverseThroughPath) {
+ direction += 0x8000;
+ }
+
+ daWMPlayer_c *player = daWMPlayer_c::instance;
+ player->startAnimation(2, 2.0, 10.0, 0.0);
+ player->rot.y = direction;
+}
+
+void dWMPathManager_c::moveThroughPath() {
+ dKPNode_s *from, *to;
+
+ from = reverseThroughPath ? currentPath->end : currentPath->start;
+ to = reverseThroughPath ? currentPath->start : currentPath->end;
+
+ Vec move = (Vec){to->x - from->x, to->y - from->y, 0};
+ VECNormalize(&move, &move);
+ VECScale(&move, &move, 1.5);
+
+ daWMPlayer_c *player = daWMPlayer_c::instance;
+
+ player->pos.x += move.x;
+ player->pos.y -= move.y;
+
+ // Check if we've reached the end yet
+ if (
+ ((move.x > 0) ? (player->pos.x >= to->x) : (player->pos.x <= to->x)) &&
+ ((move.y > 0) ? (-player->pos.y >= to->y) : (-player->pos.y <= to->y))
+ ) {
+
+ currentNode = to;
+ player->pos.x = to->x;
+ player->pos.y = -to->y;
+
+ if (to->type != dKPNode_s::PASS_THROUGH) {
+ // Stop here
+ player->startAnimation(0, 1.2, 10.0, 0.0);
+
+ isMoving = false;
+
+ SaveBlock *save = GetSaveFile()->GetBlock(-1);
+ save->current_path_node = pathLayer->findNodeID(to);
+
+ dWMHud_c::instance->showPointBar();
+ } else {
+ startMovementTo(to->getOppositeExitTo(currentPath));
+ }
+ }
+}
+
+void dWMPathManager_c::activatePoint() {
+ if (currentNode->type == dKPNode_s::LEVEL) {
+ daWMPlayer_c::instance->startAnimation(170, 1.2, 10.0, 0.0);
+
+ int w = currentNode->levelNumber[0] - 1;
+ int l = currentNode->levelNumber[1] - 1;
+ dLevelInfo_c::entry_s *level = dScKoopatlas_c::instance->levelInfo.search(w, l);
+ dScKoopatlas_c::instance->startLevel(level);
+ }
+}
+
+
diff --git a/src/koopatlas/pathmanager.h b/src/koopatlas/pathmanager.h
new file mode 100644
index 0000000..3ddcf58
--- /dev/null
+++ b/src/koopatlas/pathmanager.h
@@ -0,0 +1,29 @@
+#ifndef __KOOPATLAS_PATH_MANAGER_H
+#define __KOOPATLAS_PATH_MANAGER_H
+
+#include "koopatlas/mapdata.h"
+
+class dWMPathManager_c {
+ public:
+ void setup();
+ void execute();
+
+ bool canUseExit(dKPPath_s *path) {
+ return (path != 0) && (path->isAvailable);
+ }
+
+ void startMovementTo(dKPPath_s *path);
+ void moveThroughPath();
+ void activatePoint();
+
+ dKPLayer_s *pathLayer;
+
+ bool isMoving;
+ dKPNode_s *currentNode;
+
+ dKPPath_s *currentPath;
+ bool reverseThroughPath; // direction we are going through the path
+};
+
+#endif
+
diff --git a/src/koopatlas/player.h b/src/koopatlas/player.h
index d5fcc33..2b53119 100644
--- a/src/koopatlas/player.h
+++ b/src/koopatlas/player.h
@@ -1,3 +1,6 @@
+#ifndef __KOOPATLAS_PLAYER_H
+#define __KOOPATLAS_PLAYER_H
+
#include "koopatlas/core.h"
class daWMPlayer_c : public dActor_c {
@@ -22,4 +25,5 @@ class daWMPlayer_c : public dActor_c {
static daWMPlayer_c *instance;
};
+#endif
diff --git a/src/levelinfo.cpp b/src/levelinfo.cpp
new file mode 100644
index 0000000..3a0ef6f
--- /dev/null
+++ b/src/levelinfo.cpp
@@ -0,0 +1,37 @@
+#include "levelinfo.h"
+
+void dLevelInfo_c::load(void *buffer) {
+ data = (header_s*)buffer;
+
+ // decode all the level names
+ for (int sect = 0; sect < sectionCount(); sect++) {
+ // parse this section
+ section_s *thisSect = getSectionByIndex(sect);
+ entry_s *levels = getLevelsForSection(thisSect);
+
+ for (int lev = 0; lev < thisSect->levelCount; lev++) {
+ entry_s *level = &levels[lev];
+
+ char *name = (char*)getNameForLevel(level);
+
+ for (int i = 0; i < level->nameLength+1; i++) {
+ name[i] -= 0xD0;
+ }
+ }
+ }
+}
+
+dLevelInfo_c::entry_s *dLevelInfo_c::search(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)
+ return entry;
+ }
+ }
+
+ return 0;
+}
+
diff --git a/src/levelinfo.h b/src/levelinfo.h
new file mode 100644
index 0000000..470992b
--- /dev/null
+++ b/src/levelinfo.h
@@ -0,0 +1,56 @@
+#ifndef __NEWER_LEVELINFO_H
+#define __NEWER_LEVELINFO_H
+
+#include <common.h>
+
+class dLevelInfo_c {
+public:
+ struct header_s {
+ u32 magic;
+ u32 sectionCount;
+ u32 sectionOffsets[1];
+ };
+
+ struct section_s {
+ u32 levelCount;
+ };
+
+ struct entry_s {
+ u8 world;
+ u8 level;
+ u8 reserved1;
+ u8 reserved2;
+ u8 nameLength;
+ u8 reserved3;
+ u16 flags;
+ u32 nameOffset;
+ };
+
+private:
+ header_s *data;
+
+public:
+ void load(void *buffer);
+
+ entry_s *search(int world, int level);
+
+ u32 sectionCount() {
+ return data->sectionCount;
+ }
+
+ section_s *getSectionByIndex(u32 index) {
+ return (section_s*)(((char*)data) + data->sectionOffsets[index]);
+ }
+
+ entry_s *getLevelsForSection(section_s *section) {
+ return (entry_s*)(section + 1);
+ }
+
+ const char *getNameForLevel(entry_s *entry) {
+ return (const char*)data + entry->nameOffset;
+ }
+};
+
+
+#endif
+