From f43a3c1130c423ccb859b903ee13381098277eba Mon Sep 17 00:00:00 2001 From: cuckydev Date: Sat, 19 Jan 2019 21:23:04 -0500 Subject: [PATCH] Org and sound --- Makefile | 9 + build/data/Title.pbm | Bin 7806 -> 16446 bytes build/data/WAVE100.bin | Bin 0 -> 25600 bytes build/data/stage.tbl | Bin 21756 -> 18997 bytes src/Back.cpp | 33 +++ src/Back.h | 16 ++ src/Draw.cpp | 18 +- src/Ending.cpp | 1 + src/Escape.cpp | 39 +++ src/Escape.h | 2 + src/Frame.cpp | 0 src/Frame.h | 0 src/Game.cpp | 425 +++++++++++++++++++++++++-- src/Generic.cpp | 9 + src/Generic.h | 1 + src/Main.cpp | 20 +- src/Map.cpp | 254 +++++++++++++++++ src/Map.h | 14 + src/MapName.cpp | 73 +++++ src/MapName.h | 12 + src/NpChar.cpp | 12 + src/NpChar.h | 43 +++ src/NpcTbl.cpp | 9 +- src/NpcTbl.h | 1 + src/Organya.cpp | 632 +++++++++++++++++++++++++++++++++++++++++ src/Organya.h | 51 ++++ src/PixTone.cpp | 288 +++++++++++++++++++ src/PixTone.h | 5 + src/Profile.cpp | 24 ++ src/Profile.h | 4 + src/Sound.cpp | 324 +++++++++++++++++++++ src/Sound.h | 96 +++++++ src/Stage.cpp | 229 +++++++++++++++ src/Stage.h | 19 ++ src/TextScr.cpp | 41 +++ src/TextScr.h | 1 + 36 files changed, 2664 insertions(+), 41 deletions(-) create mode 100644 build/data/WAVE100.bin create mode 100644 src/Back.cpp create mode 100644 src/Back.h create mode 100644 src/Escape.cpp create mode 100644 src/Escape.h create mode 100644 src/Frame.cpp create mode 100644 src/Frame.h create mode 100644 src/MapName.cpp create mode 100644 src/MapName.h create mode 100644 src/NpChar.cpp create mode 100644 src/NpChar.h create mode 100644 src/Organya.cpp create mode 100644 src/Organya.h create mode 100644 src/PixTone.cpp create mode 100644 src/PixTone.h create mode 100644 src/Profile.cpp create mode 100644 src/Profile.h create mode 100644 src/Sound.cpp create mode 100644 src/Sound.h create mode 100644 src/Stage.cpp create mode 100644 src/Stage.h diff --git a/Makefile b/Makefile index cc5ee19e..6995a10d 100644 --- a/Makefile +++ b/Makefile @@ -20,9 +20,11 @@ LIBS += `sdl2-config --static-libs` -lSDL2_ttf -lfreetype -lharfbuzz -lfreetype # For an accurate result to the original's code, compile in alphabetical order SOURCES = \ + Back \ Config \ Draw \ Ending \ + Escape \ Flags \ Game \ Generic \ @@ -31,7 +33,14 @@ SOURCES = \ KeyControl \ Main \ Map \ + MapName \ + NpChar \ NpcTbl \ + Organya \ + PixTone \ + Profile \ + Sound \ + Stage \ TextScr \ Triangle \ diff --git a/build/data/Title.pbm b/build/data/Title.pbm index 218b9fb1547afe61968e012c4b9146ddf4ed2716..f69181a9eec7bc58d275bc485a67bb949a39e638 100644 GIT binary patch literal 16446 zcmeHMOLE&r5G7S!5?-V#2gvzyoLs<5r{8=18(;vD3Z;Y;ri7XP zyzc3K7?2Y5^RJ)3oH#yzIGsM4^yPdyeX{j@`auqx|N2pv8R5YA{`a?U-!UK`*TKPY z2Hw>fu-k3peAcId7L%!laRQ+Ufqq#An3j>F5r}{kk{G(~ck*s>VNb4!OK&~ek5&Qn zYkTp#1Aw8Wnc_OFcRqPHv1Dfyq@i_Psh25eJ?k7AqG4StzUcGA?bgTQPfd+|FP>0u z*a#!ou|^8X3I0gZm?w~reEy>S7BCb8gbj?1{1NsZ_#+AEeL_Zje08FdKNAqL zIGsx8#_(kx;TdK=t*{;AVBlcjVBlcjVBlcjVBlcjVBlcjVBlcj5(b`5C;PGSMCr+g zOtQl-C#`)#kdG2miezmK^uw$qhTSAZ;Do${533DMbUGmjOR~Bc#ztHV;cjm^v1TvU zdqF!Ks4HrbM09u+B}_v`gsn!4G{zAh-muuppU@eVAXqh)m4MRa2<%&~RX3YuFWxna zhk*i(bW06Ai*on5aQS-_6WDTT4`|MHR>z1^gfQQ-5fQjjBiQP*&LmV4IpE zfY=sLy7O1;_zp+~4uV1jgAB#`BC|}G%N$Y!2s3IKXRovHMvD_(ib3H!t{c7OvSN5L zP@iP4R8{tqA%r>!IqU2VmeDyvE)c{)ZxDz)HY#F~r+G>YX%QFZo=oo&{f%N@ZupiE zO?so~)3?`3dofBQCc6XxT78u683-c~u5e3^J>4p1r38>!nyKt5EeNcAOY)bhFz82%PLguPRuvN8s*Vuwa4@rQ8RHKwQR@GubAi0L@x?Sat6m5+< zn~7p&UwWuJe{0{SV-4N2Sj}j_hEUZ*NiCknC4bAvhQFmaEePfBZL&$zreiPLoBDKH zUS%Ho*e7s+9?FD)e0Cg?fdV_cdQy-7)^Ax;G0{yAWMM6A_weEhp1^btPp1%+G zgb0HCYdBRGQjc%x-QNDo1E_}u<@GAoH&hn%g^2#J?Y6ezEPg~_>9vnS%d?Tn%)Rn$ z)T?+#qC(?Jo^n$&$%;k4!8j@*mkTRWn2Pa|R)GE7+XU*@6r1(t3V*)o+D~|?x9V1e zSD)e42RypSYp8bb6MVU_6C+n--2wL9p5YHK009r~sPy<3%d7fe7>uFt$eH3gNTe8@ zUQ@zOjJpC6yFZgXidn-%ne%6ENTsdu*IJeZn!YemC0S14SZs89&BmKCeow3h6|o6i z>^7Fvoynj7&3kM9qSDw?pKPIFbvmsTlfsRHZNTmR9`c;L5#t#V&FoEIWgK_iMjC(o z0goZw^8B$>R;Q+dpeooaC0FE6#hOmf1{W1Sk>)X-1V_w)$T)Zq>18f=6IaeyDEcH^ zLSLwZ2yO0F42nn+Z$4`ughARWe6N~W%t%2XRLd+^_aL_G4WE?h`&WDwnjTUC+7DX|27gE=aou^<8 zKFtt!VXIEBDmTNde+z6X)1;QP_@kME eJMZ3A(~1{Jdu?e{;w{_zjn%@&^k literal 7806 zcmeI0J&xQ)5QSR+bKbzQocRa^nQ$P$fG**{fKv$ubSTG4eH=%VDI9*_q+& zE&&^u(y)JvtdFmM*sBk}e)*xig&I3ME8O*ikq>CtVS7K zg(4qn6GZfp*@xoJR(wPPL9vN^%7?Oac31hR2C3c2cC_LXTk`eMR?LVnO3xCr_?+)Z zmX9tzqIJHIf+X0q5)S;?r)wPY+SN2n8m;6TCKkjr^TE7aJh)0+`6#2t^{|Hm4+S0y zJQR2+@PAf-uiAgv^of2e8{630acrEC53P+#+IXOm#9g$wQ33V2*KZQR#0P(Ji@y8= zr`9Rl9@RL>N9TrDnEA%B9r!hVkcx|%`GChV1wv=%{24_usp@R*q9D)y@0EN46V0f< zF;wiFB89h;NmZ=i1`bOZziTGU1)nv>W7cnRxSCMk{m85ryJd%QWOzxO8kN8m2(l0 zpqw+0xLH=}b3c!cicVqX+oB&tFtI$e5RM0pXlf@=L2D*1_#CG{c=3Gko!FvRLUs%D z@e1fSH&*8}c^_YTD5+mG$)=oX3ET$0^I)s!b0w0GbQ516PU&~-auuOQJAr4unnrUp z_1ki~Rc)1rYnck}?(scp(g`&8K&@JqGn!@kq@M%5Fj?^R{ZZ5RwrNmV!ZL3y?AAu} zyj$tV&hSDLTS=~RS+!ODxm-J+{(Hq!tj{y5kg+bzSDnw@y}hkiVsT5gEt+0eL_a-X z@Xk@1uoUa5%)+cF&0@c0)~{Um$Q2bpKk}6?YH;Zt@H+)m2s&&UQ>J4$lv5V2U;{iWNTNil_5+ zk8;>{7|5rrQtxr2R`9%9RTx><2kkUE2c{LD!GgAPK06{9zf(TF%S)_>R|br>K7mps z@uzO)BWPJ)ni{`FYxZhF@;l+1q`HhWav5>+ZL1wllF8e0>082{eVH$#LlJ!Fu~-CB z<$sI2E)|Op#Zo9WNIT{0@g-;)FD`X-DN>fQ3$)Hh7ad%_O`@tnX@p9o z%5GW>UmcY_$_%aa)6Gxw&w?Ed9JrsyzqFF}yq! z)`diJM>cp)!mg2~45n3eRdC{y@ClqZUQQ2EC=Y)cQt4*njy2zw$0h5q5cD*#_#ofR zr*)7fp*-nGblSSG|6RpQjTTbZ!{;3Im@69!@G-Q~a3*E$^|D%pofginXp?i47r62c zJS3mvhuu!hmk=|F`Ofs~s=Si#Hqm_^3;nztug$F#?&=HN7yM3dMa~s)=|*1R`U_mT f@on0*v0j;51o6^*n_zc6<^9h;e)|2--~RX)P#bp| diff --git a/build/data/WAVE100.bin b/build/data/WAVE100.bin new file mode 100644 index 0000000000000000000000000000000000000000..86f1faff9d37b706a60f935fa758525f874fcefc GIT binary patch literal 25600 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 aE-NiIH8wU`jaV}^4s+1dsB;wvUH3oAivUgl literal 0 HcmV?d00001 diff --git a/build/data/stage.tbl b/build/data/stage.tbl index a121901c49655aaff7f3249f6ca81467969e7a31..34d510780effcfc7b6e3a71e33181787313e47df 100644 GIT binary patch delta 1943 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 +#include "WindowsWrapper.h" + +#include "Tags.h" +#include "Back.h" +#include "Draw.h" + +BACK gBack; +int gWaterY; + +bool InitBack(char *fName, int type) +{ + //Get width and height + char path[PATH_LENGTH]; + sprintf(path, "%s/%s.pbm", gDataPath, fName); + + SDL_Surface *temp = SDL_LoadBMP(path); + if (!temp) + return false; + + gBack.partsW = temp->w; + gBack.partsH = temp->h; + + SDL_FreeSurface(temp); + + //Set background stuff and load texture + gBack.flag = 1; + if (!ReloadBitmap_File(fName, 28)) + return false; + gBack.type = type; + gWaterY = 0x1E0000; + return true; +} diff --git a/src/Back.h b/src/Back.h new file mode 100644 index 00000000..1f02abf3 --- /dev/null +++ b/src/Back.h @@ -0,0 +1,16 @@ +#pragma once + +struct BACK +{ + int flag; + int partsW; + int partsH; + int numX; + int numY; + int type; + int fx; +}; + +extern int gWaterY; + +bool InitBack(char *fName, int type); diff --git a/src/Draw.cpp b/src/Draw.cpp index d80e2317..fe36f003 100644 --- a/src/Draw.cpp +++ b/src/Draw.cpp @@ -104,7 +104,7 @@ bool MakeSurface(const char *name, int surf_no) } //Make sure surface has color key on - SDL_SetColorKey(surface, SDL_TRUE, 0x000000); + SDL_SetColorKey(surface, SDL_TRUE, SDL_MapRGB(surface->format, 0, 0, 0)); //Get texture from surface SDL_Texture *texture = SDL_CreateTextureFromSurface(gRenderer, surface); @@ -136,7 +136,8 @@ bool MakeSurface(const char *name, int surf_no) surf[surf_no].texture = textureAccessible; surf[surf_no].scale = true; - //Free surface + //Free surface and texture + SDL_DestroyTexture(texture); SDL_FreeSurface(surface); printf(" ^ Successfully loaded\n"); @@ -239,7 +240,7 @@ void PutBitmap3(RECT *rcView, int x, int y, RECT *rect, int surf_no) //Transpare //Draw to screen if (SDL_RenderCopy(gRenderer, surf[surf_no].texture, &frameRect, &destRect) < 0) - printf(SDL_GetError()); + printf("Failed to draw texture %d\nSDL Error: %s\n", surf_no, SDL_GetError()); //Undo cliprect SDL_RenderSetClipRect(gRenderer, NULL); @@ -272,7 +273,7 @@ void PutBitmap4(RECT *rcView, int x, int y, RECT *rect, int surf_no) //No Transp //Draw texture if (SDL_RenderCopy(gRenderer, surf[surf_no].texture, &frameRect, &destRect) < 0) - printf(SDL_GetError()); + printf("Failed to draw texture %d\nSDL Error: %s\n", surf_no, SDL_GetError()); //Restore original colour, and undo cliprect SDL_RenderSetClipRect(gRenderer, NULL); @@ -297,7 +298,7 @@ void Surface2Surface(int x, int y, RECT *rect, int to, int from) //Draw texture if (SDL_RenderCopy(gRenderer, surf[from].texture, &frameRect, &rcSet) < 0) - printf(SDL_GetError()); + printf("Failed to draw texture %d to %d\nSDL Error: %s\n", from, to, SDL_GetError()); //Stop targetting surface SDL_SetRenderTarget(gRenderer, NULL); @@ -329,8 +330,13 @@ void CortBox2(RECT *rect, uint32_t col, int surf_no) SDL_SetRenderTarget(gRenderer, surf[surf_no].texture); + const unsigned char col_red = col & 0xFF0000 >> 16; + const unsigned char col_green = col & 0x00FF00 >> 8; + const unsigned char col_blue = col & 0x0000FF; + const unsigned char col_alpha = (col_red || col_green || col_blue) ? 0xFF : 0; + //Set colour and draw - SDL_SetRenderDrawColor(gRenderer, col & 0xFF0000 >> 16, col & 0x00FF00 >> 8, col & 0x0000FF, 0xFF); + SDL_SetRenderDrawColor(gRenderer, col_red, col_green, col_blue, col_alpha); SDL_RenderFillRect(gRenderer, &destRect); //Stop targetting surface diff --git a/src/Ending.cpp b/src/Ending.cpp index 82ef1311..43906bc2 100644 --- a/src/Ending.cpp +++ b/src/Ending.cpp @@ -191,6 +191,7 @@ bool StartCreditScript() //Clear casts memset(Strip, 0, sizeof(Strip)); + SDL_RWclose(fp); return true; } diff --git a/src/Escape.cpp b/src/Escape.cpp new file mode 100644 index 00000000..15898878 --- /dev/null +++ b/src/Escape.cpp @@ -0,0 +1,39 @@ +#include "WindowsWrapper.h" +#include "Draw.h" +#include "KeyControl.h" + +int Call_Escape() +{ + RECT rc = {0, 128, 208, 144}; + + while (Flip_SystemTask()) + { + //Get pressed keys + GetTrg(); + + if (gKeyTrg & 0x8000) //Escape is pressed, quit game + { + gKeyTrg = 0; + return 0; + } + if (gKeyTrg & 0x400) //F1 is pressed, continue + { + gKeyTrg = 0; + return 1; + } + if (gKeyTrg & 0x800) //F2 is pressed, reset + { + gKeyTrg = 0; + return 2; + } + + //Draw screen + CortBox(&grcFull, 0x000000); + PutBitmap3(&grcFull, 56, 112, &rc, 26); + //PutFramePerSecound(); + } + + //Quit if window is closed + gKeyTrg = 0; + return 0; +} diff --git a/src/Escape.h b/src/Escape.h new file mode 100644 index 00000000..393ea8ce --- /dev/null +++ b/src/Escape.h @@ -0,0 +1,2 @@ +#pragma once +int Call_Escape(); diff --git a/src/Frame.cpp b/src/Frame.cpp new file mode 100644 index 00000000..e69de29b diff --git a/src/Frame.h b/src/Frame.h new file mode 100644 index 00000000..e69de29b diff --git a/src/Game.cpp b/src/Game.cpp index 5027ca75..d11cf718 100644 --- a/src/Game.cpp +++ b/src/Game.cpp @@ -1,65 +1,440 @@ #include #include +#include +#include "WindowsWrapper.h" + #include "Tags.h" #include "NpcTbl.h" +#include "Generic.h" #include "GenericLoad.h" #include "TextScr.h" #include "Flags.h" +#include "Escape.h" +#include "Stage.h" #include "Map.h" +#include "MapName.h" +#include "Sound.h" +#include "Profile.h" +#include "Back.h" +#include "KeyControl.h" #include "Draw.h" #include "Ending.h" int g_GameFlags; int gCounter; +bool bContinue; + int Random(int min, int max) { return min + rand() % (max - min + 1); } +void PutNumber4(int x, int y, int value, bool bZero) +{ + //Define rects + RECT rcClient = grcFull; + + RECT rect[10]; + rect[0] = {0, 56, 8, 64}; + rect[1] = {8, 56, 16, 64}; + rect[2] = {16, 56, 24, 64}; + rect[3] = {24, 56, 32, 64}; + rect[4] = {32, 56, 40, 64}; + rect[5] = {40, 56, 48, 64}; + rect[6] = {48, 56, 56, 64}; + rect[7] = {56, 56, 64, 64}; + rect[8] = {64, 56, 72, 64}; + rect[9] = {72, 56, 80, 64}; + + //Digits + int tbl[4] = {1000, 100, 10, 1}; + + //Limit value + if ( value > 9999 ) + value = 9999; + + //Go through number and draw digits + int offset = 0; + int sw = 0; + while (offset < 4) + { + //Get the digit that this is + int a = 0; + + while (tbl[offset] <= value) + { + value -= tbl[offset]; + ++a; + ++sw; + } + + //Draw digit + if ( bZero && offset == 2 || sw != 0 || offset == 3 ) + PutBitmap3(&rcClient, x + 8 * offset, y, &rect[a], SURFACE_ID_TEXT_BOX); + + //Go to next digit + ++offset; + } +} + +int ModeOpening() +{ + //InitNpChar(); + //InitCaret(); + //InitStar(); + //InitFade(); + //InitFlash(); + //InitBossLife(); + ChangeMusic(0); + TransferStage(72, 100, 3, 3); + //SetFrameTargetMyChar(16); + //SetFadeMask(); + + //Reset cliprect and flags + grcGame.left = 0; + g_GameFlags = 3; + + //CutNoise(); + + int wait = 0; + while (wait < 500) + { + //Increase timer + ++wait; + + //Get pressed keys + GetTrg(); + + //Escape menu + if (gKey & 0x8000) + { + int escRet = Call_Escape(); + if (escRet == 0) + return 0; + if (escRet == 2) + return 1; + } + + //Skip intro if OK is pressed + if ( gKey & gKeyOk ) + break; + + //Update everything + //ActNpChar(); + //ActBossChar(); + //ActBack(); + //ResetMyCharFlag(); + //HitMyCharMap(); + //HitMyCharNpChar(); + //HitMyCharBoss(); + //HitNpCharMap(); + //HitBossMap(); + //HitBossBullet(); + //ActCaret(); + //MoveFrame3(); + //ProcFade(); + + //Draw everything + CortBox(&grcFull, 0x000000); + + int frame_x = 0; + int frame_y = 0; + //GetFramePosition(&frame_x, &frame_y); + //PutBack(frame_x, frame_y); + PutStage_Back(frame_x, frame_y); + //PutBossChar(frame_x, frame_y); + //PutNpChar(frame_x, frame_y); + PutMapDataVector(frame_x, frame_y); + PutStage_Front(frame_x, frame_y); + //PutFront(frame_x, frame_y); + //PutCaret(frame_x, frame_y); + //PutFade(); + + //Update Text Script + //int tscRet = TextScriptProc(); + //if (tscRet == 0) + // return 0; + //if (tscRet == 2) + // return 1; + + PutMapName(false); + //PutTextScript(); + //PutFramePerSecound(); + + if (!Flip_SystemTask()) + return 0; + + ++gCounter; + } + + wait = SDL_GetTicks(); + while (SDL_GetTicks() < wait + 500) + { + CortBox(&grcGame, 0x000000); + //PutFramePerSecound(); + if (!Flip_SystemTask()) + return 0; + } + return 2; +} + +int ModeTitle() +{ + //Set rects + RECT rcTitle = {0, 0, 144, 32}; + RECT rcPixel = {0, 0, 160, 16}; + + RECT rcNew = {144, 0, 192, 16}; + RECT rcContinue = {144, 16, 192, 32}; + + RECT rcVersion = {152, 80, 208, 88}; + RECT rcPeriod = {152, 88, 208, 96}; + + //Character rects + RECT rcMyChar[4]; + RECT rcCurly[4]; + RECT rcToroko[4]; + RECT rcKing[4]; + RECT rcSu[4]; + + rcMyChar[0] = {0, 16, 16, 32}; + rcMyChar[1] = {16, 16, 32, 32}; + rcMyChar[2] = {0, 16, 16, 32}; + rcMyChar[3] = {32, 16, 48, 32}; + + rcCurly[0] = {0, 112, 16, 128}; + rcCurly[1] = {16, 112, 32, 128}; + rcCurly[2] = {0, 112, 16, 128}; + rcCurly[3] = {32, 112, 48, 128}; + + rcToroko[0] = {64, 80, 80, 96}; + rcToroko[1] = {80, 80, 96, 96}; + rcToroko[2] = {64, 80, 80, 96}; + rcToroko[3] = {96, 80, 112, 96}; + + rcKing[0] = {224, 48, 240, 64}; + rcKing[1] = {288, 48, 304, 64}; + rcKing[2] = {224, 48, 240, 64}; + rcKing[3] = {304, 48, 320, 64}; + + rcSu[0] = {0, 16, 16, 32}; + rcSu[1] = {32, 16, 48, 32}; + rcSu[2] = {0, 16, 16, 32}; + rcSu[3] = {48, 16, 64, 32}; + + //Reset everything + //InitCaret(); + //InitStar(); + //CutNoise(); + + //Create variables + int anime = 0; + int char_type = 0; + int time_counter = 0; + + //Set state + bContinue = IsProfile(); + + //Set character + time_counter = 0;//LoadTimeCounter(); + + if (time_counter && time_counter < 18000) + char_type = 1; + if (time_counter && time_counter < 15000) + char_type = 2; + if (time_counter && time_counter < 12000) + char_type = 3; + if (time_counter && time_counter < 9000) + char_type = 4; + + //Set music to character's specific music + switch (char_type) + { + case 1: + ChangeMusic(mus_RunningHell); + break; + case 2: + ChangeMusic(mus_TorokosTheme); + break; + case 3: + ChangeMusic(mus_White); + break; + case 4: + ChangeMusic(mus_Safety); + break; + default: + ChangeMusic(mus_Geothermal);//mus_CaveStory); + break; + } + + //Reset cliprect, flags, and give the player the booster 0.8? + grcGame.left = 0; + g_GameFlags = 0; + + /* + v0 = unk_81C8598; + BYTE1(v0) |= 1u; + unk_81C8598 = v0; + */ + + //Start loop + int wait = 0; + + while (true) + { + //Don't accept selection for 10 frames + if (wait < 10) + ++wait; + + //Get pressed keys + GetTrg(); + + //Quit when OK is pressed + if (wait >= 10) + { + if (gKeyTrg & gKeyOk) + break; + } + + if (gKey & 0x8000) + { + int escRet = Call_Escape(); + if (escRet == 0) + return 0; + if (escRet == 2) + return 1; + } + + //Move cursor + if ((gKeyDown | gKeyUp) & gKeyTrg) + { + PlaySoundObject(1, 1); + bContinue = !bContinue; + } + + //Update carets + //ActCaret(); + + //Animate character cursor + if ( ++anime >= 40 ) + anime = 0; + + //Draw title + CortBox(&grcGame, 0x202020); + + //Draw version + int v1, v2, v3, v4; + PutBitmap3(&grcGame, 100, 216, &rcVersion, SURFACE_ID_TEXT_BOX); + PutBitmap3(&grcGame, 156, 216, &rcPeriod, SURFACE_ID_TEXT_BOX); + + GetCompileVersion(&v1, &v2, &v3, &v4); + PutNumber4(140, 216, v1, 0); + PutNumber4(156, 216, v2, 0); + PutNumber4(172, 216, v3, 0); + PutNumber4(188, 216, v4, 0); + + //Draw main title + PutBitmap3(&grcGame, 88, 40, &rcTitle, 0); + PutBitmap3(&grcGame, 136, 128, &rcNew, 0); + PutBitmap3(&grcGame, 136, 148, &rcContinue, 0); + PutBitmap3(&grcGame, 80, 192, &rcPixel, 1); + + //Draw character cursor + RECT char_rc; + int char_surf; + + switch ( char_type ) + { + case 0: + char_rc = rcMyChar[anime / 10 % 4]; + char_surf = SURFACE_ID_MY_CHAR; + break; + case 1: + char_rc = rcCurly[anime / 10 % 4]; + char_surf = SURFACE_ID_NPC_REGU; + break; + case 2: + char_rc = rcToroko[anime / 10 % 4]; + char_surf = SURFACE_ID_NPC_REGU; + break; + case 3: + char_rc = rcKing[anime / 10 % 4]; + char_surf = SURFACE_ID_NPC_REGU; + break; + case 4: + char_rc = rcSu[anime / 10 % 4]; + char_surf = SURFACE_ID_NPC_REGU; + break; + } + + int char_y; + if (bContinue == 1) + char_y = 147; + else + char_y = 127; + + PutBitmap3(&grcGame, 116, char_y, &char_rc, char_surf); + + //Draw carets + //PutCaret(0, 0); + + //if (time_counter) + // PutTimeCounter(16, 8); + + //PutFramePerSecound(); + + if (!Flip_SystemTask()) + return 0; + } + + PlaySoundObject(18, 1); + ChangeMusic(0); + + //Black screen when option is selected + wait = SDL_GetTicks(); + while (SDL_GetTicks() < wait + 1000) + { + CortBox(&grcGame, 0); + //PutFramePerSecound(); + if (!Flip_SystemTask()) + return 0; + } + + return 0; +} + bool Game() { if (LoadGenericData()) { char path[PATH_LENGTH]; sprintf(path, "%s/npc.tbl", gDataPath); - if (LoadNpcTable(path)) + + if (LoadNpcTable(path) && InitStageTable()) { InitTextScript2(); InitSkipFlags(); InitMapData2(); InitCreditScript(); - StartCreditScript(); - - while (Flip_SystemTask()) - { - ActionCredit(); - ActionIllust(); - ActionStripper(); - CortBox(&grcFull, 0x000020); - PutIllust(); - PutStripper(); - } - - /* - int mode = 0; //1; + int mode = 1; while (mode) { - //if ( mode == 1 ) - // mode = ModeOpening(); - //if ( mode == 2 ) - // mode = ModeTitle(); - //if ( mode == 3 ) + if (mode == 1) + mode = ModeOpening(); + if (mode == 2) + mode = ModeTitle(); + //if (mode == 3) // mode = ModeAction(); } - */ - //EndMapData(); - //EndTextScript(); - //ReleaseNpcTable(); - //ReleaseCreditScript(); + EndMapData(); + EndTextScript(); + ReleaseNpcTable(); + ReleaseStageTable(); + ReleaseCreditScript(); } else { diff --git a/src/Generic.cpp b/src/Generic.cpp index 032eed6d..d19180b0 100644 --- a/src/Generic.cpp +++ b/src/Generic.cpp @@ -1,5 +1,14 @@ #include +bool GetCompileVersion(int *v1, int *v2, int *v3, int *v4) +{ + *v1 = 1; + *v2 = 0; + *v3 = 0; + *v4 = 6; + return true; +} + bool IsShiftJIS(uint8_t c) { if ( c > 0x80 && c < 0xA0 ) diff --git a/src/Generic.h b/src/Generic.h index bfab70b6..9a8f8c50 100644 --- a/src/Generic.h +++ b/src/Generic.h @@ -1,4 +1,5 @@ #pragma once #include +bool GetCompileVersion(int *v1, int *v2, int *v3, int *v4); bool IsShiftJIS(uint8_t c); diff --git a/src/Main.cpp b/src/Main.cpp index 599e58af..bc31e940 100644 --- a/src/Main.cpp +++ b/src/Main.cpp @@ -9,6 +9,8 @@ #include "Draw.h" #include "Input.h" +#include "Organya.h" +#include "Sound.h" #include "Game.h" #include "Config.h" #include "KeyControl.h" @@ -32,9 +34,9 @@ bool bFps; bool bActive; #ifdef JAPANESE -const char *lpWindowName = "洞窟物語エンジン"; +const char *lpWindowName = "洞窟物語エンジン2"; #else -const char *lpWindowName = "Cave Story Engine ~ Doukutsu Monogatari Enjin"; +const char *lpWindowName = "Cave Story Engine 2 ~ Doukutsu Monogatari Enjin 2"; #endif int main(int argc, char *argv[]) @@ -212,7 +214,7 @@ int main(int argc, char *argv[]) if (Flip_SystemTask()) { //Initialize sound - //InitDirectSound(); + InitDirectSound(); //Initialize joystick if (config.bJoystick && InitDirectInput()) @@ -229,7 +231,7 @@ int main(int argc, char *argv[]) Game(); //End stuff - //EndDirectSound(); + EndDirectSound(); EndTextObject(); EndDirectDraw(); @@ -250,11 +252,11 @@ void InactiveWindow() if (bActive) { bActive = false; - //StopOrganyaMusic(); + StopOrganyaMusic(); //SleepNoise(); } - //PlaySoundObject(7, 0); + PlaySoundObject(7, 0); } void ActiveWindow() @@ -262,12 +264,12 @@ void ActiveWindow() if (!bActive) { bActive = true; - //StopOrganyaMusic(); - //PlayOrganyaMusic(); + StopOrganyaMusic(); + PlayOrganyaMusic(); //ResetNoise(); } - //PlaySoundObject(7, -1); + PlaySoundObject(7, -1); } void JoystickProc() diff --git a/src/Map.cpp b/src/Map.cpp index a2340a9b..8d302605 100644 --- a/src/Map.cpp +++ b/src/Map.cpp @@ -1,7 +1,13 @@ #include #include +#include +#include "WindowsWrapper.h" + +#include "CommonDefines.h" #include "Map.h" +#include "Tags.h" +#include "Draw.h" #define PXM_BUFFER_SIZE 0x4B000 @@ -12,3 +18,251 @@ bool InitMapData2() gMap.data = (uint8_t*)malloc(PXM_BUFFER_SIZE); return true; } + +bool LoadMapData2(char *path_map) +{ + //Get path + char path[PATH_LENGTH]; + sprintf(path, "%s/%s", gDataPath, path_map); + + //Open file + SDL_RWops *fp = SDL_RWFromFile(path, "rb"); + if (!fp) + return false; + + //Make sure file begins with "PXM" + char check[3]; + fp->read(fp, check, 1, 3); + + if (!memcmp(check, "PXM", 3)) + { + uint8_t nul; + fp->read(fp, &nul, 1, 1); + + //Get width and height + gMap.width = SDL_ReadLE16(fp); + gMap.length = SDL_ReadLE16(fp); + + if (gMap.data) + { + //Read tiledata + fp->read(fp, gMap.data, 1, gMap.length * gMap.width); + SDL_RWclose(fp); + return true; + } + else + { + SDL_RWclose(fp); + return false; + } + } + else + { + SDL_RWclose(fp); + return false; + } + + return false; +} + +bool LoadAttributeData(char *path_atrb) +{ + //Open file + char path[260]; + sprintf(path, "%s/%s", gDataPath, path_atrb); + + SDL_RWops *fp = SDL_RWFromFile(path, "rb"); + if (!fp) + return false; + + //Read data + fp->read(fp, gMap.atrb, 1, 0x100); + SDL_RWclose(fp); + return true; +} + +void EndMapData() +{ + if (gMap.data) + free(gMap.data); +} + +void ReleasePartsImage() +{ + ReleaseSurface(SURFACE_ID_LEVEL_TILESET); +} + +void GetMapData(uint8_t **data, int16_t *mw, int16_t *ml) +{ + if (data) + *data = gMap.data; + if (mw) + *mw = gMap.width; + if (ml) + *ml = gMap.length; +} + +int GetAttribute(int x, int y) +{ + if (x >= 0 && y >= 0 && gMap.width > x && gMap.length > y) + return gMap.atrb[gMap.data[y * gMap.width + x]]; + return false; +} + +void DeleteMapParts(int x, int y) +{ + gMap.data[y * gMap.width + x] = 0; +} + +void ShiftMapParts(int x, int y) +{ + --gMap.data[y * gMap.width + x]; +} + +bool ChangeMapParts(int x, int y, uint8_t no) +{ + if ( gMap.data[y * gMap.width + x] == no ) + return false; + gMap.data[y * gMap.width + x] = no; + //for (int i = 0; i <= 2; ++i ) + // SetNpChar(4, x << 13, y << 13, 0, 0, 0, 0, 0); + return true; +} + +void PutStage_Back(int fx, int fy) +{ + //Get range to draw + int num_x = WINDOW_WIDTH / 2 + 1; + int num_y = WINDOW_HEIGHT / 2 + 1; + int put_x = (fx / 0x200 + 8) / 16; + int put_y = (fy / 0x200 + 8) / 16; + + for (int j = put_y; put_y + num_y > j; j++) + { + for (int i = put_x; put_x + num_x > i; i++) + { + //Get attribute + int offset = i + j * gMap.width; + int atrb = GetAttribute(i, j); + + if (atrb < 0x20) + { + //Draw tile + RECT rect; + rect.left = 16 * (gMap.data[offset] & 0xF); + rect.top = 16 * (gMap.data[offset] >> 4); + rect.right = rect.left + 16; + rect.bottom = rect.top + 16; + + PutBitmap3(&grcGame, 8 * (2 * i - 1) - fx / 0x200, 8 * (2 * j - 1) - fy / 0x200, &rect, SURFACE_ID_LEVEL_TILESET); + } + } + } +} + +void PutStage_Front(int fx, int fy) +{ + RECT rcSnack = {256, 48, 272, 64}; + + //Get range to draw + int num_x = WINDOW_WIDTH / 2 + 1; + int num_y = WINDOW_HEIGHT / 2 + 1; + int put_x = (fx / 0x200 + 8) / 16; + int put_y = (fy / 0x200 + 8) / 16; + + for (int j = put_y; put_y + num_y > j; j++) + { + for (int i = put_x; put_x + num_x > i; i++) + { + //Get attribute + int offset = i + j * gMap.width; + int atrb = GetAttribute(i, j); + + if (atrb >= 0x40 && atrb < 0x80) + { + //Draw tile + RECT rect; + rect.left = 16 * (gMap.data[offset] & 0xF); + rect.top = 16 * (gMap.data[offset] >> 4); + rect.right = rect.left + 16; + rect.bottom = rect.top + 16; + + PutBitmap3(&grcGame, 8 * (2 * i - 1) - fx / 0x200, 8 * (2 * j - 1) - fy / 0x200, &rect, SURFACE_ID_LEVEL_TILESET); + + if (atrb == 0x43) + PutBitmap3(&grcGame, 8 * (2 * i - 1) - fx / 0x200, 8 * (2 * j - 1) - fy / 0x200, &rcSnack, SURFACE_ID_NPC_SYM); + } + } + } +} + +void PutMapDataVector(int fx, int fy) +{ + //Get range to draw + int num_x = WINDOW_WIDTH / 2 + 1; + int num_y = WINDOW_HEIGHT / 2 + 1; + int put_x = (fx / 0x200 + 8) / 16; + int put_y = (fy / 0x200 + 8) / 16; + + //Animate the wind + static int count = 0; + count++; + + for (int j = put_y; put_y + num_y > j; j++) + { + for (int i = put_x; put_x + num_x > i; i++) + { + //Get attribute + int offset = i + j * gMap.width; + int atrb = GetAttribute(i, j); + + if ( atrb == 0x80 + || atrb == 0x81 + || atrb == 0x82 + || atrb == 0x83 + || atrb == 0xA0 + || atrb == 0xA1 + || atrb == 0xA2 + || atrb == 0xA3) + { + RECT rect; + + switch ( atrb ) + { + case 128: + case 160: + rect.left = (count & 0xF) + 224; + rect.right = (count & 0xF) + 240; + rect.top = 48; + rect.bottom = 64; + break; + case 129: + case 161: + rect.left = 224; + rect.right = 240; + rect.top = (count & 0xF) + 48; + rect.bottom = (count & 0xF) + 64; + break; + case 130: + case 162: + rect.left = 240 - (count & 0xF); + rect.right = rect.left + 16; + rect.top = 48; + rect.bottom = 64; + break; + case 131: + case 163: + rect.left = 224; + rect.right = 240; + rect.top = 64 - (count & 0xF); + rect.bottom = rect.top + 16; + break; + default: + break; + } + + PutBitmap3(&grcGame, 8 * (2 * i - 1) - fx / 0x200, 8 * (2 * j - 1) - fy / 0x200, &rect, SURFACE_ID_CARET); + } + } + } +} diff --git a/src/Map.h b/src/Map.h index 46d53991..68e43d26 100644 --- a/src/Map.h +++ b/src/Map.h @@ -9,4 +9,18 @@ struct MAP_DATA int16_t length; }; +extern MAP_DATA gMap; + bool InitMapData2(); +bool LoadMapData2(char *path_map); +bool LoadAttributeData(char *path_atrb); +void EndMapData(); +void ReleasePartsImage(); +void GetMapData(uint8_t **data, int16_t *mw, int16_t *ml); +int GetAttribute(int x, int y); +void DeleteMapParts(int x, int y); +void ShiftMapParts(int x, int y); +bool ChangeMapParts(int x, int y, uint8_t no); +void PutStage_Back(int fx, int fy); +void PutStage_Front(int fx, int fy); +void PutMapDataVector(int fx, int fy); diff --git a/src/MapName.cpp b/src/MapName.cpp new file mode 100644 index 00000000..a6d6e9e5 --- /dev/null +++ b/src/MapName.cpp @@ -0,0 +1,73 @@ +#include +#include + +#include "CommonDefines.h" +#include "MapName.h" +#include "Draw.h" + +MAP_NAME gMapName; +RECT rc = { 0, 0, 160, 12 }; + +void ReadyMapName(char *str) +{ + //Reset map name flags + gMapName.flag = 0; + gMapName.wait = 0; + + //Handle "Studio Pixel presents" text in the intro + #ifdef JAPANESE + char presentText[24] = "開発室Pixel presents\x00\x01\x01\x01"; + #else + char presentText[24] = " Studio Pixel presents"; + #endif + + if (!strcmp(str, "u")) + { + /*for (i = 0; i < strlen(presentText); i++) //No need for this, we aren't encrypting the text + ++studio_pixel_presents_string[i];*/ + str = presentText; + } + + //Copy map's name to the MapName + strcpy(gMapName.name, str); + + //Draw the text to the surface + int len = strlen(gMapName.name); + + CortBox2(&rc, 0, SURFACE_ID_ROOM_NAME); + PutText2((-6 * len + 160) / 2 + 6, 1, gMapName.name, 0x110022, SURFACE_ID_ROOM_NAME); + PutText2((-6 * len + 160) / 2 + 6, 0, gMapName.name, 0xFFFFFE, SURFACE_ID_ROOM_NAME); +} + +void PutMapName(bool bMini) +{ + if (bMini) + { + //Map system + RECT rcBack = {0, 7, WINDOW_WIDTH, 24}; + CortBox(&rcBack, 0x000000); + PutBitmap3(&grcGame, 74, 10, &rc, SURFACE_ID_ROOM_NAME); + } + else if (gMapName.flag) + { + //MNA + PutBitmap3(&grcGame, 74, 80, &rc, SURFACE_ID_ROOM_NAME); + if (++gMapName.wait > 160) + gMapName.flag = 0; + } +} + +void StartMapName() +{ + gMapName.flag = 1; + gMapName.wait = 0; +} + +void RestoreMapName() +{ + int len = strlen(gMapName.name); + + CortBox2(&rc, 0, SURFACE_ID_ROOM_NAME); + PutText2((-6 * len + 160) / 2 + 6, 1, gMapName.name, 0x110022, SURFACE_ID_ROOM_NAME); + PutText2((-6 * len + 160) / 2 + 6, 0, gMapName.name, 0xFFFFFE, SURFACE_ID_ROOM_NAME); +} diff --git a/src/MapName.h b/src/MapName.h new file mode 100644 index 00000000..c9f651c2 --- /dev/null +++ b/src/MapName.h @@ -0,0 +1,12 @@ +#pragma once +struct MAP_NAME +{ + int flag; + int wait; + char name[0x20]; +}; + +void ReadyMapName(char *str); +void PutMapName(bool bMini); +void StartMapName(); +void RestoreMapName(); diff --git a/src/NpChar.cpp b/src/NpChar.cpp new file mode 100644 index 00000000..b4f17488 --- /dev/null +++ b/src/NpChar.cpp @@ -0,0 +1,12 @@ +#include + +#include "NpChar.h" + +#define NPC_MAX 0x200 + +NPCHAR gNPC[NPC_MAX]; + +bool LoadEvent(char *path_event) +{ + return true; +} diff --git a/src/NpChar.h b/src/NpChar.h new file mode 100644 index 00000000..55c2523b --- /dev/null +++ b/src/NpChar.h @@ -0,0 +1,43 @@ +#pragma once +#include +#include "WindowsWrapper.h" + +struct NPCHAR +{ + uint8_t cond; + int flag; + int x; + int y; + int xm; + int ym; + int xm2; + int ym2; + int tgt_x; + int tgt_y; + int code_char; + int code_flag; + int code_event; + int surf; + int hit_voice; + int destroy_voice; + int life; + int exp; + int size; + int direct; + uint16_t bits; + RECT rect; + int ani_wait; + int ani_no; + int count1; + int count2; + int act_no; + int act_wait; + RECT hit; + RECT view; + uint8_t shock; + int damage_view; + int damage; + NPCHAR *pNpc; +}; + +bool LoadEvent(char *path_event); diff --git a/src/NpcTbl.cpp b/src/NpcTbl.cpp index a912dafa..1563cc91 100644 --- a/src/NpcTbl.cpp +++ b/src/NpcTbl.cpp @@ -41,6 +41,13 @@ bool LoadNpcTable(const char *path) fp->read(fp, &gNpcTable[i].hit, 4, 1); for (size_t i = 0; i < npcCount; i++) //view fp->read(fp, &gNpcTable[i].view, 4, 1); - + + SDL_RWclose(fp); return true; } + +void ReleaseNpcTable() +{ + if (gNpcTable) + free(gNpcTable); +} diff --git a/src/NpcTbl.h b/src/NpcTbl.h index ab46dce5..0554fad5 100644 --- a/src/NpcTbl.h +++ b/src/NpcTbl.h @@ -26,3 +26,4 @@ struct NPC_TABLE extern NPC_TABLE *gNpcTable; bool LoadNpcTable(const char *path); +void ReleaseNpcTable(); diff --git a/src/Organya.cpp b/src/Organya.cpp new file mode 100644 index 00000000..e93e6f91 --- /dev/null +++ b/src/Organya.cpp @@ -0,0 +1,632 @@ +#include + +#include +#include +#include +#include +#include "WindowsWrapper.h" + +#include "CommonDefines.h" +#include "Tags.h" +#include "Organya.h" +#include "Sound.h" + +#define PANDUMMY 0xFF +#define VOLDUMMY 0xFF +#define KEYDUMMY 0xFF + +#define MAXTRACK 16 +#define MAXMELODY 8 +#define MAXDRAM 8 + +SOUNDBUFFER* lpORGANBUFFER[8][8][2] = {NULL}; +SOUNDBUFFER** lpDRAMBUFFER = &lpSECONDARYBUFFER[0x96]; + +MUSICINFO info; + +int gTrackVol[MAXTRACK]; +int gOrgVolume = 100; +bool bFadeout = false; + +bool OrganyaNoteAlloc(uint16_t alloc) +{ + for(int j = 0; j < MAXTRACK; j++) + { + info.tdata[j].wave_no = 0; + info.tdata[j].note_list = NULL; + info.tdata[j].note_p = new NOTELIST[alloc]; + + if(info.tdata[j].note_p == NULL) + return false; + + for(int i = 0; i < alloc; i++) + { + (info.tdata[j].note_p + i)->from = NULL; + (info.tdata[j].note_p + i)->to = NULL; + (info.tdata[j].note_p + i)->length = 0; + (info.tdata[j].note_p + i)->pan = PANDUMMY; + (info.tdata[j].note_p + i)->volume = VOLDUMMY; + (info.tdata[j].note_p + i)->y = KEYDUMMY; + } + } + + for(int j = 0; j < MAXMELODY; j++) + MakeOrganyaWave(j, info.tdata[j].wave_no); + //for(int j = 0; j < MAXDRAM; j++) + // InitDramObject(j); + + return true; +} + +void OrganyaReleaseNote() +{ + for(int i = 0; i < MAXTRACK; i++) + { + if(info.tdata[i].note_p != NULL) + delete info.tdata[i].note_p; + } +} + +//Wave playing and loading +typedef struct { + short wave_size; + short oct_par; + short oct_size; +} OCTWAVE; + +OCTWAVE oct_wave[8] = { + { 256, 1, 4 }, //0 Oct + { 256, 2, 8 }, //1 Oct + { 128, 4, 12 }, //2 Oct + { 128, 8, 16 }, //3 Oct + { 64, 16, 20 }, //4 Oct + { 32, 32, 24 }, //5 Oct + { 16, 64, 28 }, //6 Oct + { 8,128, 32 }, //7 Oct +}; + +bool MakeSoundObject8(int8_t *wavep, int8_t track) +{ + for (int j = 0; j < 8; j++) + { + for (int k = 0; k < 2; k++) + { + size_t wave_size = oct_wave[j].wave_size; + size_t data_size = wave_size; + + //Create sound buffer + lpORGANBUFFER[track][j][k] = new SOUNDBUFFER(data_size); + + //Get wave data + uint8_t *wp = (uint8_t*)malloc(data_size); + uint8_t *wp_sub = wp; + size_t wav_tp = 0; + + for (int i = 0; i < data_size; i++) + { + uint8_t work = *(wavep+wav_tp); + work += 0x80; + + *wp_sub = work; + + wav_tp += 0x100 / wave_size; + if (wav_tp >= 0x100) + wav_tp -= 0x100; + + wp_sub++; + } + + //Copy wave data to sound buffer + uint8_t *buf; + lpORGANBUFFER[track][j][k]->Lock(&buf, NULL); + memcpy(buf, wp, data_size); + lpORGANBUFFER[track][j][k]->Unlock(); + } + } + + return true; +} + +//Playing melody tracks +double freq_tbl[12] = { 261.62556530060, 277.18263097687, 293.66476791741, 311.12698372208, 329.62755691287, 349.22823143300, 369.99442271163, 391.99543598175, 415.30469757995, 440.00000000000, 466.16376151809, 493.88330125612 }; + +void ChangeOrganFrequency(uint8_t key, uint8_t track, int32_t a) +{ + for (int j = 0; j < 8; j++) + { + for (int i = 0; i < 2; i++) { + double tmpDouble = (((double)oct_wave[j].wave_size * freq_tbl[key]) * (double)oct_wave[j].oct_par) / 8.00f + ((double)a - 1000.0f); + lpORGANBUFFER[track][j][i]->SetFrequency(tmpDouble); + } + } +} + +int16_t pan_tbl[13] = {0, 43, 86, 129, 172, 215, 256, 297, 340, 383, 426, 469, 512}; +uint8_t old_key[MAXTRACK] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; +uint8_t key_on[MAXTRACK] = {0}; +uint8_t key_twin[MAXTRACK] = {0}; + +void ChangeOrganPan(uint8_t key, uint8_t pan, int8_t track) +{ + if(old_key[track] != PANDUMMY) + lpORGANBUFFER[track][old_key[track]/12][key_twin[track]]->SetPan((pan_tbl[pan] - 0x100) * 10); +} + +void ChangeOrganVolume(int no, int32_t volume, int8_t track) +{ + if(old_key[track] != VOLDUMMY) + lpORGANBUFFER[track][old_key[track]/12][key_twin[track]]->SetVolume((volume - 0xFF) * 8); +} + +void PlayOrganObject(uint8_t key, int mode, int8_t track, int32_t freq) +{ + if(lpORGANBUFFER[track][key/12][key_twin[track]] != NULL) + { + switch(mode) + { + case 0: + lpORGANBUFFER[track][old_key[track] / 12][key_twin[track]]->Stop(); + lpORGANBUFFER[track][old_key[track] / 12][key_twin[track]]->SetCurrentPosition(0); + break; + + case 1: + break; + + case 2: + if (old_key[track] != 0xFF) + { + lpORGANBUFFER[track][old_key[track] / 12][key_twin[track]]->Play(false); + old_key[track] = 0xFF; + } + break; + + case -1: + if (old_key[track] == 0xFF) + { + ChangeOrganFrequency(key % 12, track, freq); + lpORGANBUFFER[track][key / 12][key_twin[track]]->Play(true); + old_key[track] = key; + key_on[track] = 1; + } + else if (key_on[track] == 1 && old_key[track] == key) + { + lpORGANBUFFER[track][old_key[track] / 12][key_twin[track]]->Play(false); + key_twin[track]++; + if(key_twin[track] == 2) + key_twin[track] = 0; + lpORGANBUFFER[track][key / 12][key_twin[track]]->Play(true); + } + else + { + lpORGANBUFFER[track][old_key[track]/12][key_twin[track]]->Play(false); + key_twin[track]++; + if(key_twin[track] == 2) + key_twin[track] = 0; + ChangeOrganFrequency(key % 12, track, freq); + lpORGANBUFFER[track][key / 12][key_twin[track]]->Play(true); + old_key[track] = key; + } + break; + } + } +} + +//Release tracks +void ReleaseOrganyaObject(int8_t track) +{ + for(int i = 0; i < 8; i++) + { + if(lpORGANBUFFER[track][i][0] != NULL) + { + lpORGANBUFFER[track][i][0]->Release(); + lpORGANBUFFER[track][i][0] = NULL; + } + if(lpORGANBUFFER[track][i][1] != NULL) + { + lpORGANBUFFER[track][i][1]->Release(); + lpORGANBUFFER[track][i][1] = NULL; + } + } +} + +//Handling WAVE100 +int8_t *wave_data = NULL; + +bool InitWaveData100() +{ + if (wave_data == NULL) + wave_data = (int8_t*)malloc(100 * 0x100); + + char path[PATH_LENGTH]; + sprintf(path, "%s/WAVE100.bin", gDataPath); + + SDL_RWops *fp = SDL_RWFromFile(path, "rb"); + if (!fp) + { + printf("Failed to open %s\n", path); + return false; + } + + for (int i = 0; i < 100 * 0x100; i++) + wave_data[i] = SDL_ReadU8(fp); + + SDL_RWclose(fp); + return true; +} + +bool DeleteWaveData100() +{ + free(wave_data); + return true; +} + +//Create org wave +bool MakeOrganyaWave(int8_t track, int8_t wave_no) +{ + if(wave_no > 99) + return false; + ReleaseOrganyaObject(track); + MakeSoundObject8(&wave_data[wave_no * 0x100], track); + return true; +} + +//Dram +void ChangeDramFrequency(uint8_t key, int8_t track) +{ + lpDRAMBUFFER[track]->SetFrequency(key * 800 + 100); +} + +void ChangeDramPan(uint8_t pan, int8_t track) +{ + lpDRAMBUFFER[track]->SetPan((pan_tbl[pan] - 0x100) * 10); +} + +void ChangeDramVolume(int32_t volume, int8_t track) +{ + lpDRAMBUFFER[track]->SetVolume((volume - 0xFF) * 8); +} + +void PlayDramObject(unsigned char key, int mode,char track) +{ + + switch(mode) + { + case 0: + lpDRAMBUFFER[track]->Stop(); + lpDRAMBUFFER[track]->SetCurrentPosition(0); + break; + case 1: + lpDRAMBUFFER[track]->Stop(); + lpDRAMBUFFER[track]->SetCurrentPosition(0); + ChangeDramFrequency(key, track); + lpDRAMBUFFER[track]->Play(false); + break; + case 2: + break; + case -1: + break; + } +} + +//Play data +int32_t play_p; +NOTELIST *play_np[MAXTRACK]; +int32_t now_leng[MAXMELODY] = {0}; + +void OrganyaPlayData() +{ + //Handle fading out + if (bFadeout && gOrgVolume) + gOrgVolume -= 2; + if (gOrgVolume < 0) + gOrgVolume = 0; + + //Play melody + for(int i = 0; i < MAXMELODY; i++) + { + if (play_np[i] != NULL &&play_p == play_np[i]->x) + { + if(play_np[i]->y != KEYDUMMY) + { + PlayOrganObject(play_np[i]->y,-1,i,info.tdata[i].freq); + now_leng[i] = play_np[i]->length; + } + + if(play_np[i]->pan != PANDUMMY) + ChangeOrganPan(play_np[i]->y,play_np[i]->pan, i); + if(play_np[i]->volume != VOLDUMMY) + gTrackVol[i] = play_np[i]->volume; + + play_np[i] = play_np[i]->to; + } + + if (now_leng[i] == 0 ) + PlayOrganObject(0, 2, i, info.tdata[i].freq); + + if (now_leng[i] > 0) + now_leng[i]--; + + if (play_np[i]) + ChangeOrganVolume(play_np[i]->y, gOrgVolume * gTrackVol[i] / 0x7F, i); + } + + for(int i = MAXMELODY; i < MAXTRACK; i++) + { + if (play_np[i] != NULL && play_p == play_np[i]->x) + { + if (play_np[i]->y != KEYDUMMY) + PlayDramObject(play_np[i]->y,1,i-MAXMELODY); + + if(play_np[i]->pan != PANDUMMY) + ChangeDramPan(play_np[i]->pan,i-MAXMELODY); + if(play_np[i]->volume != VOLDUMMY) + gTrackVol[i] = play_np[i]->volume; + + play_np[i] = play_np[i]->to; + } + + if (play_np[i]) + ChangeDramVolume(gOrgVolume * gTrackVol[i] / 0x7F, i - MAXMELODY); + } + + //Looping + play_p++; + if(play_p >= info.end_x) + { + play_p = info.repeat_x; + SetPlayPointer(play_p); + } +} + +void SetPlayPointer(int32_t x) +{ + for (int i = 0; i < MAXTRACK; i++) + { + play_np[i] = info.tdata[i].note_list; + while (play_np[i] != NULL && play_np[i]->x < x) + play_np[i] = play_np[i]->to; + } + + play_p = x; +} + +//Load organya file +void LoadOrganya(char *name) +{ + //Unload previous things + OrganyaReleaseNote(); + memset(&info, 0, sizeof(info)); + OrganyaNoteAlloc(0xFFFF); + + //Stop currently playing notes + memset(play_np, 0, sizeof(play_np)); + memset(old_key, 0xFF, sizeof(old_key)); + memset(key_on, 0, sizeof(key_on)); + memset(key_twin, 0, sizeof(key_twin)); + memset(now_leng, 0, sizeof(now_leng)); + + //Open file + char path[PATH_LENGTH]; + sprintf(path, "%s/Org/%s.org", gDataPath, name); + SDL_RWops *fp = SDL_RWFromFile(path, "rb"); + + if (!fp) + { + printf("Failed to open.org\nSDL Error: %s\n", SDL_GetError()); + return; + } + + //Version Check + uint8_t ver = 0; + char pass_check[6]; + + SDL_RWread(fp, &pass_check[0], sizeof(char), 6); + + if (!memcmp(pass_check, "Org-01", 6))ver = 1; + if (!memcmp(pass_check, "Org-02", 6))ver = 2; + //if (!memcmp(pass_check, "Org-03", 6))ver = 2; + + if (!ver) + { + printf("Failed to open.org, invalid version %s", pass_check); + return; + } + + //Set song information + info.wait = SDL_ReadLE16(fp); + info.line = SDL_ReadU8(fp); + info.dot = SDL_ReadU8(fp); + info.repeat_x = SDL_ReadLE32(fp); + info.end_x = SDL_ReadLE32(fp); + + for (int i = 0; i < 16; i++) { + info.tdata[i].freq = SDL_ReadLE16(fp); + info.tdata[i].wave_no = SDL_ReadU8(fp); + SDL_ReadU8(fp); + info.tdata[i].note_num = SDL_ReadLE16(fp); + } + + //Load notes + NOTELIST *np; + + for (int j = 0; j < 16; j++) { + //The first note from is NULL + if (info.tdata[j].note_num == 0) { + info.tdata[j].note_list = nullptr; + continue; + } + + //Make note list + np = info.tdata[j].note_p; + info.tdata[j].note_list = info.tdata[j].note_p; + np->from = nullptr; + np->to = (np + 1); + np++; + + for (int i = 1; i < info.tdata[j].note_num; i++) { + np->from = (np - 1); + np->to = (np + 1); + np++; + } + + //The last note to is NULL + np--; + np->to = nullptr; + + //Set note properties + np = info.tdata[j].note_p; //X position + for (int i = 0; i < info.tdata[j].note_num; i++) { + np->x = SDL_ReadLE32(fp); + np++; + } + + np = info.tdata[j].note_p; //Y position + for (int i = 0; i < info.tdata[j].note_num; i++) { + np->y = SDL_ReadU8(fp); + np++; + } + + np = info.tdata[j].note_p; //Length + for (int i = 0; i < info.tdata[j].note_num; i++) { + np->length = SDL_ReadU8(fp); + np++; + } + + np = info.tdata[j].note_p; //Volume + for (int i = 0; i < info.tdata[j].note_num; i++) { + np->volume = SDL_ReadU8(fp); + np++; + } + + np = info.tdata[j].note_p; //Pan + for (int i = 0; i < info.tdata[j].note_num; i++) { + np->pan = SDL_ReadU8(fp); + np++; + } + } + + SDL_RWclose(fp); + + //Create waves + for (int j = 0; j < 8; j++) + MakeOrganyaWave(j, info.tdata[j].wave_no); + + //Reset position + SetPlayPointer(0); + + //Set as loaded + info.loaded = true; +} + +void SetOrganyaPosition(unsigned int x) +{ + SetPlayPointer(x); + gOrgVolume = 100; + bFadeout = false; +} + +unsigned int GetOrganyaPosition() +{ + return play_p; +} + +void PlayOrganyaMusic() +{ + //Start timer + OrganyaStartTimer(info.wait); +} + +bool ChangeOrganyaVolume(signed int volume) +{ + if ( volume >= 0 && volume <= 100 ) + { + gOrgVolume = volume; + return true; + } + + return false; +} + +void StopOrganyaMusic() +{ + //Stop timer + OrganyaEndTimer(); + + //Stop notes + for (int i = 0; i < MAXMELODY; i++) + PlayOrganObject(0, 2, i, 0); + + memset(old_key, 255, sizeof(old_key)); + memset(key_on, 0, sizeof(key_on)); + memset(key_twin, 0, sizeof(key_twin)); +} + +//Org timer +SDL_Thread *OrganyaTimer = nullptr; +bool bEndTimer = false; + +int OrganyaPlayTimer(void *ptr) +{ + SDL_SetThreadPriority(SDL_THREAD_PRIORITY_HIGH); + + //Set time for next step to play + uint32_t NextTick = SDL_GetTicks() + info.wait; + + while (bEndTimer == false) + { + if (info.loaded) + { + //Play music + OrganyaPlayData(); + + //Wait until this step is over + while (NextTick > SDL_GetTicks()) + SDL_Delay(1); + + //Get time for next step to play + while (NextTick <= SDL_GetTicks()) + NextTick += info.wait; + } + else + { + //Wait until the org is loaded + SDL_Delay(1); + } + } + + return 0; +} + +void OrganyaStartTimer(unsigned int wait) +{ + OrganyaEndTimer(); + bEndTimer = false; + OrganyaTimer = SDL_CreateThread(OrganyaPlayTimer, "OrganyaPlayTimer", (void*)NULL); +} + +void OrganyaEndTimer() +{ + bEndTimer = true; //Tell thread to end + SDL_WaitThread(OrganyaTimer, NULL); //Wait for thread to end + OrganyaTimer = nullptr; +} + +//Start and end organya +void StartOrganya() +{ + //Initialize org stuff + InitWaveData100(); +} + +void EndOrganya() +{ + //End timer + OrganyaEndTimer(); + + //Release everything related to org + OrganyaReleaseNote(); + DeleteWaveData100(); + + for (int i = 0; i < MAXMELODY; i++) + ReleaseOrganyaObject(i); +} diff --git a/src/Organya.h b/src/Organya.h new file mode 100644 index 00000000..dc74d2b2 --- /dev/null +++ b/src/Organya.h @@ -0,0 +1,51 @@ +#pragma once +#include + +//Below are Organya song data structures +struct NOTELIST { + NOTELIST *from; //Previous address + NOTELIST *to; //Next address + + int32_t x; //Position + unsigned char length; //Sound length + unsigned char y; //Sound height + unsigned char volume; //Volume + unsigned char pan; +}; + +//Track data * 8 +struct TRACKDATA { + uint16_t freq; //Frequency (1000 is default) + uint8_t wave_no; //Waveform No. + uint16_t note_num; //Number of notes + + NOTELIST *note_p; + NOTELIST *note_list; +}; + +//Unique information held in songs +struct MUSICINFO { + uint16_t wait; + bool loaded; + bool playing; + unsigned char line; //Number of lines in one measure + unsigned char dot; //Number of dots per line + uint16_t alloc_note; //Number of allocated notes + int32_t repeat_x; //Repeat + int32_t end_x; //End of song (Return to repeat) + TRACKDATA tdata[16]; +}; + +bool MakeOrganyaWave(int8_t track, int8_t wave_no); +void OrganyaPlayData(); +void SetPlayPointer(int32_t x); +void LoadOrganya(char *name); +void SetOrganyaPosition(unsigned int x); +unsigned int GetOrganyaPosition(); +void PlayOrganyaMusic(); +bool ChangeOrganyaVolume(signed int volume); +void StopOrganyaMusic(); +void OrganyaStartTimer(unsigned int wait); +void OrganyaEndTimer(); +void StartOrganya(); +void EndOrganya(); diff --git a/src/PixTone.cpp b/src/PixTone.cpp new file mode 100644 index 00000000..ab49e427 --- /dev/null +++ b/src/PixTone.cpp @@ -0,0 +1,288 @@ +#include +#include +#include +#include +#include +#include + +#include "CommonDefines.h" +#include "Tags.h" +#include "PixTone.h" + +int8_t gWaveModelTable[6][0x100]; + +void MakeWaveTables() +{ + /* Sine wave */ + for (int i = 0; i < 0x100; i++) + gWaveModelTable[0][i] = (sin(i * 6.283184 / 256.0) * 64.0); + + /* Triangle wave */ + int triangle = 0; + for (int i = 0; i < 0x40; ++i) //Upwards + gWaveModelTable[1][i] = (triangle++ << 6) / 0x40; + triangle = 0; + for (int i = 0x40; i < 0xC0; ++i) //Downwards + gWaveModelTable[1][i] = 0x40 - (triangle++ << 6) / 0x40; + triangle = 0; + for (int i = 0xC0; i < 0x100; ++i) //Back upwards + gWaveModelTable[1][i] = (triangle++ << 6) / 0x40 - 0x40; + + /* Saw up wave */ + for (int i = 0; i < 0x100; i++) + gWaveModelTable[2][i] = i / 2 - 0x40; + + /* Saw down wave */ + for (int i = 0; i < 0x100; i++) + gWaveModelTable[3][i] = 0x40 - i / 2; + + /* Square wave */ + for (int i = 0; i < 0x80; i++) + gWaveModelTable[4][i] = 0x40; + for (int i = 0x80; i < 0x100; i++) + gWaveModelTable[4][i] = -0x40; + + /* White noise wave */ + srand(0); + for (int i = 0; i < 0x100; i++) + gWaveModelTable[5][i] = (int8_t)rand() / 2; +} + +//Loading .pxt files +double fgetv(FILE *fp) // Load a numeric value from text file; one per line. +{ + //Create buffer + char Buf[0x1000]; + Buf[0xFFF] = '\0'; + char *p = Buf; + + if (!std::fgets(Buf, sizeof(Buf) - 1, fp)) + return 0.0; + + // Ignore empty lines. If the line was empty, try next line. + if (!Buf[0] || Buf[0] == '\r' || Buf[0] == '\n') + return fgetv(fp); + + while (*p && *p++ != ':') + { + } + + return std::strtod(p, 0); // Parse the value and return it. +} + +bool MakePixelWaveData(const std::vector& pxtData, uint8_t *data) +{ + //Get some envelope stuff + char envelopeTable[0x100]; + memset(envelopeTable, 0, sizeof(envelopeTable)); + + size_t i = 0; + + //Point A + long double currentEnvelope = pxtData[14]; + while (i < pxtData[15]) + { + envelopeTable[i] = (char)currentEnvelope; + currentEnvelope = (pxtData[16] - pxtData[14]) + / pxtData[15] + + currentEnvelope; + ++i; + } + + //Point B + long double currentEnvelopea = pxtData[16]; + while (i < pxtData[17]) + { + envelopeTable[i] = (char)currentEnvelopea; + currentEnvelopea = (pxtData[18] - pxtData[16]) + / (pxtData[17] - pxtData[15]) + + currentEnvelopea; + ++i; + } + + //Point C + long double currentEnvelopeb = pxtData[18]; + while (i < pxtData[19]) + { + envelopeTable[i] = (char)currentEnvelopeb; + currentEnvelopeb = (pxtData[20] - pxtData[18]) + / (pxtData[19] - pxtData[17]) + + currentEnvelopeb; + ++i; + } + + //End + long double currentEnvelopec = pxtData[20]; + while (i < 0x100) + { + envelopeTable[i] = (char)currentEnvelopec; + currentEnvelopec = currentEnvelopec + - pxtData[20] / (0x100 - pxtData[19]); + ++i; + } + + long double pitchOffset = pxtData[9]; + long double mainOffset = pxtData[5]; + long double volumeOffset = pxtData[13]; + + //Main + long double mainFreq; + if (pxtData[3] == 0.0) + mainFreq = 0.0; + else + mainFreq = 256.0 / (pxtData[1] / pxtData[3]); + + //Pitch + long double pitchFreq; + if (pxtData[7] == 0.0) + pitchFreq = 0.0; + else + pitchFreq = 256.0 / (pxtData[1] / pxtData[7]); + + //Volume + long double volumeFreq; + if (pxtData[11] == 0.0) + volumeFreq = 0.0; + else + volumeFreq = 256.0 / (pxtData[1] / pxtData[11]); + + for (i = 0; i < pxtData[1]; ++i) + { + const int a = (int)(uint64_t)mainOffset % 256; + const int v2 = (int)(uint64_t)pitchOffset % 256; + + //Input data + data[i] = envelopeTable[(unsigned __int64)((long double)(i << 8) / pxtData[1])] + * (pxtData[4] + * gWaveModelTable[(size_t)pxtData[2]][a] + / 0x40 + * (pxtData[12] + * gWaveModelTable[(size_t)pxtData[10]][(signed int)(uint64_t)volumeOffset % 0x100] + / 0x40 + + 0x40) + / 0x40) + / 0x40 + + 0x80; + + long double newMainOffset; + if (gWaveModelTable[(size_t)pxtData[6]][v2] >= 0) + newMainOffset = (mainFreq * 2) + * (long double)gWaveModelTable[(size_t)pxtData[6]][(signed int)(unsigned __int64)pitchOffset % 256] + * pxtData[8] + / 64.0 + / 64.0 + + mainFreq + + mainOffset; + else + newMainOffset = mainFreq + - mainFreq + * 0.5 + * (long double)-gWaveModelTable[(size_t)pxtData[6]][v2] + * pxtData[8] + / 64.0 + / 64.0 + + mainOffset; + + mainOffset = newMainOffset; + pitchOffset = pitchOffset + pitchFreq; + volumeOffset = volumeOffset + volumeFreq; + } + + return true; +} + +bool LoadPxt(char *name, uint8_t **buf, size_t *length) +{ + //Open file + char path[PATH_LENGTH]; + sprintf(path, "%s/Sound/%s", gDataPath, name); + FILE *fp = fopen(path, "rb"); + + if (!fp) + return false; + + //Read data + std::vector lineNumbers[4]; + for (int i = 0; i < 4; ++i) + { + for (int j = 0; j < 21; j++) + { + double val = fgetv(fp); + lineNumbers[i].push_back(val); + } + } + + //Close file + fclose(fp); + + //Get size + size_t size; + for (int i = 0; i < 4; i++) + { + if (lineNumbers[i][1] > size) + size = (size_t)lineNumbers[i][1]; + } + + //Allocate buffers + uint8_t *dest = (uint8_t*)malloc(size); + uint8_t *pBlock = (uint8_t*)malloc(size); + + if (dest && pBlock) + { + //Set buffers to default value of 0x80 + memset(dest, 0x80, size); + memset(pBlock, 0x80, size); + + for (int i = 0; i < 4; ++i) + { + //Get wave data + if (!MakePixelWaveData(lineNumbers[i], dest)) + { + printf("MakePixelWaveData failed for %s\n", name); + free(dest); + free(pBlock); + return -1; + } + + //Put data into buffer + for (int j = 0; j < lineNumbers[i][1]; ++j) + { + if (dest[j] + pBlock[j] - 0x100 >= -0x7F) + { + if (dest[j] + pBlock[j] - 0x100 <= 0x7F) + pBlock[j] += dest[j] - 0x80; + else + pBlock[j] = (uint8_t)-1; + } + else + { + pBlock[j] = 0; + } + } + } + + //Put data from buffers into main sound buffer + *buf = (uint8_t*)malloc(size); + + if (!*buf) + { + printf("Failed to allocate buffer for %s\n", name); + free(dest); + free(pBlock); + return false; + } + + *length = size; + memcpy(*buf, pBlock, size); + + //Free the two buffers + free(dest); + free(pBlock); + return true; + } + + printf("Failed to allocate dest or pBlock for %s\n", name); + free(dest); + free(pBlock); + return false; +} diff --git a/src/PixTone.h b/src/PixTone.h new file mode 100644 index 00000000..17ec5e14 --- /dev/null +++ b/src/PixTone.h @@ -0,0 +1,5 @@ +#pragma once +#include + +void MakeWaveTables(); +bool LoadPxt(char *name, uint8_t **buf, size_t *length); diff --git a/src/Profile.cpp b/src/Profile.cpp new file mode 100644 index 00000000..6b173425 --- /dev/null +++ b/src/Profile.cpp @@ -0,0 +1,24 @@ +#include + +#include +#include "WindowsWrapper.h" + +#include "CommonDefines.h" +#include "Tags.h" +#include "Profile.h" + +const char *gDefaultName = "Profile.dat"; +const char *gProfileCode = "Do041220"; + +bool IsProfile() +{ + char path[PATH_LENGTH]; + sprintf(path, "%s/%s", gModulePath, gDefaultName); + + SDL_RWops *fp = SDL_RWFromFile(path, "rb"); + if (!fp) + return false; + + SDL_RWclose(fp); + return true; +} diff --git a/src/Profile.h b/src/Profile.h new file mode 100644 index 00000000..99fe9e7e --- /dev/null +++ b/src/Profile.h @@ -0,0 +1,4 @@ +#pragma once +#include + +bool IsProfile(); diff --git a/src/Sound.cpp b/src/Sound.cpp new file mode 100644 index 00000000..44d434ac --- /dev/null +++ b/src/Sound.cpp @@ -0,0 +1,324 @@ +#include +#include +#include +#include + +#include + +#include "Sound.h" +#include "Organya.h" +#include "PixTone.h" + +#define FREQUENCY 44100 +#define STREAM_SIZE (FREQUENCY / 100) + +#define clamp(x, y, z) ((x > z) ? z : (x < y) ? y : x) + +//Audio device +SDL_AudioDeviceID audioDevice; + +//Keep track of all existing sound buffers +SOUNDBUFFER *soundBuffers; + +//Sound buffer code +SOUNDBUFFER::SOUNDBUFFER(size_t bufSize) +{ + //Lock audio buffer + SDL_LockAudioDevice(audioDevice); + + //Set parameters + size = bufSize; + + playing = false; + looping = false; + + frequency = 0.0; + volume = 1.0; + volume_l = 1.0; + volume_r = 1.0; + samplePosition = 0.0; + + //Create waveform buffer + data = new uint8_t[bufSize]; + memset(data, 0x80, bufSize); + + //Add to buffer list + this->next = soundBuffers; + soundBuffers = this; + + //Unlock audio buffer + SDL_UnlockAudioDevice(audioDevice); +} + +SOUNDBUFFER::~SOUNDBUFFER() +{ + //Lock audio buffer + SDL_LockAudioDevice(audioDevice); + + //Free buffer + if (data) + delete[] data; + + //Remove from buffer list + for (SOUNDBUFFER **soundBuffer = &soundBuffers; *soundBuffer != nullptr; soundBuffer = &(*soundBuffer)->next) + { + if (*soundBuffer == this) + { + *soundBuffer = this->next; + break; + } + } + + //Unlock audio buffer + SDL_UnlockAudioDevice(audioDevice); +} + +void SOUNDBUFFER::Release() +{ + //TODO: find a better and more stable(?) way to handle this function + delete this; +} + +void SOUNDBUFFER::Lock(uint8_t **outBuffer, size_t *outSize) +{ + SDL_LockAudioDevice(audioDevice); + + if (outBuffer != nullptr) + *outBuffer = data; + + if (outSize != nullptr) + *outSize = size; +} + +void SOUNDBUFFER::Unlock() +{ + SDL_UnlockAudioDevice(audioDevice); +} + +void SOUNDBUFFER::SetCurrentPosition(uint32_t dwNewPosition) +{ + SDL_LockAudioDevice(audioDevice); + samplePosition = dwNewPosition; + SDL_UnlockAudioDevice(audioDevice); +} + +void SOUNDBUFFER::SetFrequency(uint32_t dwFrequency) +{ + SDL_LockAudioDevice(audioDevice); + frequency = (double)dwFrequency; + SDL_UnlockAudioDevice(audioDevice); +} + +float MillibelToVolume(int32_t lVolume) +{ + //Volume is in hundredths of decibels, from 0 to -10000 + lVolume = clamp(lVolume, (decltype(lVolume))-10000, (decltype(lVolume))0); + return pow(10.0f, lVolume / 2000.0f); +} + +void SOUNDBUFFER::SetVolume(int32_t lVolume) +{ + SDL_LockAudioDevice(audioDevice); + volume = MillibelToVolume(lVolume); + SDL_UnlockAudioDevice(audioDevice); +} + +void SOUNDBUFFER::SetPan(int32_t lPan) +{ + SDL_LockAudioDevice(audioDevice); + volume_l = MillibelToVolume(-lPan); + volume_r = MillibelToVolume(lPan); + SDL_UnlockAudioDevice(audioDevice); +} + +void SOUNDBUFFER::Play(bool bLooping) +{ + SDL_LockAudioDevice(audioDevice); + playing = true; + looping = bLooping; + SDL_UnlockAudioDevice(audioDevice); +} + +void SOUNDBUFFER::Stop() +{ + SDL_LockAudioDevice(audioDevice); + playing = false; + SDL_UnlockAudioDevice(audioDevice); +} + +void SOUNDBUFFER::Mix(float *buffer, int len) +{ + if (!playing) //This sound buffer isn't playing + return; + + size_t samples = len / (sizeof(float) * 2); + + for (size_t sample = 0; sample < samples; sample++) + { + double freqPosition = (frequency / (double)FREQUENCY); //This is added to position at the end + + //Get the in-between sample this is (linear interpolation) + uint8_t sample1 = ((looped || ((size_t)samplePosition) >= 1) ? data[(size_t)samplePosition] : 0x80); + uint8_t sample2 = 0x80; + if (looping || (((size_t)samplePosition) + 1) < size) + sample2 = data[(((size_t)samplePosition) + 1) % size]; + + //Interpolate sample + float subPos = std::fmod(samplePosition, 1.0); + float sampleA = (float)sample1 + ((float)sample2 - (float)sample1) * subPos; + + //Convert sample to float32 + float sampleConvert = (sampleA - 128.0) / 256.0; + + //Mix + buffer[sample * 2] += sampleConvert * volume * volume_l; + buffer[sample * 2 + 1] += sampleConvert * volume * volume_r; + + //Increment position + samplePosition += freqPosition; + + if (samplePosition >= size) + { + if (looping) + { + samplePosition = std::fmod(samplePosition, size); + looped = true; + } + else + { + samplePosition = 0.0; + playing = false; + looped = false; + break; + } + } + } +} + +//Sound mixer +void AudioCallback(void *userdata, uint8_t *stream, int len) +{ + //Clear stream + memset(stream, 0, len); + + //Mix sounds to primary buffer + for (SOUNDBUFFER *sound = soundBuffers; sound != nullptr; sound = sound->next) + { + sound->Mix((float*)stream, len); + } +} + +//Sound things +SOUNDBUFFER* lpSECONDARYBUFFER[SOUND_NO]; + +bool InitDirectSound() +{ + SDL_AudioSpec want, have; + + //Set specifications we want + SDL_memset(&want, 0, sizeof(want)); + want.freq = FREQUENCY; + want.format = AUDIO_F32; + want.channels = 2; + want.samples = STREAM_SIZE; + want.callback = AudioCallback; + + audioDevice = SDL_OpenAudioDevice(NULL, 0, &want, &have, 0); + + if (audioDevice == 0) + { + printf("Failed to open audio device\nSDL Error: %s\n", SDL_GetError()); + return false; + } + + //Unpause audio device + SDL_PauseAudioDevice(audioDevice, 0); + + //Start organya + StartOrganya(); + + //Load sound effects + MakeWaveTables(); + + char path[0x100]; + uint8_t *buf = nullptr; + size_t len; + + for (size_t n = 0; n < SOUND_NO; n++) + { + sprintf(path, "%2.2X.pxt", n); + + if (LoadPxt(path, &buf, &len)) + { + lpSECONDARYBUFFER[n] = new SOUNDBUFFER(len); + + uint8_t *sBuf; + size_t sLen; + lpSECONDARYBUFFER[n]->Lock(&sBuf, &sLen); + memcpy(sBuf, buf, sLen); + lpSECONDARYBUFFER[n]->Unlock(); + lpSECONDARYBUFFER[n]->SetFrequency(22050); + } + + //Free buffer, we're done with it + if (buf) + { + free(buf); + buf = nullptr; + } + } + + return true; +} + +void EndDirectSound() +{ + //Close audio device + SDL_CloseAudioDevice(audioDevice); + + //End organya + EndOrganya(); +} + +//Sound effects playing +void PlaySoundObject(int no, int mode) +{ + if (lpSECONDARYBUFFER[no]) + { + if (mode == -1) + { + lpSECONDARYBUFFER[no]->Play(true); + } + else if ( mode ) + { + if ( mode == 1 ) + { + lpSECONDARYBUFFER[no]->Stop(); + lpSECONDARYBUFFER[no]->SetCurrentPosition(0); + lpSECONDARYBUFFER[no]->Play(false); + } + } + else + { + lpSECONDARYBUFFER[no]->Stop(); + } + } +} + +void ChangeSoundFrequency(int no, uint32_t rate) +{ + if (lpSECONDARYBUFFER[no]) + lpSECONDARYBUFFER[no]->SetFrequency(10 * rate + 100); +} + +void ChangeSoundVolume(int no, int32_t volume) +{ + if (lpSECONDARYBUFFER[no]) + lpSECONDARYBUFFER[no]->SetVolume(8 * volume - 2400); +} + +void ChangeSoundPan(int no, int32_t pan) +{ + if (lpSECONDARYBUFFER[no]) + lpSECONDARYBUFFER[no]->SetPan(10 * (pan - 256)); +} diff --git a/src/Sound.h b/src/Sound.h new file mode 100644 index 00000000..0ffb0ecb --- /dev/null +++ b/src/Sound.h @@ -0,0 +1,96 @@ +#pragma once +#include + +class SOUNDBUFFER +{ + public: + SOUNDBUFFER(size_t bufSize); + ~SOUNDBUFFER(); + + void Release(); + + void Lock(uint8_t **buffer, size_t *size); + void Unlock(); + + void SetCurrentPosition(uint32_t dwNewPosition); + void SetFrequency(uint32_t dwFrequency); + void SetVolume(int32_t lVolume); + void SetPan(int32_t lPan); + void Play(bool bLooping); + void Stop(); + + void Mix(float *buffer, int len); + + SOUNDBUFFER *next; + + private: + uint8_t *data; + size_t size; + + bool playing; + bool looping; + bool looped; + + double frequency; + double volume; + double volume_l; + double volume_r; + double samplePosition; +}; + +//Music ID enum +enum MUSIC_IDS +{ + mus_Silence = 0x0, + mus_MischievousRobot = 0x1, + mus_Safety = 0x2, + mus_GameOver = 0x3, + mus_Gravity = 0x4, + mus_OnToGrasstown = 0x5, + mus_Meltdown2 = 0x6, + mus_EyesOfFlame = 0x7, + mus_Gestation = 0x8, + mus_MimigaTown = 0x9, + mus_GetItem = 0xA, + mus_BalrogsTheme = 0xB, + mus_Cemetary = 0xC, + mus_Plant = 0xD, + mus_Pulse = 0xE, + mus_Victory = 0xF, + mus_GetLifeCapsule = 0x10, + mus_Tyrant = 0x11, + mus_Run = 0x12, + mus_Jenka1 = 0x13, + mus_LabyrinthFight = 0x14, + mus_Access = 0x15, + mus_Oppression = 0x16, + mus_Geothermal = 0x17, + mus_CaveStory = 0x18, + mus_Moonsong = 0x19, + mus_Herosend = 0x1A, + mus_ScorchingBack = 0x1B, + mus_Quiet = 0x1C, + mus_FinalCave = 0x1D, + mus_Balcony = 0x1E, + mus_Charge = 0x1F, + mus_LastBattle = 0x20, + mus_TheWayBackHome = 0x21, + mus_Zombie = 0x22, + mus_BreakDown = 0x23, + mus_RunningHell = 0x24, + mus_Jenka2 = 0x25, + mus_LivingWaterway = 0x26, + mus_SealChamber = 0x27, + mus_TorokosTheme = 0x28, + mus_White = 0x29, +}; + +#define SOUND_NO 0x100 +extern SOUNDBUFFER* lpSECONDARYBUFFER[SOUND_NO]; + +bool InitDirectSound(); +void EndDirectSound(); +void PlaySoundObject(int no, int mode); +void ChangeSoundFrequency(int no, uint32_t rate); +void ChangeSoundVolume(int no, int32_t volume); +void ChangeSoundPan(int no, int32_t pan); diff --git a/src/Stage.cpp b/src/Stage.cpp new file mode 100644 index 00000000..4cf0bdaf --- /dev/null +++ b/src/Stage.cpp @@ -0,0 +1,229 @@ +#include +#include + +#include +#include "WindowsWrapper.h" + +#include "CommonDefines.h" +#include "Map.h" +#include "MapName.h" +#include "Draw.h" +#include "Tags.h" +#include "NpChar.h" +#include "TextScr.h" +#include "Organya.h" +#include "Back.h" +#include "Stage.h" + +STAGE_TABLE *gTMT; +int gStageNo; + +//Stage table functions +bool InitStageTable() +{ + //Get path + char path[PATH_LENGTH]; + sprintf(path, "%s/stage.tbl", gDataPath); + + //Open file + SDL_RWops *fp = SDL_RWFromFile(path, "rb"); + + if (!fp) + return false; + + //Get amount of stages and allocate stage data + size_t stages = SDL_RWsize(fp) / 0xC8; + gTMT = (STAGE_TABLE*)calloc(stages, sizeof(STAGE_TABLE)); + + //Read data + for (size_t i = 0; i < stages; i++) + { + SDL_RWread(fp, &gTMT[i].parts, 1, 0x20); + SDL_RWread(fp, &gTMT[i].map, 1, 0x20); + gTMT[i].bkType = SDL_ReadLE32(fp); + SDL_RWread(fp, &gTMT[i].back, 1, 0x20); + SDL_RWread(fp, &gTMT[i].npc, 1, 0x20); + SDL_RWread(fp, &gTMT[i].boss, 1, 0x20); + gTMT[i].boss_no = SDL_ReadU8(fp); + SDL_RWread(fp, &gTMT[i].name, 1, 0x20); + + //Padding (3 bytes) + uint8_t nul[3]; + SDL_RWread(fp, &nul, 1, 3); + } + + SDL_RWclose(fp); + return true; +} + +void ReleaseStageTable() +{ + free(gTMT); + gTMT = nullptr; +} + +bool TransferStage(int no, int w, int x, int y) +{ + //Move character + //SetMyCharPosition(x << 13, y << 13); + + bool bError = false; + bool result; + + //Get path + char path_dir[20]; + strcpy(path_dir, "Stage"); + + //Load tileset + char path[PATH_LENGTH]; + sprintf(path, "%s/Prt%s", path_dir, gTMT[no].parts); + if (!ReloadBitmap_File(path, SURFACE_ID_LEVEL_TILESET)) + bError = true; + + sprintf(path, "%s/%s.pxa", path_dir, gTMT[no].parts); + if (!LoadAttributeData(path)) + bError = true; + + //Load tilemap + sprintf(path, "%s/%s.pxm", path_dir, gTMT[no].map); + if (!LoadMapData2(path)) + bError = true; + + //Load NPCs + sprintf(path, "%s/%s.pxe", path_dir, gTMT[no].map); + if (!LoadEvent(path)) + bError = true; + + //Load script + sprintf(path, "%s/%s.tsc", path_dir, gTMT[no].map); + if (!LoadTextScript_Stage(path)) + bError = true; + + //Load background + strcpy(path, gTMT[no].back); + if (!InitBack(path, gTMT[no].bkType)) + bError = true; + + //Get path + strcpy(path_dir, "Npc"); + + //Load NPC sprite sheets + sprintf(path, "%s/Npc%s", path_dir, gTMT[no].npc); + if (!ReloadBitmap_File(path, SURFACE_ID_LEVEL_SPRITESET_1)) + bError = true; + + sprintf(path, "%s/Npc%s", path_dir, gTMT[no].boss); + if (!ReloadBitmap_File(path, SURFACE_ID_LEVEL_SPRITESET_2)) + bError = true; + + if (bError) + { + printf("Failed to load stage %d\n", no); + return false; + } + else + { + //Load map name + ReadyMapName(gTMT[no].name); + + //StartTextScript(w); + //SetFrameMyChar(); + //ClearBullet(); + //InitCaret(); + //ClearValueView(); + //ResetQuake(); + //InitBossChar(gTMT[no].boss_no); + //ResetFlash(); + gStageNo = no; + return true; + } + + return false; +} + +//Music +const char *gMusicTable[42] = +{ + "xxxx", + "wanpaku", + "anzen", + "gameover", + "gravity", + "weed", + "mdown2", + "fireeye", + "vivi", + "mura", + "fanfale1", + "ginsuke", + "cemetery", + "plant", + "kodou", + "fanfale3", + "fanfale2", + "dr", + "escape", + "jenka", + "maze", + "access", + "ironh", + "grand", + "curly", + "oside", + "requiem", + "wanpak2", + "quiet", + "lastcave", + "balcony", + "lastbtl", + "lastbt3", + "ending", + "zonbie", + "breakdown", + "hell", + "jenka2", + "marine", + "ballos", + "toroko", + "white" +}; + +unsigned int gOldPos; +int gOldNo; +int gMusicNo; + +void ChangeMusic(int no) +{ + //Stop and keep track of old song + gOldPos = GetOrganyaPosition(); + gOldNo = gMusicNo; + StopOrganyaMusic(); + + //Load .org + char *name = (char*)malloc(strlen(gMusicTable[no]) + 1); + strcpy(name, gMusicTable[no]); + LoadOrganya(name); + + //Reset position, volume, and then play the song + ChangeOrganyaVolume(100); + SetOrganyaPosition(0); + PlayOrganyaMusic(); + gMusicNo = no; +} + +void ReCallMusic() +{ + //Stop old song + StopOrganyaMusic(); + + //Load .org that was playing before + char *name = (char*)malloc(strlen(gMusicTable[gOldNo]) + 1); + strcpy(name, gMusicTable[gOldNo]); + LoadOrganya(name); + + //Reset position, volume, and then play the song + SetOrganyaPosition(gOldPos); + ChangeOrganyaVolume(100); + PlayOrganyaMusic(); + gMusicNo = gOldNo; +} diff --git a/src/Stage.h b/src/Stage.h new file mode 100644 index 00000000..2fe80b7e --- /dev/null +++ b/src/Stage.h @@ -0,0 +1,19 @@ +#pragma once + +struct STAGE_TABLE +{ + char parts[0x20]; + char map[0x20]; + int bkType; + char back[0x20]; + char npc[0x20]; + char boss[0x20]; + char boss_no; + char name[0x20]; +}; + +bool InitStageTable(); +void ReleaseStageTable(); +bool TransferStage(int no, int w, int x, int y); +void ChangeMusic(int no); +void ReCallMusic(); diff --git a/src/TextScr.cpp b/src/TextScr.cpp index d5e57650..88b42c9f 100644 --- a/src/TextScr.cpp +++ b/src/TextScr.cpp @@ -1,8 +1,10 @@ #include #include +#include "CommonDefines.h" #include "TextScr.h" #include "Draw.h" +#include "Tags.h" #include "Game.h" #define TSC_BUFFER_SIZE 0x5000 @@ -61,3 +63,42 @@ void EncryptionBinaryData2(uint8_t *pData, int size) pData[i] += val1; } } + +//Load stage .tsc +bool LoadTextScript_Stage(char *name) +{ + //Open Head.tsc + char path[PATH_LENGTH]; + sprintf(path, "%s/%s", gDataPath, "Head.tsc"); + + SDL_RWops *fp = SDL_RWFromFile(path, "rb"); + if (!fp) + return false; + + //Read Head.tsc + int head_size = SDL_RWsize(fp); + + fp->read(fp, gTS.data, 1, head_size); + EncryptionBinaryData2((uint8_t*)gTS.data, head_size); + gTS.data[head_size] = 0; + SDL_RWclose(fp); + + //Open stage's .tsc + sprintf(path, "%s/%s", gDataPath, name); + + fp = SDL_RWFromFile(path, "rb"); + if (!fp) + return false; + + //Read stage's tsc + int body_size = SDL_RWsize(fp); + fp->read(fp, &gTS.data[head_size], 1, body_size); + EncryptionBinaryData2((uint8_t*)&gTS.data[head_size], body_size); + gTS.data[head_size + body_size] = 0; + SDL_RWclose(fp); + + //Set parameters + gTS.size = head_size + body_size; + strcpy(gTS.path, name); + return true; +} diff --git a/src/TextScr.h b/src/TextScr.h index a4023bd7..d4ce4beb 100644 --- a/src/TextScr.h +++ b/src/TextScr.h @@ -57,3 +57,4 @@ struct TEXT_SCRIPT bool InitTextScript2(); void EndTextScript(); void EncryptionBinaryData2(uint8_t *pData, int size); +bool LoadTextScript_Stage(char *name);