#include "game.h" #include "hero.h" #include "PHL.h" #include "qda.h" #include "ini.h" #include "titlescreen.h" #include "options.h" #include "inventory.h" #include "object.h" #include "effect.h" #include "text.h" #include "stagedata.h" #include #include #include #ifdef DREAMCAST #include #include "dreamcast_icon.h" int DC_LoadVMU(void); int DC_SaveVMU(void); #endif int gameStep(); void gameDraw(char doDrawHud); void freeArrays(); void drawHud(); int getTileType(int valx, int valy); void loadUncommonImages(); char forceGameExit = 0; int drawhp; int NumOfSounds = 43; int NumOfImages = 14; char autoSave = 1; int levelStartFlag = 0; char tilesetStrings[9][12] = {"stage01.bmp", "stage02.bmp", "stage02.bmp", "stage03.bmp", "stage04.bmp", "stage03.bmp", "stage02.bmp", "stage05.bmp", "stage08.bmp" }; char musicStrings[9][14] = { "midi/main01", "midi/main02", "midi/main02", "midi/main05", "midi/main03", "midi/main05", "midi/main02", "midi/main04", "midi/main06" }; double cutInTimer = 240; int transitionTimer = 0; int level = 0; int screenX = 5, screenY = 2; #ifdef _SDL char savename[4096]; char savemap[4096]; #endif void game() { #ifdef _SDL const char* home = getenv("HOME"); if(home) { strcpy(savename, home); strcat(savename, "/.hydracastlelabyrinth/"); strcpy(savemap, savename); strcat(savename, "save.tmp"); strcat(savemap, "save.map"); } else { strcpy(savename, "data/save.tmp"); strcpy(savemap, savemap); } #ifdef DREAMCAST strcpy(savename, "/ram/save.tmp"); strcpy(savemap, "/ram/save.map"); #endif #endif //Setup services PHL_Init(); initQDA(); textInit(); iniInit(); //Load Resources loadText(); loadResources(); while (PHL_MainLoop()) { //Titlescreen int titleScreenResult = titleScreen(); //Exit game if (titleScreenResult == 2) { PHL_GameQuit(); } //Game Start else{ //Reset game state gameSetup(); //Load Game if (titleScreenResult == 1) { if (fileExists(savename) == 1) { loadSave(savename); }else if (fileExists(savemap) == 1) { loadSave(savemap); } } //Update resources, depending on level loadUncommonImages(); /*printf("\nTiles are "); if (images[imgTiles].pxdata == NULL) { printf("not loaded."); }else{ printf("loaded."); }*/ PHL_FreeSurface(images[imgTiles]); images[imgTiles] = PHL_LoadQDA(tilesetStrings[level]); PHL_FreeMusic(bgmMusic); bgmMusic = PHL_LoadMusic(musicStrings[level], 1); loadScreen(); //In game main loop char gameLoop = 1; while (PHL_MainLoop() == 1 && gameLoop == 1) { PHL_ScanInput(); int gameResult = gameStep(); if (gameResult != -1) { gameLoop = 0; } if (gameLoop == 1) { PHL_StartDrawing(); gameDraw(1); PHL_EndDrawing(); } } //Game end (return to titlescreen) roomDarkness = 0; freeArrays(); //Erase temp save if it exists if (fileExists(savename)) { #ifdef _SDL remove(savename); #else char fullPath[128]; strcpy(fullPath, ""); #ifdef _3DS strcat(fullPath, "sdmc:/3ds/appdata/HydraCastleLabyrinth/"); #endif strcat(fullPath, savename); remove(fullPath); #endif } } } //Free Resources textFree(); freeResources(); //Deinit services PHL_Deinit(); } void loadResources() { //Loading Images images[imgTiles] = PHL_LoadQDA(tilesetStrings[level]); images[imgEnemies] = PHL_LoadQDA("ene01.bmp"); images[imgHud] = PHL_LoadQDA("status.bmp"); images[imgMisc20] = PHL_LoadQDA("chr20.BMP"); images[imgMisc32] = PHL_LoadQDA("chr32.BMP"); images[imgHero] = PHL_LoadQDA("mychr.bmp"); images[imgItems] = PHL_LoadQDA("items.bmp"); images[imgExplosion] = PHL_LoadQDA("chr64.BMP"); images[imgBoss] = PHL_LoadQDA("boss01.bmp"); //images[imgMisc2040] = PHL_LoadQDA("chr20x40.BMP"); images[imgFontKana] = PHL_LoadQDA("font8x8-kana.bmp"); images[imgBoldFont] = PHL_LoadQDA("font8x8-01.bmp"); //images[imgDark] = PHL_LoadQDA("dark.bmp"); //images[imgMisc6020] = PHL_LoadQDA("chr60x20.bmp"); //images[imgHud].colorKey = PHL_NewRGB(0, 0, 0); //PHL_SetColorKey(images[imgHud], 0, 0, 0); images[imgTitle01] = PHL_LoadQDA("title01.BMP"); //Load Sounds sounds[sndBee01] = PHL_LoadSound("wav/bee01.wav"); sounds[sndBell01] = PHL_LoadSound("wav/bell01.wav"); sounds[sndBom01] = PHL_LoadSound("wav/bom01.wav"); sounds[sndBom02] = PHL_LoadSound("wav/bom02.wav"); sounds[sndBom03] = PHL_LoadSound("wav/bom03.wav"); sounds[sndDoor00] = PHL_LoadSound("wav/door00.wav"); sounds[sndFire01] = PHL_LoadSound("wav/fire01.wav"); sounds[sndGas01] = PHL_LoadSound("wav/gas01.wav"); sounds[sndGet01] = PHL_LoadSound("wav/get01.wav"); sounds[sndGet02] = PHL_LoadSound("wav/get02.wav"); sounds[sndHit01] = PHL_LoadSound("wav/hit01.wav"); sounds[sndHit02] = PHL_LoadSound("wav/hit02.wav"); sounds[sndHit03] = PHL_LoadSound("wav/hit03.wav"); sounds[sndHit04] = PHL_LoadSound("wav/hit04.wav"); sounds[sndHit05] = PHL_LoadSound("wav/hit05.wav"); sounds[sndHit06] = PHL_LoadSound("wav/hit06.wav"); sounds[sndHit07] = PHL_LoadSound("wav/hit07.wav"); sounds[sndJump01] = PHL_LoadSound("wav/jump01.wav"); sounds[sndJump02] = PHL_LoadSound("wav/jump02.wav"); sounds[sndNg] = PHL_LoadSound("wav/ng.wav"); sounds[sndOk] = PHL_LoadSound("wav/ok.wav"); sounds[sndPi01] = PHL_LoadSound("wav/pi01.wav"); sounds[sndPi02] = PHL_LoadSound("wav/pi02.wav"); sounds[sndPi03] = PHL_LoadSound("wav/pi03.wav"); sounds[sndPi04] = PHL_LoadSound("wav/pi04.wav"); sounds[sndPi05] = PHL_LoadSound("wav/pi05.wav"); sounds[sndPi06] = PHL_LoadSound("wav/pi06.wav"); sounds[sndPi07] = PHL_LoadSound("wav/pi07.wav"); sounds[sndPi08] = PHL_LoadSound("wav/pi08.wav"); sounds[sndPi09] = PHL_LoadSound("wav/pi09.wav"); sounds[sndPi10] = PHL_LoadSound("wav/pi10.wav"); sounds[sndPower01] = PHL_LoadSound("wav/power01.wav"); sounds[sndPower02] = PHL_LoadSound("wav/power02.wav"); sounds[sndShot01] = PHL_LoadSound("wav/shot01.wav"); sounds[sndShot02] = PHL_LoadSound("wav/shot02.wav"); sounds[sndShot03] = PHL_LoadSound("wav/shot03.wav"); sounds[sndShot04] = PHL_LoadSound("wav/shot04.wav"); sounds[sndShot05] = PHL_LoadSound("wav/shot05.wav"); sounds[sndShot06] = PHL_LoadSound("wav/shot06.wav"); sounds[sndShot07] = PHL_LoadSound("wav/shot07.wav"); sounds[sndStep01] = PHL_LoadSound("wav/step01.wav"); sounds[sndWater01] = PHL_LoadSound("wav/water01.wav"); sounds[sndWolf01] = PHL_LoadSound("wav/wolf01.wav"); //Load Music bgmSecret = PHL_LoadMusic("midi/nazo", 0); bgmGameover = PHL_LoadMusic("midi/gameover", 0); } void freeResources() { //Free sounds int i; for (i = 0; i < NumOfSounds; i++) { PHL_FreeSound(sounds[i]); } //Free Music PHL_FreeMusic(bgmMusic); PHL_FreeMusic(bgmGameover); PHL_FreeMusic(bgmSecret); //Free graphics for (i = 0; i < NumOfImages; i++) { PHL_FreeSurface(images[i]); } } void gameSetup() { //Reset Flags { quakeTimer = 0; secretTimer = 0; roomDarkness = 0; bellFlag = 0; bossFlag = 0; bossDefeatedFlag = 0; int i; for (i = 0; i < 60; i++) { flags[i] = 0; } } //Save Data { playTime = 0; //Inventory int i; for (i = 0; i < 5; i++) { hasWeapon[i] = 0; } for (i = 0; i < 28; i++) { hasItem[i] = 0; } for (i = 0; i< 8; i++) { hasKey[i] = 0; } } //Room Data { roomSecret = 0; level = 0; screenX = 5; screenY = 2; } //Hero Setup { heroSetup(); drawhp = herohp; } //Reset object arrays freeArrays(); //Setup screen transition cutInTimer = 240; } int gameStep() { //Manage Timers { playTime += 1; secretCountdown(); if (quakeTimer > 0) { quakeTimer -= 1; } if (cutInTimer > 0) { cutInTimer -= 5; //Play music when the transition ends if (cutInTimer <= 0 && bossDefeatedFlag == 0 && bossFlag == 0) { PHL_PlayMusic(bgmMusic); } } } //Hero step { //End game if hero died if (heroStep() == 1) { return 0; } } //Menu button presses { if (getHeroState() <= 5 && cutInTimer <= 0) { if (btnSelect.pressed == 1) { int optionsResult = options(); //Reset Game if (optionsResult == 1) { return 0; } //Exit Game if (optionsResult == 3) { PHL_GameQuit(); return 1; } }else if (btnStart.pressed == 1) { inventory(); } } } //Objects steps { int i; for (i = 0; i < MAX_PLATFORMS; i++) { if (platforms[i] != NULL) { platformStep(platforms[i]); } } for (i = 0; i < MAX_OBJECTS; i++) { if (objects[i] != NULL) { objects[i]->objectStep(objects[i]->data); } } for (i = 0; i < MAX_WEAPONS; i++) { if (weapons[i] != NULL) { weaponStep(weapons[i]); } } for (i = 0; i < MAX_EFFECTS; i++) { if (effects[i] != NULL) { effectStep(effects[i]); } } for (i = 0; i < MAX_ENEMIES; i++) { if (enemies[i] != NULL) { enemies[i]->enemyStep(enemies[i]->data); } } } if (forceGameExit == 1) { forceGameExit = 0; return 0; } return -1; } void gameDraw(char doDrawHud) { PHL_DrawBackground(background, foreground); int i; //Draw water/lava top effects for (i = 0; i < MAX_EFFECTS; i++) { if (effects[i] != NULL) { if (effects[i]->depth == -1) { effectDraw(effects[i]); } } } for (i = 0; i < MAX_PLATFORMS; i++) { if (platforms[i] != NULL) { platformDraw(platforms[i]); } } for (i = 0; i < MAX_OBJECTS; i++) { if (objects[i] != NULL) { objects[i]->objectDraw(objects[i]->data); } } for (i = 0; i < MAX_WEAPONS; i++) { if (weapons[i] != NULL) { weaponDraw(weapons[i]); } } //Draw effects under for (i = 0; i < MAX_EFFECTS; i++) { if (effects[i] != NULL) { if (effects[i]->depth == 0) { effectDraw(effects[i]); } } } //Draw enemies backwards, so bullets and such are underneath their spawners //for (i = MAX_ENEMIES - 1; i >= 0; i--) { for (i = 0; i < MAX_ENEMIES; i++) { if (enemies[i] != NULL) { enemies[i]->enemyDraw(enemies[i]->data); } } //Not Death, draw death later if (getHeroState() != 8) { heroDraw(); } //Draw effects over for (i = 0; i < MAX_EFFECTS; i++) { if (effects[i] != NULL) { if (effects[i]->depth == 1) { effectDraw(effects[i]); } } } //Draw Darkness if (roomDarkness == 1) { int cornerX = herox - 160, cornerY = heroy + 20 - 160; PHL_DrawSurfacePart(cornerX, cornerY, 320 * hasItem[18], 0, 320, 320, images[imgDark]); //Top darkness rectangle if (cornerY > 0) { PHL_DrawRect(0, 0, 640, cornerY, PHL_NewRGB(10, 0, 0)); } //Bottom darkness rectangle if (cornerY + 320 < 480) { PHL_DrawRect(0, cornerY + 320, 640, 480, PHL_NewRGB(10, 0, 0)); } //Left rectangle if (cornerX > 0) { PHL_DrawRect(0, cornerY, cornerX, 320, PHL_NewRGB(10, 0, 0)); } //Right rectangle if (cornerX + 320 < 640) { PHL_DrawRect(cornerX + 320, cornerY, 640 - cornerX + 320, 320, PHL_NewRGB(10, 0, 0)); } } //Draw death over darkness if (getHeroState() == 8) { heroDraw(); } if (doDrawHud == 1) { drawHud(); } //cut-in transition { if (cutInTimer > 0) { PHL_DrawRect(0, 0, 640, cutInTimer, PHL_NewRGB(0, 0, 0)); PHL_DrawRect(0, 240 + (240 - cutInTimer), 640, 480, PHL_NewRGB(0, 0, 0)); } } } void getItem(int itemNum) { setHeroState(6); setHeroImageIndex(0); char getItemTimer = 0; char loop = 1; while (PHL_MainLoop() && loop == 1) { secretCountdown(); //Get Item Step if (getItemTimer == 0) { setHeroImageIndex(getHeroImageIndex() + 0.3); if (getHeroImageIndex() > 3) { getItemTimer = 1; } }else if (getItemTimer == 1) { //Wait for input PHL_ScanInput(); if (btnAccept.pressed == 1 || btnFaceDown.pressed == 1 || btnFaceRight.pressed == 1 || btnFaceUp.pressed == 1 || btnFaceLeft.pressed == 1 || btnStart.pressed == 1) { getItemTimer = 2; } }else if (getItemTimer == 2) { setHeroImageIndex(getHeroImageIndex() + 0.3); if (getHeroImageIndex() >= 7) { loop = 0; setHeroState(0); setHeroImageIndex(0); } } //Get Item Draw { PHL_StartDrawing(); gameDraw(1); if (getHeroImageIndex() >= 3) { char tempDarkness = roomDarkness; roomDarkness = 0; PHL_DrawRect(140, 208, 360, 64, PHL_NewRGB(255, 255, 255)); PHL_DrawRect(142, 210, 356, 60, PHL_NewRGB(0, 20, 0)); PHL_DrawRect(148, 216, 48, 48, PHL_NewRGB(255, 255, 255)); PHL_DrawRect(152, 220, 40, 40, PHL_NewRGB(119, 166, 219)); //Image PHL_DrawSurfacePart(152, 220, itemGotX, itemGotY, 40, 40, images[imgItems]); //Text { int drawX = 196, drawY = 216; int twoLayers = 0; if (itemName[itemNum]->length + found->length + 2 > 17) { twoLayers = 1; drawY -= 8; } drawX = drawCharacter(17, 2, drawX, drawY); drawX = drawText(itemName[itemNum], drawX, drawY); drawX = drawCharacter(18, 2, drawX, drawY); if (twoLayers == 1) { drawX = 204; drawY += 24; } drawText(found, drawX, drawY); } roomDarkness = tempDarkness; } PHL_EndDrawing(); } } } void saveScreen() { PHL_PlaySound(sounds[sndPower02], CHN_SOUND); herohp = maxhp; setHeroHsp(0); int saveTimer = 60; char loop = 1; while (PHL_MainLoop() && loop == 1) { PHL_StartDrawing(); gameDraw(1); PHL_DrawRect(140, 208, 360, 64, PHL_NewRGB(255, 255, 255)); PHL_DrawRect(142, 210, 356, 60, PHL_NewRGB(0, 0, 255)); drawTextCentered(saving, 320, 216); saveTimer -= 1; if (saveTimer <= 0) { loop = 0; } PHL_EndDrawing(); } if (writeSave(savemap) == 1) { if (fileExists(savename)) { char fullPath[128]; strcpy(fullPath, ""); #ifdef _3DS strcat(fullPath, "sdmc:/3ds/appdata/HydraCastleLabyrinth/"); #endif strcat(fullPath, savename); remove(fullPath); } } } //Result screen and credits void gameEnding() { int timer = 0; char exitLoop = 0; //Result screen { PHL_StopMusic(); PHL_FreeMusic(bgmMusic); bgmMusic = PHL_LoadMusic("midi/allclear", 0); PHL_PlayMusic(bgmMusic); //Calculate completion percentage char treasureString[10]; { int itemCount = 0; int ALLITEMS = 41; int i; for (i = 0; i < 5; i++) { itemCount += hasWeapon[i]; } for (i = 0; i < 28; i++) { itemCount += hasItem[i]; } for (i = 0; i < 8; i++) { itemCount += hasKey[i]; } sprintf(treasureString, "%d%%", itemCount * 100 / ALLITEMS); } //Calculate time char timeString[9]; { int hours = playTime / 216000; int minutes = (playTime % 216000) / 3600; int seconds = ((playTime % 216000) % 3600) / 60; sprintf(timeString, "%02d:%02d:%02d", hours, minutes, seconds); } int transTimer = 0; while (PHL_MainLoop() && exitLoop == 0) { timer += 1; if (timer >= 500) { transTimer += 8; } if (transTimer >= 360) { exitLoop = 1; } //Animate Effects int i; for (i = 0; i < MAX_EFFECTS; i++) { if (effects[i] != NULL) { effectStep(effects[i]); } } PHL_StartDrawing(); gameDraw(0); PHL_DrawTextBoldCentered("--- ALL CLEAR! ---", 320, 64, YELLOW); PHL_DrawTextBoldCentered("TIME", 320, 128, YELLOW); PHL_DrawTextBoldCentered(timeString, 320, 144, WHITE); PHL_DrawTextBoldCentered("TREASURE", 320, 192, YELLOW); PHL_DrawTextBoldCentered(treasureString, 320, 208, WHITE); //transition if (transTimer > 0) { PHL_DrawRect(0, 0, 640, transTimer, PHL_NewRGB(0, 0, 0)); PHL_DrawRect(0, 240 + (240 - transTimer), 640, 480, PHL_NewRGB(0, 0, 0)); } PHL_EndDrawing(); } } //Credits { timer = 0; exitLoop = 0; PHL_StopMusic(); PHL_FreeMusic(bgmMusic); bgmMusic = PHL_LoadMusic("midi/ending", 0); PHL_PlayMusic(bgmMusic); int timer = 0; double viewY = 0; int maxViewY = 2200; double imageIndex = 0; while (PHL_MainLoop() && exitLoop == 0) { timer += 1; if (timer >= 2220) { exitLoop = 1; } viewY += 1; if (viewY >= maxViewY - 480) { viewY = maxViewY - 480; } imageIndex += 0.1; if (imageIndex >= 2) { imageIndex -= 2; } PHL_StartDrawing(); PHL_DrawRect(0, 0, 640, 480, PHL_NewRGB(0, 0, 0)); if (exitLoop == 0) { PHL_DrawTextBoldCentered("- STAFF -", 320, 480 - viewY, YELLOW); PHL_DrawTextBoldCentered("SPRITES", 320, 560 - viewY, YELLOW); PHL_DrawTextBoldCentered("BUSTER", 320, 576 - viewY, WHITE); PHL_DrawTextBoldCentered("PROGRAM", 320, 640 - viewY, YELLOW); PHL_DrawTextBoldCentered("BUSTER", 320, 656 - viewY, WHITE); PHL_DrawTextBoldCentered("MUSIC", 320, 720 - viewY, YELLOW); PHL_DrawTextBoldCentered("MATAJUUROU", 320, 736 - viewY, WHITE); PHL_DrawTextBoldCentered("TEST PLAYER", 320, 800 - viewY, YELLOW); PHL_DrawTextBoldCentered("ZAC", 320, 816 - viewY, WHITE); PHL_DrawTextBoldCentered("- SPECIAL THANKS -", 320, 912 - viewY, YELLOW); PHL_DrawTextBoldCentered("QUADRUPLE D", 320, 992 - viewY, YELLOW); PHL_DrawTextBoldCentered("SANDMAN", 320, 1008 - viewY, WHITE); PHL_DrawTextBoldCentered("KBGM", 320, 1072 - viewY, YELLOW); PHL_DrawTextBoldCentered("KR.SHIN", 320, 1088 - viewY, WHITE); PHL_DrawTextBoldCentered("KBGMPLAYER", 320, 1152 - viewY, YELLOW); PHL_DrawTextBoldCentered("NARUTO", 320, 1168 - viewY, WHITE); PHL_DrawTextBoldCentered("SOUND EFFECT", 320, 1232 - viewY, YELLOW); PHL_DrawTextBoldCentered("OSABISHIYUUKI", 320, 1248 - viewY, WHITE); PHL_DrawTextBoldCentered("EDGE", 320, 1312 - viewY, YELLOW); PHL_DrawTextBoldCentered("TAKABO", 320, 1328 - viewY, WHITE); PHL_DrawTextBoldCentered("THE END", 320, maxViewY - 284 - viewY, YELLOW); PHL_DrawSurfacePart(300, maxViewY - 256 - viewY, (int)imageIndex * 40, 280, 40, 80, images[imgHero]); } PHL_EndDrawing(); } } forceGameExit = 1; } //Black screen between screens void screenTransition() { char timer = 15; while (PHL_MainLoop() && timer > 0) { PHL_StartDrawing(); PHL_DrawRect(0, 0, 640, 480, PHL_NewRGB(0, 0, 0)); timer -= 1; PHL_EndDrawing(); } if (autoSave == 1) { writeSave(savename); } } void enterDoor() { //Is not leaving boss room prematurely bossFlag = 0; level = lastDoor->warplevel; screenX = lastDoor->warpcoords % 12; screenY = lastDoor->warpcoords / 12; herox = lastDoor->warpx; heroy = lastDoor->warpy; PHL_StopMusic(); PHL_FreeMusic(bgmMusic); if (level == 0) { //Free uncommon images PHL_FreeSurface(images[imgMisc2040]); PHL_FreeSurface(images[imgMisc6020]); PHL_FreeSurface(images[imgDark]); }else{ bgmMusic = PHL_LoadMusic("midi/start", 0); PHL_PlayMusic(bgmMusic); int timer = 125; while (PHL_MainLoop() && timer > 0) { timer -= 1; PHL_StartDrawing(); PHL_DrawRect(0, 0, 640, 480, PHL_NewRGB(0, 0, 0)); drawTextCentered(dungeon[level - 1], 320, 216); PHL_EndDrawing(); } PHL_StopMusic(); PHL_FreeMusic(bgmMusic); loadUncommonImages(); } //Reload tileset PHL_FreeSurface(images[imgTiles]); images[imgTiles] = PHL_LoadQDA(tilesetStrings[level]); bgmMusic = PHL_LoadMusic(musicStrings[level], 1); changeScreen(0, 0); PHL_PlayMusic(bgmMusic); } void loadScreen() { //Stop music if you leave a boss room early if (bossFlag == 1) { PHL_StopMusic(); PHL_FreeMusic(bgmMusic); bgmMusic = PHL_LoadMusic(musicStrings[level], 1); PHL_PlayMusic(bgmMusic); } bossDefeatedFlag = bossFlag = 0; roomDarkness = 0; screenTransition(); int fileNum = stage[level][(screenY * 12) + screenX]; //Cycle through this process twice. Once for the backgroud, and one for the foreground int cycle = 0; for (cycle = 0; cycle < 2; cycle++) { //Build file string char toChar[4]; sprintf(toChar, "%03d", fileNum); char dest[80]; strcpy(dest, ""); #ifdef _3DS strcat(dest, "romfs:/map/"); #elif defined(_SDL) strcat(dest, "data/map/"); #else strcat(dest, "romfs/map/"); #endif strcat(dest, toChar); //load background on first pass if (cycle == 0) { strcat(dest, "a"); } strcat(dest, ".map"); //Read file FILE* file; if ((file = fopen(dest, "rb"))) { char* memblock; int size; fseek(file, 0, SEEK_END); size = ftell(file); memblock = (char*)malloc(size); fseek(file, 0, SEEK_SET); fread(memblock, 1, size, file); fclose(file); //Load data int count = 162; //Level data starts 118 int xx, yy; int valx = 0, valy = 0; int raw; for (yy = 0; yy < 12; yy++) { for (xx = 0; xx < 16; xx++) { raw = (unsigned)memblock[count]; valx = raw & 0x0F; valy = raw & 0xF0; valy >>= 4; if (cycle == 0) { background.tileX[xx][yy] = valx; background.tileY[xx][yy] = valy; }else if (cycle == 1) { foreground.tileX[xx][yy] = valx; foreground.tileY[xx][yy] = valy; collisionTiles[xx][yy] = getTileType(valx, valy); //Breakable blocks if (valy == 11 && (valx == 0 || valx == 1 || valx == 2)) { int secret = 0; if (valx == 2) { secret = 1; } createDestroyable(xx * 40, yy * 40, secret); } //Lava if (valx == 2 && valy == 1) { createEffect(10, xx * 40, yy * 40); foreground.tileX[xx][yy] = 0; foreground.tileY[xx][yy] = 0; } //Water if (valx == 6 && valy == 1) { createEffect(11, xx * 40, yy * 40); foreground.tileX[xx][yy] = 0; foreground.tileY[xx][yy] = 0; } } count += 2; } count += 12; } free(memblock); }else{ PHL_ErrorScreen("Map file was not found"); } } PHL_UpdateBackground(background, foreground); //Load file //Build file string char toChar[4]; sprintf(toChar, "%03d", fileNum); char dest[30]; #ifdef _3DS strcpy(dest, "romfs:/obj/"); #elif defined(_SDL) strcpy(dest, "data/obj/"); #else strcpy(dest, "romfs/obj/"); #endif //Add a 0 if needed /* if (fileNum < 100) { strcat(dest, "0"); } */ strcat(dest, toChar); strcat(dest, ".dat"); FILE* file; if ((file = fopen(dest, "rb"))) { unsigned char* memblock; int size; fseek(file, 0, SEEK_END); size = ftell(file); memblock = (unsigned char*)malloc(size); fseek(file, 0, SEEK_SET); fread(memblock, 1, size, file); int count = 0; while (count < size) { int type = memblock[count]; if (type <= 10) { if (type == 0 || type == 9) { //Blue/Red Slime createSlime(memblock[count + 1] * 20, memblock[count + 2] * 20, memblock[count + 3], memblock[count + 4]); } else if (type == 1) { //Bat (grey/red) createBat(memblock[count + 1] * 20, memblock[count + 2] * 20, memblock[count + 3]); } else if (type == 2) { //Slug createSlug(memblock[count + 1] * 20, memblock[count + 2] * 20, memblock[count + 3]); } else if (type == 3) { //Knight createKnight(memblock[count + 1] * 20, memblock[count + 2] * 20, memblock[count + 3]); } else if (type == 4) { //Rhyno head createHead(0, memblock[count + 1] * 20, memblock[count + 2] * 20, memblock[count + 3], memblock[count+4], memblock[count+5]); } else if (type == 5) { //Dragon head createHead(2, memblock[count + 1] * 20, memblock[count + 2] * 20, memblock[count + 3], memblock[count+4], memblock[count+5]); } else if (type == 6) { //Goblin/medusa head createHead(1, memblock[count + 1] * 20, memblock[count + 2] * 20, memblock[count + 3], memblock[count+4], memblock[count+5]); } else if (type == 7) { //Demon head createHead(3, memblock[count + 1] * 20, memblock[count + 2] * 20, memblock[count + 3], memblock[count+4], memblock[count+5]); } else if (type == 10) { //Fireball head createHead(4, memblock[count+1] * 20, memblock[count+2] * 20, 1, memblock[count+3], memblock[count+4]); } } else if (type <= 20) { if (type == 11) { //Poison Gas createGas(memblock[count+1] * 20, memblock[count+2] * 20, memblock[count+3]); } else if (type == 12) { //Flying skull createSkull(memblock[count+1] * 20, memblock[count+2] * 20); } else if (type == 13) { //Fish createFish(memblock[count+1] * 20, memblock[count+2] * 20, memblock[count+3]); } else if (type == 14) { //Water Jumper createWaterJumper(memblock[count+1] * 20, memblock[count+2] * 20, memblock[count+3], memblock[count+4], memblock[count+5]); } else if (type == 15) { //Podoboo createPodoboo(memblock[count+1] * 20, memblock[count+2] * 20, memblock[count+3], memblock[count+4]); } else if (type == 16) { //Thwomp createThwomp(memblock[count+1] * 20, memblock[count+2] * 20, memblock[count+3], memblock[count+4], memblock[count+5], memblock[count+6]); } else if (type == 17) { //Skeleton createSkeleton(memblock[count+1] * 20, memblock[count+2] * 20, memblock[count+3]); } else if (type == 18) { //Ghoul createGhoul(memblock[count+1]*20, memblock[count+2]*20, memblock[count+3]); } else if (type == 19) { //Seal createSeal(memblock[count+1]*20, memblock[count+2]*20); } else if (type == 20) { //Jellyfish createJellyfish(memblock[count+1]*20, memblock[count+2]*20); } } else if (type <= 30) { if (type == 21) { //Wizard createWizard(memblock[count+1]*20, memblock[count+2]*20); } else if (type == 22) { //Pendulum createPendulum(memblock[count+1]*20, memblock[count+2]*20, memblock[count+3]); } else if (type == 24) { //Bee createBee(memblock[count+1]*20, memblock[count+2]*20, memblock[count+3]); } else if (type == 25) { //Air Jar //createJar(memblock[count+1]*20, memblock[count+2]*20, memblock[count+3], memblock[count+4]); createHead(5, memblock[count + 1] * 20, memblock[count + 2] * 20, 0, memblock[count+3], memblock[count+4]); } else if (type == 26) { //Boar createBoar(memblock[count+1]*20, memblock[count+2]*20); } else if (type == 27) { //Fire Wheel createFirewheel(memblock[count+1]*20, memblock[count+2]*20, memblock[count+3]); } else if (type == 28) { //Rock Golem createGolem(memblock[count+1]*20, memblock[count+2]*20, memblock[count+3]); } else if (type == 29) { //Poison Knight createPoisonknight(memblock[count+1]*20, memblock[count+2]*20); } else if (type == 30) { //Electricity doggy createDog(memblock[count+1]*20, memblock[count+2]*20); } } else if (type < 40) { if (type == 31) { createBoomknight(memblock[count+1]*20, memblock[count+2]*20); } else if (type == 32) { createPumpkinenemy(memblock[count+1]*20, memblock[count+2]*20); } } else if (type < 50) { //Bosses if (type == 40) { createDodo(memblock[count+1] * 20, memblock[count+2] * 20, memblock[count+3]); } else if (type == 41) { createBatboss(memblock[count+1] * 20, memblock[count+2] * 20); } else if (type == 42) { createCrab(memblock[count+1] * 20, memblock[count+2] * 20); } else if (type == 43) { createGyra(memblock[count+1] * 20, memblock[count+2] * 20); } else if (type == 44) { createLolidra(memblock[count+1] * 20, memblock[count+2] * 20); } else if (type == 45) { createDevil(memblock[count+1] * 20, memblock[count+2] * 20); } else if (type == 46) { createGarm(memblock[count+1] * 20, memblock[count+2] * 20); } else if (type == 47) { createHydra(memblock[count+1] * 20); } } else if (type <= 60) { //Objects if (type == 50) { //Moving platforms createPlatform(0, memblock[count + 1] * 20, memblock[count + 2] * 20, memblock[count + 3] * 20, memblock[count + 4] * 20, memblock[count + 5], memblock[count+6]); } else if (type == 51) { //Loose block createPlatform(1, memblock[count + 1] * 20, memblock[count + 2] * 20, 0, 0, 0, memblock[count+3]); } else if (type == 52) { //Locked Block createLockBlock(memblock[count+1] * 20, memblock[count+2] * 20, memblock[count+3]); } else if (type == 53) { //Gate createGate(memblock[count+1]*20, memblock[count+2]*20, memblock[count+3]); } else if (type == 54) { //Statue createStatue(memblock[count+1]*20, memblock[count+2]*20, memblock[count+3]); } else if (type == 55) { //Megaman block createPlatform(2, memblock[count + 1] * 20, memblock[count + 2] * 20, memblock[count + 3], memblock[count + 4], 0, 0); } else if (type == 56) { //Electric gate createShockgate(memblock[count + 1] * 20, memblock[count + 2] * 20, memblock[count + 3]); } else if (type == 57) { //Hydra platform createPlatform(3, memblock[count + 1] * 20, memblock[count + 2] * 20, 0, 0, 0, 0); } } else if (type < 70) { } else/* if (type <= 80)*/ { if (type == 70) { //Breakable Block createDestroyable(memblock[count+1] * 20, memblock[count+2] * 20, 1); } else if (type == 71) { //Secret Trigger createSecretTrigger(memblock[count+1], memblock[count+2], memblock[count+3]); } else if (type == 73) { //Chests createChest(memblock[count + 1] * 20, memblock[count + 2] * 20, memblock[count + 3], memblock[count + 4]); } else if (type == 74) { //Save Points createSavePoint(memblock[count+1] * 20, memblock[count+2] * 20, memblock[count+3]); } else if (type == 75) { //door createDoor(memblock[count+1] * 20, memblock[count+2] * 20, memblock[count+3], memblock[count+4], memblock[count+5] * 20, memblock[count+6] * 20, memblock[count+7]); } else if (type == 76) { //Light Switch createSwitch(memblock[count+1] * 20, memblock[count+2] * 20, memblock[count+3]); } else if (type == 77) { //Floor Button createFloorPad(memblock[count+1]*20, memblock[count+2]*20, memblock[count+3]); } else if (type == 78) { roomDarkness = 1; } else if (type == 79) { //Ladder Spawner createLadder(memblock[count+1] * 20, memblock[count+2] * 20, memblock[count+3]); } else if (type == 80) { //Generator createGenerator(memblock[count+1] * 20, memblock[count+2] * 20, memblock[count+3]); } else if (type == 81) { //Crown createCrown(memblock[count+1] * 20, memblock[count+2] * 20); } } count += 16; } free(memblock); fclose(file); } } void drawHud() { //Repress certain screen altering variables int tempDark = roomDarkness; roomDarkness = 0; int tempQuake = quakeTimer; quakeTimer = 0; //Change HUD position int drawy = 8; { if (heroy <= 100) { drawy = 400; } } //Move scrolling health bar { if (drawhp > herohp) { drawhp -= 1; } if (drawhp < herohp) { drawhp += 1; } } //Main image { PHL_DrawSurfacePart(8, drawy, 0, 0, 368, 64, images[imgHud]); } //Health bar { PHL_RGB hpbarc = PHL_NewRGB(128, 255, 0); if (getHeroPoisoned() > 0) { hpbarc = PHL_NewRGB(255, 128, 255); } PHL_DrawRect(76, drawy + 8, maxhp * 2, 6, PHL_NewRGB(255, 0, 0)); PHL_DrawRect(76, drawy + 8, drawhp * 2, 6, hpbarc); } //Ammo counter { char c[10]; sprintf(c, "%02d", heroAmmo); PHL_DrawTextBold(c, 74, drawy + 36, WHITE); } //Draw weapon icon { int wx = 32 * (heroWeapon + 1); if (hasWeapon[heroWeapon] == 0) { wx = 0; } PHL_DrawSurfacePart(24, drawy + 16, wx, 64, 32, 32, images[imgHud]); } //Restore screen altering variables { quakeTimer = tempQuake; roomDarkness = tempDark; } } void freeArrays() { int i; for (i = 0; i < MAX_EFFECTS; i++) { effectDestroy(i); } for (i = 0; i < MAX_OBJECTS; i++) { objectDestroy(i); } for (i = 0; i < MAX_ENEMIES; i++) { enemyDestroy(i); } for (i = 0; i < MAX_WEAPONS; i++) { weaponDestroy(i); } for (i = 0; i < MAX_PLATFORMS; i++) { platformDestroy(i); } } void changeScreen(int dx, int dy) { roomSecret = 0; freeArrays(); screenX += dx; screenY += dy; loadScreen(); writeSave(savename); } int getTileType(int valx, int valy) { int result = 0; if (valy == 11 && valx == 8) { result = 3; //Ladder Top }else if (valy == 1 && valx == 1) { result = 5; //Lava }else if (valy > 7) { result = 1; //Solid }else //specifics if (valy == 0 && (valx == 3 || valx == 5)) { result = 2; //Ladders }else if (valy == 1 && valx == 5) { result = 4; //Water }else if (valx == 0 && (valy == 1 || valy == 2)) { result = 6; //Spikes }else if (valy == 11 && (valx == 0 || valx == 1 || valx == 2)) { result = 1; //Breakable solid block } if (level == 4 && valy == 3 && (valx == 0 || valx == 1 || valx == 2)) { result = 6; //Spikes } return result; } //Save file load/save int writeSave(char* fname) { int result = 0; //mkdir("data"); FILE* f; char fullPath[4096]; strcpy(fullPath, ""); #ifdef _3DS strcat(fullPath, "sdmc:/3ds/appdata/HydraCastleLabyrinth/"); #endif #ifdef DREAMCAST strcpy(fullPath, "/ram/"); #endif strcat(fullPath, fname); if ( (f = fopen(fullPath, "wb")) ) { int size = 4548; unsigned char* memblock = (unsigned char*)malloc(size); memset(memblock, 0, size); memblock[0x0] = herohp; memblock[0x4] = maxhp; memblock[0x8] = heroAmmo; memblock[0x0C] = maxAmmo; if (heroWeapon == -1) { memblock[0x10] = 0; }else{ memblock[0x10] = heroWeapon; } memblock[0x14] = 1; //Unknown, but always resets to 1 int i; for (i = 0; i < 60; i++) { memblock[(0x3FC) + i] = flags[i]; } for (i = 0; i < 5; i++) { memblock[(0x7E4) + i] = hasWeapon[i]; } int itemorder[28] = { 0x7F6, 0x7FA, 0x7F9, 0x7F8, 0x7F1, 0x7F3, 0x7F2, 0x7FB, 0x7ED, 0x7EF, 0x7EE, 0x7F0, 0x7EC, 0x7F4, 0x7F7, 0x7F5, 0x7EA, 0x7EB, 0x7FF, 0x803, 0x804, 0x7FE, 0x802, 0x805, 0x800, 0x7FD, 0x7FC, 0x801 }; for (i = 0; i < 28; i++) { memblock[itemorder[i]] = hasItem[i]; } for (i = 0; i < 8; i++) { memblock[(0x806) + i] = hasKey[i]; } int writeHerox = herox; int writeHeroy = heroy; memcpy(&memblock[0x11B0], &writeHerox, 4); memcpy(&memblock[0x11B4], &writeHeroy, 4); if (getHeroDirection() == 1) { memblock[0x11C0] = 0; }else{ memblock[0x11C0] = 1; } memblock[0x11B8] = level; //Screen memblock[0x11BC] = (screenX) + (screenY * 12); //Time memcpy(&memblock[0x11AC], &playTime, 4); fwrite(memblock, 1, size, f); free(memblock); result = 1; fclose(f); } #ifdef DREAMCAST DC_SaveVMU(); #endif return result; } void loadSave(char* fname) { FILE* f; #ifdef DREAMCAST DC_LoadVMU(); #endif char fullPath[128]; strcpy(fullPath, ""); #ifdef _3DS strcat(fullPath, "sdmc:/3ds/appdata/HydraCastleLabyrinth/"); #endif #ifdef DREAMCAST strcat(fullPath, "/ram/"); #endif strcat(fullPath, fname); if ((f = fopen(fullPath, "rb"))) { //Reminder: read order matters unsigned long loadTemp = 0; //Hero HP fread(&loadTemp, 4, 1, f); herohp = loadTemp; drawhp = herohp; //Max HP fread(&loadTemp, 4, 1, f); maxhp = loadTemp; //Ammo fread(&loadTemp, 4, 1, f); heroAmmo = loadTemp; //Max Ammo fread(&loadTemp, 4, 1, f); maxAmmo = loadTemp; int loadedWeapon = 0; fread(&loadedWeapon, 1, 1, f); //Read Flags fseek(f, 0x3FC, SEEK_SET); int i; for (i = 0; i < 60; i++) { fread(&flags[i], 1, 1, f); } //Read weapons fseek(f, 0x7E4, SEEK_SET); for (i = 0; i < 5; i++) { fread(&hasWeapon[i], 1, 1, f); } heroWeapon = -1; if (hasWeapon[loadedWeapon] == 1) { heroWeapon = loadedWeapon; } //Read items int itemorder[28] = { 16, 17, 12, 8, 10, 9, 11, 4, 6, 5, 13, 15, 0, 14, 3, 2, 1, 7, 26, 25, 21, 18, 24, 27, 22, 19, 20, 23 }; fseek(f, 0x7EA, SEEK_SET); for (i = 0; i < 28; i++) { fread(&hasItem[itemorder[i]], 1, 1, f); } //Read keys for (i = 0; i < 8; i++) { fread(&hasKey[i], 1, 1, f); } fseek(f, 0x11AC, SEEK_SET); fread(&playTime, 4, 1, f); //fseek(f, 4540, SEEK_SET); //Hero X and Y fread(&loadTemp, 4, 1, f); herox = loadTemp; fread(&loadTemp, 4, 1, f); heroy = loadTemp; //Level fread(&loadTemp, 4, 1, f); level = loadTemp; //Screen coords fread(&loadTemp, 4, 1, f); screenX = (loadTemp) % 12; screenY = ((int)(loadTemp) / 12); //Direction fread(&loadTemp, 4, 1, f); if (loadTemp == 0) { setHeroDirection(1); }else{ setHeroDirection(-1); } fclose(f); } } int fileExists(char* fpath) { int result = 0; char fullPath[128]; strcpy(fullPath, ""); #ifdef _3DS strcat(fullPath, "sdmc:/3ds/appdata/HydraCastleLabyrinth/"); #endif strcat(fullPath, fpath); FILE* f; if ( (f = fopen(fullPath, "rb")) ) { result = 1; fclose(f); } return result; } void playSecret() { PHL_StopMusic(); secretTimer = 210; } void secretCountdown() { if (secretTimer > 0) { secretTimer -= 1; if (secretTimer <= 0) { PHL_StopMusic(); if (bossFlag == 0 && bossDefeatedFlag == 0) { PHL_PlayMusic(bgmMusic); } }else if (secretTimer == 180) { PHL_PlayMusic(bgmSecret); } } } int getDrawHP() { return drawhp; } void setDrawHP(int val) { drawhp = val; } int getLevel() { return level; } void setBossRoom() { bossFlag = 1; PHL_StopMusic(); secretTimer = 0; PHL_FreeMusic(bgmMusic); if (level != 8) { bgmMusic = PHL_LoadMusic("midi/boss", 1); }else{ bgmMusic = PHL_LoadMusic("midi/lastboss", 1); } PHL_PlayMusic(bgmMusic); } void setAutoSave(char val) { autoSave = val; } char getAutoSave() { return autoSave; } void loadUncommonImages() { //Seal Toungs if (level == 4) { images[imgMisc2040] = PHL_LoadQDA("chr20x40.BMP"); } //Darkness if (level == 5) { images[imgDark] = PHL_LoadQDA("dark.bmp"); } //Dragon Flame if (level == 7 || level == 8) { images[imgMisc6020] = PHL_LoadQDA("chr60x20.bmp"); } } #ifdef DREAMCAST int DC_LoadVMU(void) { unsigned long unzipsize; uint8* unzipdata; vmu_pkg_t pkg; // Name of the file to open file_t fd; if ((fd = fs_open("/vmu/a1/hydracas", O_RDONLY)) == -1) { printf("error opening VMU A1, not found.\n"); return -1; } // Remove VMU header vmu_pkg_parse(fs_mmap(fd), &pkg); // Allocate memory for the uncompressed data unzipdata = (uint8 *)malloc(524288); //512KB unzipsize = 524288; uncompress(unzipdata, &unzipsize, (uint8 *)pkg.data, pkg.data_len); // Save buffer into a RAM file fs_close(fd); file_t fd2; if ((fd2 = fs_open("/ram/save.map", O_WRONLY)) == -1) { printf("Can't create RAM file from VMU.\n"); return -1; } fs_write(fd2, unzipdata, unzipsize); fs_close(fd2); // Free unused memory free(unzipdata); return 0; } int DC_SaveVMU(void) { vmu_pkg_t pkg; uint8 *pkg_out; int pkg_size; file_t ft; // Temporal for reading the file file_t file; int data_size; unsigned long zipsize = 0; uint8 *datasave; uint8 *zipdata; // Open file and copy to buffer file = fs_open("/ram/save.map", O_RDONLY); data_size = fs_total(file); datasave = (uint8 *)malloc(data_size+1); fs_read(file, datasave, data_size); fs_close(file); // Allocate some memory for compression zipsize = data_size * 2; zipdata = (uint8*)malloc(zipsize); // The compressed save compress(zipdata, &zipsize, datasave, data_size); // Make the package to the VMU. strcpy(pkg.desc_short, "hydra"); strcpy(pkg.desc_long, "Hydra Castle Labyrinth"); strcpy(pkg.app_id, "hydracas"); pkg.icon_cnt = 1; memcpy((void *)&pkg.icon_pal[0],(void *)&vmu_savestate_pal,32); pkg.icon_data = (const uint8*)&vmu_savestate_data; pkg.icon_anim_speed = 0; pkg.eyecatch_type = VMUPKG_EC_NONE; pkg.data_len = zipsize; pkg.data = zipdata; vmu_pkg_build(&pkg, &pkg_out, &pkg_size); // Write at A1 port fs_unlink("/vmu/a1/hydracas"); ft = fs_open("/vmu/a1/hydracas", O_WRONLY); if (!ft) { return -1; } fs_write(ft, pkg_out, pkg_size); fs_close(ft); // Free unused memory free(pkg_out); free(datasave); free(zipdata); return 0; } #endif