ref: f43a3c1130c423ccb859b903ee13381098277eba
parent: c84f49f1dcd521fdbc70613d7ab4d5f505d7c8c0
author: cuckydev <cuckydev@users.noreply.github.com>
date: Sat Jan 19 16:23:04 EST 2019
Org and sound
--- a/Makefile
+++ b/Makefile
@@ -20,9 +20,11 @@
# 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 @@
KeyControl \
Main \
Map \
+ MapName \
+ NpChar \
NpcTbl \
+ Organya \
+ PixTone \
+ Profile \
+ Sound \
+ Stage \
TextScr \
Triangle \
binary files a/build/data/Title.pbm b/build/data/Title.pbm differ
binary files /dev/null b/build/data/WAVE100.bin differ
binary files a/build/data/stage.tbl b/build/data/stage.tbl differ
--- /dev/null
+++ b/src/Back.cpp
@@ -1,0 +1,33 @@
+#include <SDL_rwops.h>
+#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;
+}
--- /dev/null
+++ b/src/Back.h
@@ -1,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);
--- a/src/Draw.cpp
+++ b/src/Draw.cpp
@@ -104,7 +104,7 @@
}
//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 @@
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 @@
//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 @@
//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 @@
//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 @@
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
--- a/src/Ending.cpp
+++ b/src/Ending.cpp
@@ -191,6 +191,7 @@
//Clear casts
memset(Strip, 0, sizeof(Strip));
+ SDL_RWclose(fp);
return true;
}
--- /dev/null
+++ b/src/Escape.cpp
@@ -1,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;
+}
--- /dev/null
+++ b/src/Escape.h
@@ -1,0 +1,2 @@
+#pragma once
+int Call_Escape();
--- a/src/Game.cpp
+++ b/src/Game.cpp
@@ -1,12 +1,23 @@
#include <string>
#include <stdlib.h>
+#include <SDL_timer.h>
+#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"
@@ -13,11 +24,387 @@
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())
@@ -24,7 +411,8 @@
{
char path[PATH_LENGTH];
sprintf(path, "%s/npc.tbl", gDataPath);
- if (LoadNpcTable(path))
+
+ if (LoadNpcTable(path) && InitStageTable())
{
InitTextScript2();
InitSkipFlags();
@@ -31,35 +419,22 @@
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
{
--- a/src/Generic.cpp
+++ b/src/Generic.cpp
@@ -1,5 +1,14 @@
#include <stdint.h>
+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 )
--- a/src/Generic.h
+++ b/src/Generic.h
@@ -1,4 +1,5 @@
#pragma once
#include <stdint.h>
+bool GetCompileVersion(int *v1, int *v2, int *v3, int *v4);
bool IsShiftJIS(uint8_t c);
--- 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 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 @@
if (Flip_SystemTask())
{
//Initialize sound
- //InitDirectSound();
+ InitDirectSound();
//Initialize joystick
if (config.bJoystick && InitDirectInput())
@@ -229,7 +231,7 @@
Game();
//End stuff
- //EndDirectSound();
+ EndDirectSound();
EndTextObject();
EndDirectDraw();
@@ -250,11 +252,11 @@
if (bActive)
{
bActive = false;
- //StopOrganyaMusic();
+ StopOrganyaMusic();
//SleepNoise();
}
- //PlaySoundObject(7, 0);
+ PlaySoundObject(7, 0);
}
void ActiveWindow()
@@ -262,12 +264,12 @@
if (!bActive)
{
bActive = true;
- //StopOrganyaMusic();
- //PlayOrganyaMusic();
+ StopOrganyaMusic();
+ PlayOrganyaMusic();
//ResetNoise();
}
- //PlaySoundObject(7, -1);
+ PlaySoundObject(7, -1);
}
void JoystickProc()
--- a/src/Map.cpp
+++ b/src/Map.cpp
@@ -1,7 +1,13 @@
#include <stdint.h>
#include <string>
+#include <SDL_rwops.h>
+#include "WindowsWrapper.h"
+
+#include "CommonDefines.h"
#include "Map.h"
+#include "Tags.h"
+#include "Draw.h"
#define PXM_BUFFER_SIZE 0x4B000
@@ -11,4 +17,252 @@
{
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);
+ }
+ }
+ }
}
--- a/src/Map.h
+++ b/src/Map.h
@@ -9,4 +9,18 @@
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);
--- /dev/null
+++ b/src/MapName.cpp
@@ -1,0 +1,73 @@
+#include <stdint.h>
+#include <string>
+
+#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);
+}
--- /dev/null
+++ b/src/MapName.h
@@ -1,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();
--- /dev/null
+++ b/src/NpChar.cpp
@@ -1,0 +1,12 @@
+#include <stdint.h>
+
+#include "NpChar.h"
+
+#define NPC_MAX 0x200
+
+NPCHAR gNPC[NPC_MAX];
+
+bool LoadEvent(char *path_event)
+{
+ return true;
+}
--- /dev/null
+++ b/src/NpChar.h
@@ -1,0 +1,43 @@
+#pragma once
+#include <stdint.h>
+#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);
--- a/src/NpcTbl.cpp
+++ b/src/NpcTbl.cpp
@@ -41,6 +41,13 @@
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);
}
--- a/src/NpcTbl.h
+++ b/src/NpcTbl.h
@@ -26,3 +26,4 @@
extern NPC_TABLE *gNpcTable;
bool LoadNpcTable(const char *path);
+void ReleaseNpcTable();
--- /dev/null
+++ b/src/Organya.cpp
@@ -1,0 +1,632 @@
+#include <stdint.h>
+
+#include <SDL_rwops.h>
+#include <SDL_thread.h>
+#include <SDL_timer.h>
+#include <SDL_events.h>
+#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);
+}
--- /dev/null
+++ b/src/Organya.h
@@ -1,0 +1,51 @@
+#pragma once
+#include <stdint.h>
+
+//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();
--- /dev/null
+++ b/src/PixTone.cpp
@@ -1,0 +1,288 @@
+#include <cstdio>
+#include <cstdlib>
+#include <stdint.h>
+#include <vector>
+#include <cstring>
+#include <math.h>
+
+#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<double>& 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<double> 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;
+}
--- /dev/null
+++ b/src/PixTone.h
@@ -1,0 +1,5 @@
+#pragma once
+#include <stdint.h>
+
+void MakeWaveTables();
+bool LoadPxt(char *name, uint8_t **buf, size_t *length);
--- /dev/null
+++ b/src/Profile.cpp
@@ -1,0 +1,24 @@
+#include <stdint.h>
+
+#include <SDL_rwops.h>
+#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;
+}
--- /dev/null
+++ b/src/Profile.h
@@ -1,0 +1,4 @@
+#pragma once
+#include <stdint.h>
+
+bool IsProfile();
--- /dev/null
+++ b/src/Sound.cpp
@@ -1,0 +1,324 @@
+#include <string>
+#include <math.h>
+#include <algorithm>
+#include <stdint.h>
+
+#include <SDL_audio.h>
+
+#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));
+}
--- /dev/null
+++ b/src/Sound.h
@@ -1,0 +1,96 @@
+#pragma once
+#include <stdint.h>
+
+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);
--- /dev/null
+++ b/src/Stage.cpp
@@ -1,0 +1,229 @@
+#include <stdint.h>
+#include <string.h>
+
+#include <SDL_rwops.h>
+#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;
+}
--- /dev/null
+++ b/src/Stage.h
@@ -1,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();
--- a/src/TextScr.cpp
+++ b/src/TextScr.cpp
@@ -1,8 +1,10 @@
#include <stdint.h>
#include <string>
+#include "CommonDefines.h"
#include "TextScr.h"
#include "Draw.h"
+#include "Tags.h"
#include "Game.h"
#define TSC_BUFFER_SIZE 0x5000
@@ -60,4 +62,43 @@
if ( i != half )
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;
}
--- a/src/TextScr.h
+++ b/src/TextScr.h
@@ -57,3 +57,4 @@
bool InitTextScript2();
void EndTextScript();
void EncryptionBinaryData2(uint8_t *pData, int size);
+bool LoadTextScript_Stage(char *name);