#ifndef __KOOPATLAS_MAPDATA_H #define __KOOPATLAS_MAPDATA_H #include #include // forward declarations struct dKPLayer_s; class dKPNodeExtra_c; /****************************************************************************** * Doodads ******************************************************************************/ struct dKPDoodad_s { struct animation_s { enum LoopTypes { CONTIGUOUS, LOOP, REVERSE_LOOP }; enum CurveTypes { LINEAR, SIN, COS }; enum AnimTypes { X_POS, Y_POS, ANGLE, X_SCALE, Y_SCALE, OPACITY }; LoopTypes loop; CurveTypes curve; int frameCount; AnimTypes type; int start, end; // FORWARDS COMPATIBILITY: // int delay, delayOffset; u32 baseTick; bool isReversed; }; float x, y; float width, height; float angle; GXTexObj *texObj; int animationCount; animation_s animations[1]; // variable size }; /****************************************************************************** * Paths ******************************************************************************/ struct dKPPath_s; struct dKPNode_s { enum NodeTypes { PASS_THROUGH, STOP, LEVEL, CHANGE }; short x, y; union { dKPPath_s *exits[4]; struct { dKPPath_s *leftExit; dKPPath_s *rightExit; dKPPath_s *upExit; dKPPath_s *downExit; }; }; dKPLayer_s *tileLayer, *doodadLayer; NodeTypes type; dKPNodeExtra_c *extra; // The union is placed at the very end so we can leave out padding in the // kpbin union { // struct { u8 levelNumber[2]; }; // FORWARDS COMPATIBILITY: struct { u8 levelNumber[2]; bool hasSecret; }; struct { const char *destMap; u8 thisID, foreignID, transition, _; }; }; dKPPath_s *getAnyExit() { for (int i = 0; i < 4; i++) if (exits[i]) return exits[i]; return 0; } bool isUnlocked(); void setupNodeExtra(); dKPPath_s *getOppositeExitTo(dKPPath_s *path); }; struct dKPPath_s { dKPNode_s *start, *end; dKPLayer_s *tileLayer, *doodadLayer; 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; }; /****************************************************************************** * Tying It All Together ******************************************************************************/ struct dKPLayer_s { enum LayerTypes { OBJECTS, DOODADS, PATHS }; LayerTypes type; typedef u16 sector_s[16][16]; union { struct { GXTexObj *tileset; union { int sectorBounds[4]; struct { int sectorLeft; int sectorTop; int sectorRight; int sectorBottom; }; }; union { int bounds[4]; struct { int left; int top; int right; int bottom; }; }; u16 indices[1]; // variable size }; struct { int doodadCount; dKPDoodad_s *doodads[1]; // variable size }; struct { int nodeCount; dKPNode_s **nodes; int pathCount; dKPPath_s **paths; }; }; int findNodeID(dKPNode_s *node); }; struct dKPMapFile_s { int layerCount; dKPLayer_s **layers; int tilesetCount; GXTexObj *tilesets; dKPLayer_s::sector_s sectors[1]; // variable size }; class dKPMapData_c { private: dDvdLoader_c m_fileLoader; template inline T* fixRef(T*& indexAsPtr) { unsigned int index = (unsigned int)indexAsPtr; if (index == 0xFFFFFFFF) indexAsPtr = 0; else indexAsPtr = (T*)(((char*)data) + index); return indexAsPtr; } template inline T* fixRefSafe(T*& indexAsPtr) { unsigned int index = (unsigned int)indexAsPtr; if (index == 0xFFFFFFFF) indexAsPtr = 0; else if (index < 0x80000000) indexAsPtr = (T*)(((char*)data) + index); return indexAsPtr; } inline void fixTexObjSafe(GXTexObj *obj) { if (obj->dummy[3] >= 0x10000000) { obj->dummy[3] = (((u32)data) & 0x7FFFFFFF) + (obj->dummy[3] - 0x10000000); obj->dummy[3] >>= 5; } } bool fixedUp; bool tilesetsLoaded; void fixup(); bool loadTilesets(); void unloadTilesets(); public: dDvdLoader_c *tilesetLoaders; dKPMapFile_s *data; dKPLayer_s *pathLayer; dDvdLoader_c bgLoader; dKPNodeExtra_c *levelNodeExtraArray; dKPMapData_c(); bool load(const char *filename); ~dKPMapData_c(); }; // Currently only available for LEVEL nodes class dKPNodeExtra_c { public: mHeapAllocator_c mallocator; mMtx matrix; m3d::mdl_c model; }; #endif