shithub: cstory

Download patch

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);