Org and sound
This commit is contained in:
parent
c84f49f1dc
commit
f43a3c1130
36 changed files with 2664 additions and 41 deletions
9
Makefile
9
Makefile
|
@ -20,9 +20,11 @@ LIBS += `sdl2-config --static-libs` -lSDL2_ttf -lfreetype -lharfbuzz -lfreetype
|
|||
|
||||
# For an accurate result to the original's code, compile in alphabetical order
|
||||
SOURCES = \
|
||||
Back \
|
||||
Config \
|
||||
Draw \
|
||||
Ending \
|
||||
Escape \
|
||||
Flags \
|
||||
Game \
|
||||
Generic \
|
||||
|
@ -31,7 +33,14 @@ SOURCES = \
|
|||
KeyControl \
|
||||
Main \
|
||||
Map \
|
||||
MapName \
|
||||
NpChar \
|
||||
NpcTbl \
|
||||
Organya \
|
||||
PixTone \
|
||||
Profile \
|
||||
Sound \
|
||||
Stage \
|
||||
TextScr \
|
||||
Triangle \
|
||||
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 7.6 KiB After Width: | Height: | Size: 16 KiB |
BIN
build/data/WAVE100.bin
Normal file
BIN
build/data/WAVE100.bin
Normal file
Binary file not shown.
Binary file not shown.
33
src/Back.cpp
Normal file
33
src/Back.cpp
Normal file
|
@ -0,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;
|
||||
}
|
16
src/Back.h
Normal file
16
src/Back.h
Normal file
|
@ -0,0 +1,16 @@
|
|||
#pragma once
|
||||
|
||||
struct BACK
|
||||
{
|
||||
int flag;
|
||||
int partsW;
|
||||
int partsH;
|
||||
int numX;
|
||||
int numY;
|
||||
int type;
|
||||
int fx;
|
||||
};
|
||||
|
||||
extern int gWaterY;
|
||||
|
||||
bool InitBack(char *fName, int type);
|
18
src/Draw.cpp
18
src/Draw.cpp
|
@ -104,7 +104,7 @@ bool MakeSurface(const char *name, int surf_no)
|
|||
}
|
||||
|
||||
//Make sure surface has color key on
|
||||
SDL_SetColorKey(surface, SDL_TRUE, 0x000000);
|
||||
SDL_SetColorKey(surface, SDL_TRUE, SDL_MapRGB(surface->format, 0, 0, 0));
|
||||
|
||||
//Get texture from surface
|
||||
SDL_Texture *texture = SDL_CreateTextureFromSurface(gRenderer, surface);
|
||||
|
@ -136,7 +136,8 @@ bool MakeSurface(const char *name, int surf_no)
|
|||
surf[surf_no].texture = textureAccessible;
|
||||
surf[surf_no].scale = true;
|
||||
|
||||
//Free surface
|
||||
//Free surface and texture
|
||||
SDL_DestroyTexture(texture);
|
||||
SDL_FreeSurface(surface);
|
||||
|
||||
printf(" ^ Successfully loaded\n");
|
||||
|
@ -239,7 +240,7 @@ void PutBitmap3(RECT *rcView, int x, int y, RECT *rect, int surf_no) //Transpare
|
|||
|
||||
//Draw to screen
|
||||
if (SDL_RenderCopy(gRenderer, surf[surf_no].texture, &frameRect, &destRect) < 0)
|
||||
printf(SDL_GetError());
|
||||
printf("Failed to draw texture %d\nSDL Error: %s\n", surf_no, SDL_GetError());
|
||||
|
||||
//Undo cliprect
|
||||
SDL_RenderSetClipRect(gRenderer, NULL);
|
||||
|
@ -272,7 +273,7 @@ void PutBitmap4(RECT *rcView, int x, int y, RECT *rect, int surf_no) //No Transp
|
|||
|
||||
//Draw texture
|
||||
if (SDL_RenderCopy(gRenderer, surf[surf_no].texture, &frameRect, &destRect) < 0)
|
||||
printf(SDL_GetError());
|
||||
printf("Failed to draw texture %d\nSDL Error: %s\n", surf_no, SDL_GetError());
|
||||
|
||||
//Restore original colour, and undo cliprect
|
||||
SDL_RenderSetClipRect(gRenderer, NULL);
|
||||
|
@ -297,7 +298,7 @@ void Surface2Surface(int x, int y, RECT *rect, int to, int from)
|
|||
|
||||
//Draw texture
|
||||
if (SDL_RenderCopy(gRenderer, surf[from].texture, &frameRect, &rcSet) < 0)
|
||||
printf(SDL_GetError());
|
||||
printf("Failed to draw texture %d to %d\nSDL Error: %s\n", from, to, SDL_GetError());
|
||||
|
||||
//Stop targetting surface
|
||||
SDL_SetRenderTarget(gRenderer, NULL);
|
||||
|
@ -329,8 +330,13 @@ void CortBox2(RECT *rect, uint32_t col, int surf_no)
|
|||
|
||||
SDL_SetRenderTarget(gRenderer, surf[surf_no].texture);
|
||||
|
||||
const unsigned char col_red = col & 0xFF0000 >> 16;
|
||||
const unsigned char col_green = col & 0x00FF00 >> 8;
|
||||
const unsigned char col_blue = col & 0x0000FF;
|
||||
const unsigned char col_alpha = (col_red || col_green || col_blue) ? 0xFF : 0;
|
||||
|
||||
//Set colour and draw
|
||||
SDL_SetRenderDrawColor(gRenderer, col & 0xFF0000 >> 16, col & 0x00FF00 >> 8, col & 0x0000FF, 0xFF);
|
||||
SDL_SetRenderDrawColor(gRenderer, col_red, col_green, col_blue, col_alpha);
|
||||
SDL_RenderFillRect(gRenderer, &destRect);
|
||||
|
||||
//Stop targetting surface
|
||||
|
|
|
@ -191,6 +191,7 @@ bool StartCreditScript()
|
|||
|
||||
//Clear casts
|
||||
memset(Strip, 0, sizeof(Strip));
|
||||
SDL_RWclose(fp);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
39
src/Escape.cpp
Normal file
39
src/Escape.cpp
Normal file
|
@ -0,0 +1,39 @@
|
|||
#include "WindowsWrapper.h"
|
||||
#include "Draw.h"
|
||||
#include "KeyControl.h"
|
||||
|
||||
int Call_Escape()
|
||||
{
|
||||
RECT rc = {0, 128, 208, 144};
|
||||
|
||||
while (Flip_SystemTask())
|
||||
{
|
||||
//Get pressed keys
|
||||
GetTrg();
|
||||
|
||||
if (gKeyTrg & 0x8000) //Escape is pressed, quit game
|
||||
{
|
||||
gKeyTrg = 0;
|
||||
return 0;
|
||||
}
|
||||
if (gKeyTrg & 0x400) //F1 is pressed, continue
|
||||
{
|
||||
gKeyTrg = 0;
|
||||
return 1;
|
||||
}
|
||||
if (gKeyTrg & 0x800) //F2 is pressed, reset
|
||||
{
|
||||
gKeyTrg = 0;
|
||||
return 2;
|
||||
}
|
||||
|
||||
//Draw screen
|
||||
CortBox(&grcFull, 0x000000);
|
||||
PutBitmap3(&grcFull, 56, 112, &rc, 26);
|
||||
//PutFramePerSecound();
|
||||
}
|
||||
|
||||
//Quit if window is closed
|
||||
gKeyTrg = 0;
|
||||
return 0;
|
||||
}
|
2
src/Escape.h
Normal file
2
src/Escape.h
Normal file
|
@ -0,0 +1,2 @@
|
|||
#pragma once
|
||||
int Call_Escape();
|
0
src/Frame.cpp
Normal file
0
src/Frame.cpp
Normal file
0
src/Frame.h
Normal file
0
src/Frame.h
Normal file
425
src/Game.cpp
425
src/Game.cpp
|
@ -1,65 +1,440 @@
|
|||
#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"
|
||||
|
||||
int g_GameFlags;
|
||||
int gCounter;
|
||||
|
||||
bool bContinue;
|
||||
|
||||
int Random(int min, int max)
|
||||
{
|
||||
return min + rand() % (max - min + 1);
|
||||
}
|
||||
|
||||
void PutNumber4(int x, int y, int value, bool bZero)
|
||||
{
|
||||
//Define rects
|
||||
RECT rcClient = grcFull;
|
||||
|
||||
RECT rect[10];
|
||||
rect[0] = {0, 56, 8, 64};
|
||||
rect[1] = {8, 56, 16, 64};
|
||||
rect[2] = {16, 56, 24, 64};
|
||||
rect[3] = {24, 56, 32, 64};
|
||||
rect[4] = {32, 56, 40, 64};
|
||||
rect[5] = {40, 56, 48, 64};
|
||||
rect[6] = {48, 56, 56, 64};
|
||||
rect[7] = {56, 56, 64, 64};
|
||||
rect[8] = {64, 56, 72, 64};
|
||||
rect[9] = {72, 56, 80, 64};
|
||||
|
||||
//Digits
|
||||
int tbl[4] = {1000, 100, 10, 1};
|
||||
|
||||
//Limit value
|
||||
if ( value > 9999 )
|
||||
value = 9999;
|
||||
|
||||
//Go through number and draw digits
|
||||
int offset = 0;
|
||||
int sw = 0;
|
||||
while (offset < 4)
|
||||
{
|
||||
//Get the digit that this is
|
||||
int a = 0;
|
||||
|
||||
while (tbl[offset] <= value)
|
||||
{
|
||||
value -= tbl[offset];
|
||||
++a;
|
||||
++sw;
|
||||
}
|
||||
|
||||
//Draw digit
|
||||
if ( bZero && offset == 2 || sw != 0 || offset == 3 )
|
||||
PutBitmap3(&rcClient, x + 8 * offset, y, &rect[a], SURFACE_ID_TEXT_BOX);
|
||||
|
||||
//Go to next digit
|
||||
++offset;
|
||||
}
|
||||
}
|
||||
|
||||
int ModeOpening()
|
||||
{
|
||||
//InitNpChar();
|
||||
//InitCaret();
|
||||
//InitStar();
|
||||
//InitFade();
|
||||
//InitFlash();
|
||||
//InitBossLife();
|
||||
ChangeMusic(0);
|
||||
TransferStage(72, 100, 3, 3);
|
||||
//SetFrameTargetMyChar(16);
|
||||
//SetFadeMask();
|
||||
|
||||
//Reset cliprect and flags
|
||||
grcGame.left = 0;
|
||||
g_GameFlags = 3;
|
||||
|
||||
//CutNoise();
|
||||
|
||||
int wait = 0;
|
||||
while (wait < 500)
|
||||
{
|
||||
//Increase timer
|
||||
++wait;
|
||||
|
||||
//Get pressed keys
|
||||
GetTrg();
|
||||
|
||||
//Escape menu
|
||||
if (gKey & 0x8000)
|
||||
{
|
||||
int escRet = Call_Escape();
|
||||
if (escRet == 0)
|
||||
return 0;
|
||||
if (escRet == 2)
|
||||
return 1;
|
||||
}
|
||||
|
||||
//Skip intro if OK is pressed
|
||||
if ( gKey & gKeyOk )
|
||||
break;
|
||||
|
||||
//Update everything
|
||||
//ActNpChar();
|
||||
//ActBossChar();
|
||||
//ActBack();
|
||||
//ResetMyCharFlag();
|
||||
//HitMyCharMap();
|
||||
//HitMyCharNpChar();
|
||||
//HitMyCharBoss();
|
||||
//HitNpCharMap();
|
||||
//HitBossMap();
|
||||
//HitBossBullet();
|
||||
//ActCaret();
|
||||
//MoveFrame3();
|
||||
//ProcFade();
|
||||
|
||||
//Draw everything
|
||||
CortBox(&grcFull, 0x000000);
|
||||
|
||||
int frame_x = 0;
|
||||
int frame_y = 0;
|
||||
//GetFramePosition(&frame_x, &frame_y);
|
||||
//PutBack(frame_x, frame_y);
|
||||
PutStage_Back(frame_x, frame_y);
|
||||
//PutBossChar(frame_x, frame_y);
|
||||
//PutNpChar(frame_x, frame_y);
|
||||
PutMapDataVector(frame_x, frame_y);
|
||||
PutStage_Front(frame_x, frame_y);
|
||||
//PutFront(frame_x, frame_y);
|
||||
//PutCaret(frame_x, frame_y);
|
||||
//PutFade();
|
||||
|
||||
//Update Text Script
|
||||
//int tscRet = TextScriptProc();
|
||||
//if (tscRet == 0)
|
||||
// return 0;
|
||||
//if (tscRet == 2)
|
||||
// return 1;
|
||||
|
||||
PutMapName(false);
|
||||
//PutTextScript();
|
||||
//PutFramePerSecound();
|
||||
|
||||
if (!Flip_SystemTask())
|
||||
return 0;
|
||||
|
||||
++gCounter;
|
||||
}
|
||||
|
||||
wait = SDL_GetTicks();
|
||||
while (SDL_GetTicks() < wait + 500)
|
||||
{
|
||||
CortBox(&grcGame, 0x000000);
|
||||
//PutFramePerSecound();
|
||||
if (!Flip_SystemTask())
|
||||
return 0;
|
||||
}
|
||||
return 2;
|
||||
}
|
||||
|
||||
int ModeTitle()
|
||||
{
|
||||
//Set rects
|
||||
RECT rcTitle = {0, 0, 144, 32};
|
||||
RECT rcPixel = {0, 0, 160, 16};
|
||||
|
||||
RECT rcNew = {144, 0, 192, 16};
|
||||
RECT rcContinue = {144, 16, 192, 32};
|
||||
|
||||
RECT rcVersion = {152, 80, 208, 88};
|
||||
RECT rcPeriod = {152, 88, 208, 96};
|
||||
|
||||
//Character rects
|
||||
RECT rcMyChar[4];
|
||||
RECT rcCurly[4];
|
||||
RECT rcToroko[4];
|
||||
RECT rcKing[4];
|
||||
RECT rcSu[4];
|
||||
|
||||
rcMyChar[0] = {0, 16, 16, 32};
|
||||
rcMyChar[1] = {16, 16, 32, 32};
|
||||
rcMyChar[2] = {0, 16, 16, 32};
|
||||
rcMyChar[3] = {32, 16, 48, 32};
|
||||
|
||||
rcCurly[0] = {0, 112, 16, 128};
|
||||
rcCurly[1] = {16, 112, 32, 128};
|
||||
rcCurly[2] = {0, 112, 16, 128};
|
||||
rcCurly[3] = {32, 112, 48, 128};
|
||||
|
||||
rcToroko[0] = {64, 80, 80, 96};
|
||||
rcToroko[1] = {80, 80, 96, 96};
|
||||
rcToroko[2] = {64, 80, 80, 96};
|
||||
rcToroko[3] = {96, 80, 112, 96};
|
||||
|
||||
rcKing[0] = {224, 48, 240, 64};
|
||||
rcKing[1] = {288, 48, 304, 64};
|
||||
rcKing[2] = {224, 48, 240, 64};
|
||||
rcKing[3] = {304, 48, 320, 64};
|
||||
|
||||
rcSu[0] = {0, 16, 16, 32};
|
||||
rcSu[1] = {32, 16, 48, 32};
|
||||
rcSu[2] = {0, 16, 16, 32};
|
||||
rcSu[3] = {48, 16, 64, 32};
|
||||
|
||||
//Reset everything
|
||||
//InitCaret();
|
||||
//InitStar();
|
||||
//CutNoise();
|
||||
|
||||
//Create variables
|
||||
int anime = 0;
|
||||
int char_type = 0;
|
||||
int time_counter = 0;
|
||||
|
||||
//Set state
|
||||
bContinue = IsProfile();
|
||||
|
||||
//Set character
|
||||
time_counter = 0;//LoadTimeCounter();
|
||||
|
||||
if (time_counter && time_counter < 18000)
|
||||
char_type = 1;
|
||||
if (time_counter && time_counter < 15000)
|
||||
char_type = 2;
|
||||
if (time_counter && time_counter < 12000)
|
||||
char_type = 3;
|
||||
if (time_counter && time_counter < 9000)
|
||||
char_type = 4;
|
||||
|
||||
//Set music to character's specific music
|
||||
switch (char_type)
|
||||
{
|
||||
case 1:
|
||||
ChangeMusic(mus_RunningHell);
|
||||
break;
|
||||
case 2:
|
||||
ChangeMusic(mus_TorokosTheme);
|
||||
break;
|
||||
case 3:
|
||||
ChangeMusic(mus_White);
|
||||
break;
|
||||
case 4:
|
||||
ChangeMusic(mus_Safety);
|
||||
break;
|
||||
default:
|
||||
ChangeMusic(mus_Geothermal);//mus_CaveStory);
|
||||
break;
|
||||
}
|
||||
|
||||
//Reset cliprect, flags, and give the player the booster 0.8?
|
||||
grcGame.left = 0;
|
||||
g_GameFlags = 0;
|
||||
|
||||
/*
|
||||
v0 = unk_81C8598;
|
||||
BYTE1(v0) |= 1u;
|
||||
unk_81C8598 = v0;
|
||||
*/
|
||||
|
||||
//Start loop
|
||||
int wait = 0;
|
||||
|
||||
while (true)
|
||||
{
|
||||
//Don't accept selection for 10 frames
|
||||
if (wait < 10)
|
||||
++wait;
|
||||
|
||||
//Get pressed keys
|
||||
GetTrg();
|
||||
|
||||
//Quit when OK is pressed
|
||||
if (wait >= 10)
|
||||
{
|
||||
if (gKeyTrg & gKeyOk)
|
||||
break;
|
||||
}
|
||||
|
||||
if (gKey & 0x8000)
|
||||
{
|
||||
int escRet = Call_Escape();
|
||||
if (escRet == 0)
|
||||
return 0;
|
||||
if (escRet == 2)
|
||||
return 1;
|
||||
}
|
||||
|
||||
//Move cursor
|
||||
if ((gKeyDown | gKeyUp) & gKeyTrg)
|
||||
{
|
||||
PlaySoundObject(1, 1);
|
||||
bContinue = !bContinue;
|
||||
}
|
||||
|
||||
//Update carets
|
||||
//ActCaret();
|
||||
|
||||
//Animate character cursor
|
||||
if ( ++anime >= 40 )
|
||||
anime = 0;
|
||||
|
||||
//Draw title
|
||||
CortBox(&grcGame, 0x202020);
|
||||
|
||||
//Draw version
|
||||
int v1, v2, v3, v4;
|
||||
PutBitmap3(&grcGame, 100, 216, &rcVersion, SURFACE_ID_TEXT_BOX);
|
||||
PutBitmap3(&grcGame, 156, 216, &rcPeriod, SURFACE_ID_TEXT_BOX);
|
||||
|
||||
GetCompileVersion(&v1, &v2, &v3, &v4);
|
||||
PutNumber4(140, 216, v1, 0);
|
||||
PutNumber4(156, 216, v2, 0);
|
||||
PutNumber4(172, 216, v3, 0);
|
||||
PutNumber4(188, 216, v4, 0);
|
||||
|
||||
//Draw main title
|
||||
PutBitmap3(&grcGame, 88, 40, &rcTitle, 0);
|
||||
PutBitmap3(&grcGame, 136, 128, &rcNew, 0);
|
||||
PutBitmap3(&grcGame, 136, 148, &rcContinue, 0);
|
||||
PutBitmap3(&grcGame, 80, 192, &rcPixel, 1);
|
||||
|
||||
//Draw character cursor
|
||||
RECT char_rc;
|
||||
int char_surf;
|
||||
|
||||
switch ( char_type )
|
||||
{
|
||||
case 0:
|
||||
char_rc = rcMyChar[anime / 10 % 4];
|
||||
char_surf = SURFACE_ID_MY_CHAR;
|
||||
break;
|
||||
case 1:
|
||||
char_rc = rcCurly[anime / 10 % 4];
|
||||
char_surf = SURFACE_ID_NPC_REGU;
|
||||
break;
|
||||
case 2:
|
||||
char_rc = rcToroko[anime / 10 % 4];
|
||||
char_surf = SURFACE_ID_NPC_REGU;
|
||||
break;
|
||||
case 3:
|
||||
char_rc = rcKing[anime / 10 % 4];
|
||||
char_surf = SURFACE_ID_NPC_REGU;
|
||||
break;
|
||||
case 4:
|
||||
char_rc = rcSu[anime / 10 % 4];
|
||||
char_surf = SURFACE_ID_NPC_REGU;
|
||||
break;
|
||||
}
|
||||
|
||||
int char_y;
|
||||
if (bContinue == 1)
|
||||
char_y = 147;
|
||||
else
|
||||
char_y = 127;
|
||||
|
||||
PutBitmap3(&grcGame, 116, char_y, &char_rc, char_surf);
|
||||
|
||||
//Draw carets
|
||||
//PutCaret(0, 0);
|
||||
|
||||
//if (time_counter)
|
||||
// PutTimeCounter(16, 8);
|
||||
|
||||
//PutFramePerSecound();
|
||||
|
||||
if (!Flip_SystemTask())
|
||||
return 0;
|
||||
}
|
||||
|
||||
PlaySoundObject(18, 1);
|
||||
ChangeMusic(0);
|
||||
|
||||
//Black screen when option is selected
|
||||
wait = SDL_GetTicks();
|
||||
while (SDL_GetTicks() < wait + 1000)
|
||||
{
|
||||
CortBox(&grcGame, 0);
|
||||
//PutFramePerSecound();
|
||||
if (!Flip_SystemTask())
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool Game()
|
||||
{
|
||||
if (LoadGenericData())
|
||||
{
|
||||
char path[PATH_LENGTH];
|
||||
sprintf(path, "%s/npc.tbl", gDataPath);
|
||||
if (LoadNpcTable(path))
|
||||
|
||||
if (LoadNpcTable(path) && InitStageTable())
|
||||
{
|
||||
InitTextScript2();
|
||||
InitSkipFlags();
|
||||
InitMapData2();
|
||||
InitCreditScript();
|
||||
|
||||
StartCreditScript();
|
||||
|
||||
while (Flip_SystemTask())
|
||||
{
|
||||
ActionCredit();
|
||||
ActionIllust();
|
||||
ActionStripper();
|
||||
CortBox(&grcFull, 0x000020);
|
||||
PutIllust();
|
||||
PutStripper();
|
||||
}
|
||||
|
||||
/*
|
||||
int mode = 0; //1;
|
||||
int mode = 1;
|
||||
while (mode)
|
||||
{
|
||||
//if ( mode == 1 )
|
||||
// mode = ModeOpening();
|
||||
//if ( mode == 2 )
|
||||
// mode = ModeTitle();
|
||||
//if ( mode == 3 )
|
||||
if (mode == 1)
|
||||
mode = ModeOpening();
|
||||
if (mode == 2)
|
||||
mode = ModeTitle();
|
||||
//if (mode == 3)
|
||||
// mode = ModeAction();
|
||||
}
|
||||
*/
|
||||
|
||||
//EndMapData();
|
||||
//EndTextScript();
|
||||
//ReleaseNpcTable();
|
||||
//ReleaseCreditScript();
|
||||
EndMapData();
|
||||
EndTextScript();
|
||||
ReleaseNpcTable();
|
||||
ReleaseStageTable();
|
||||
ReleaseCreditScript();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -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 )
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#pragma once
|
||||
#include <stdint.h>
|
||||
|
||||
bool GetCompileVersion(int *v1, int *v2, int *v3, int *v4);
|
||||
bool IsShiftJIS(uint8_t c);
|
||||
|
|
20
src/Main.cpp
20
src/Main.cpp
|
@ -9,6 +9,8 @@
|
|||
|
||||
#include "Draw.h"
|
||||
#include "Input.h"
|
||||
#include "Organya.h"
|
||||
#include "Sound.h"
|
||||
#include "Game.h"
|
||||
#include "Config.h"
|
||||
#include "KeyControl.h"
|
||||
|
@ -32,9 +34,9 @@ bool bFps;
|
|||
bool bActive;
|
||||
|
||||
#ifdef JAPANESE
|
||||
const char *lpWindowName = "洞窟物語エンジン";
|
||||
const char *lpWindowName = "洞窟物語エンジン2";
|
||||
#else
|
||||
const char *lpWindowName = "Cave Story Engine ~ Doukutsu Monogatari Enjin";
|
||||
const char *lpWindowName = "Cave Story Engine 2 ~ Doukutsu Monogatari Enjin 2";
|
||||
#endif
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
|
@ -212,7 +214,7 @@ int main(int argc, char *argv[])
|
|||
if (Flip_SystemTask())
|
||||
{
|
||||
//Initialize sound
|
||||
//InitDirectSound();
|
||||
InitDirectSound();
|
||||
|
||||
//Initialize joystick
|
||||
if (config.bJoystick && InitDirectInput())
|
||||
|
@ -229,7 +231,7 @@ int main(int argc, char *argv[])
|
|||
Game();
|
||||
|
||||
//End stuff
|
||||
//EndDirectSound();
|
||||
EndDirectSound();
|
||||
EndTextObject();
|
||||
EndDirectDraw();
|
||||
|
||||
|
@ -250,11 +252,11 @@ void InactiveWindow()
|
|||
if (bActive)
|
||||
{
|
||||
bActive = false;
|
||||
//StopOrganyaMusic();
|
||||
StopOrganyaMusic();
|
||||
//SleepNoise();
|
||||
}
|
||||
|
||||
//PlaySoundObject(7, 0);
|
||||
PlaySoundObject(7, 0);
|
||||
}
|
||||
|
||||
void ActiveWindow()
|
||||
|
@ -262,12 +264,12 @@ void ActiveWindow()
|
|||
if (!bActive)
|
||||
{
|
||||
bActive = true;
|
||||
//StopOrganyaMusic();
|
||||
//PlayOrganyaMusic();
|
||||
StopOrganyaMusic();
|
||||
PlayOrganyaMusic();
|
||||
//ResetNoise();
|
||||
}
|
||||
|
||||
//PlaySoundObject(7, -1);
|
||||
PlaySoundObject(7, -1);
|
||||
}
|
||||
|
||||
void JoystickProc()
|
||||
|
|
254
src/Map.cpp
254
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
|
||||
|
||||
|
@ -12,3 +18,251 @@ bool InitMapData2()
|
|||
gMap.data = (uint8_t*)malloc(PXM_BUFFER_SIZE);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LoadMapData2(char *path_map)
|
||||
{
|
||||
//Get path
|
||||
char path[PATH_LENGTH];
|
||||
sprintf(path, "%s/%s", gDataPath, path_map);
|
||||
|
||||
//Open file
|
||||
SDL_RWops *fp = SDL_RWFromFile(path, "rb");
|
||||
if (!fp)
|
||||
return false;
|
||||
|
||||
//Make sure file begins with "PXM"
|
||||
char check[3];
|
||||
fp->read(fp, check, 1, 3);
|
||||
|
||||
if (!memcmp(check, "PXM", 3))
|
||||
{
|
||||
uint8_t nul;
|
||||
fp->read(fp, &nul, 1, 1);
|
||||
|
||||
//Get width and height
|
||||
gMap.width = SDL_ReadLE16(fp);
|
||||
gMap.length = SDL_ReadLE16(fp);
|
||||
|
||||
if (gMap.data)
|
||||
{
|
||||
//Read tiledata
|
||||
fp->read(fp, gMap.data, 1, gMap.length * gMap.width);
|
||||
SDL_RWclose(fp);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
SDL_RWclose(fp);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SDL_RWclose(fp);
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool LoadAttributeData(char *path_atrb)
|
||||
{
|
||||
//Open file
|
||||
char path[260];
|
||||
sprintf(path, "%s/%s", gDataPath, path_atrb);
|
||||
|
||||
SDL_RWops *fp = SDL_RWFromFile(path, "rb");
|
||||
if (!fp)
|
||||
return false;
|
||||
|
||||
//Read data
|
||||
fp->read(fp, gMap.atrb, 1, 0x100);
|
||||
SDL_RWclose(fp);
|
||||
return true;
|
||||
}
|
||||
|
||||
void EndMapData()
|
||||
{
|
||||
if (gMap.data)
|
||||
free(gMap.data);
|
||||
}
|
||||
|
||||
void ReleasePartsImage()
|
||||
{
|
||||
ReleaseSurface(SURFACE_ID_LEVEL_TILESET);
|
||||
}
|
||||
|
||||
void GetMapData(uint8_t **data, int16_t *mw, int16_t *ml)
|
||||
{
|
||||
if (data)
|
||||
*data = gMap.data;
|
||||
if (mw)
|
||||
*mw = gMap.width;
|
||||
if (ml)
|
||||
*ml = gMap.length;
|
||||
}
|
||||
|
||||
int GetAttribute(int x, int y)
|
||||
{
|
||||
if (x >= 0 && y >= 0 && gMap.width > x && gMap.length > y)
|
||||
return gMap.atrb[gMap.data[y * gMap.width + x]];
|
||||
return false;
|
||||
}
|
||||
|
||||
void DeleteMapParts(int x, int y)
|
||||
{
|
||||
gMap.data[y * gMap.width + x] = 0;
|
||||
}
|
||||
|
||||
void ShiftMapParts(int x, int y)
|
||||
{
|
||||
--gMap.data[y * gMap.width + x];
|
||||
}
|
||||
|
||||
bool ChangeMapParts(int x, int y, uint8_t no)
|
||||
{
|
||||
if ( gMap.data[y * gMap.width + x] == no )
|
||||
return false;
|
||||
gMap.data[y * gMap.width + x] = no;
|
||||
//for (int i = 0; i <= 2; ++i )
|
||||
// SetNpChar(4, x << 13, y << 13, 0, 0, 0, 0, 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
void PutStage_Back(int fx, int fy)
|
||||
{
|
||||
//Get range to draw
|
||||
int num_x = WINDOW_WIDTH / 2 + 1;
|
||||
int num_y = WINDOW_HEIGHT / 2 + 1;
|
||||
int put_x = (fx / 0x200 + 8) / 16;
|
||||
int put_y = (fy / 0x200 + 8) / 16;
|
||||
|
||||
for (int j = put_y; put_y + num_y > j; j++)
|
||||
{
|
||||
for (int i = put_x; put_x + num_x > i; i++)
|
||||
{
|
||||
//Get attribute
|
||||
int offset = i + j * gMap.width;
|
||||
int atrb = GetAttribute(i, j);
|
||||
|
||||
if (atrb < 0x20)
|
||||
{
|
||||
//Draw tile
|
||||
RECT rect;
|
||||
rect.left = 16 * (gMap.data[offset] & 0xF);
|
||||
rect.top = 16 * (gMap.data[offset] >> 4);
|
||||
rect.right = rect.left + 16;
|
||||
rect.bottom = rect.top + 16;
|
||||
|
||||
PutBitmap3(&grcGame, 8 * (2 * i - 1) - fx / 0x200, 8 * (2 * j - 1) - fy / 0x200, &rect, SURFACE_ID_LEVEL_TILESET);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PutStage_Front(int fx, int fy)
|
||||
{
|
||||
RECT rcSnack = {256, 48, 272, 64};
|
||||
|
||||
//Get range to draw
|
||||
int num_x = WINDOW_WIDTH / 2 + 1;
|
||||
int num_y = WINDOW_HEIGHT / 2 + 1;
|
||||
int put_x = (fx / 0x200 + 8) / 16;
|
||||
int put_y = (fy / 0x200 + 8) / 16;
|
||||
|
||||
for (int j = put_y; put_y + num_y > j; j++)
|
||||
{
|
||||
for (int i = put_x; put_x + num_x > i; i++)
|
||||
{
|
||||
//Get attribute
|
||||
int offset = i + j * gMap.width;
|
||||
int atrb = GetAttribute(i, j);
|
||||
|
||||
if (atrb >= 0x40 && atrb < 0x80)
|
||||
{
|
||||
//Draw tile
|
||||
RECT rect;
|
||||
rect.left = 16 * (gMap.data[offset] & 0xF);
|
||||
rect.top = 16 * (gMap.data[offset] >> 4);
|
||||
rect.right = rect.left + 16;
|
||||
rect.bottom = rect.top + 16;
|
||||
|
||||
PutBitmap3(&grcGame, 8 * (2 * i - 1) - fx / 0x200, 8 * (2 * j - 1) - fy / 0x200, &rect, SURFACE_ID_LEVEL_TILESET);
|
||||
|
||||
if (atrb == 0x43)
|
||||
PutBitmap3(&grcGame, 8 * (2 * i - 1) - fx / 0x200, 8 * (2 * j - 1) - fy / 0x200, &rcSnack, SURFACE_ID_NPC_SYM);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PutMapDataVector(int fx, int fy)
|
||||
{
|
||||
//Get range to draw
|
||||
int num_x = WINDOW_WIDTH / 2 + 1;
|
||||
int num_y = WINDOW_HEIGHT / 2 + 1;
|
||||
int put_x = (fx / 0x200 + 8) / 16;
|
||||
int put_y = (fy / 0x200 + 8) / 16;
|
||||
|
||||
//Animate the wind
|
||||
static int count = 0;
|
||||
count++;
|
||||
|
||||
for (int j = put_y; put_y + num_y > j; j++)
|
||||
{
|
||||
for (int i = put_x; put_x + num_x > i; i++)
|
||||
{
|
||||
//Get attribute
|
||||
int offset = i + j * gMap.width;
|
||||
int atrb = GetAttribute(i, j);
|
||||
|
||||
if ( atrb == 0x80
|
||||
|| atrb == 0x81
|
||||
|| atrb == 0x82
|
||||
|| atrb == 0x83
|
||||
|| atrb == 0xA0
|
||||
|| atrb == 0xA1
|
||||
|| atrb == 0xA2
|
||||
|| atrb == 0xA3)
|
||||
{
|
||||
RECT rect;
|
||||
|
||||
switch ( atrb )
|
||||
{
|
||||
case 128:
|
||||
case 160:
|
||||
rect.left = (count & 0xF) + 224;
|
||||
rect.right = (count & 0xF) + 240;
|
||||
rect.top = 48;
|
||||
rect.bottom = 64;
|
||||
break;
|
||||
case 129:
|
||||
case 161:
|
||||
rect.left = 224;
|
||||
rect.right = 240;
|
||||
rect.top = (count & 0xF) + 48;
|
||||
rect.bottom = (count & 0xF) + 64;
|
||||
break;
|
||||
case 130:
|
||||
case 162:
|
||||
rect.left = 240 - (count & 0xF);
|
||||
rect.right = rect.left + 16;
|
||||
rect.top = 48;
|
||||
rect.bottom = 64;
|
||||
break;
|
||||
case 131:
|
||||
case 163:
|
||||
rect.left = 224;
|
||||
rect.right = 240;
|
||||
rect.top = 64 - (count & 0xF);
|
||||
rect.bottom = rect.top + 16;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
PutBitmap3(&grcGame, 8 * (2 * i - 1) - fx / 0x200, 8 * (2 * j - 1) - fy / 0x200, &rect, SURFACE_ID_CARET);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
14
src/Map.h
14
src/Map.h
|
@ -9,4 +9,18 @@ struct MAP_DATA
|
|||
int16_t length;
|
||||
};
|
||||
|
||||
extern MAP_DATA gMap;
|
||||
|
||||
bool InitMapData2();
|
||||
bool LoadMapData2(char *path_map);
|
||||
bool LoadAttributeData(char *path_atrb);
|
||||
void EndMapData();
|
||||
void ReleasePartsImage();
|
||||
void GetMapData(uint8_t **data, int16_t *mw, int16_t *ml);
|
||||
int GetAttribute(int x, int y);
|
||||
void DeleteMapParts(int x, int y);
|
||||
void ShiftMapParts(int x, int y);
|
||||
bool ChangeMapParts(int x, int y, uint8_t no);
|
||||
void PutStage_Back(int fx, int fy);
|
||||
void PutStage_Front(int fx, int fy);
|
||||
void PutMapDataVector(int fx, int fy);
|
||||
|
|
73
src/MapName.cpp
Normal file
73
src/MapName.cpp
Normal file
|
@ -0,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);
|
||||
}
|
12
src/MapName.h
Normal file
12
src/MapName.h
Normal file
|
@ -0,0 +1,12 @@
|
|||
#pragma once
|
||||
struct MAP_NAME
|
||||
{
|
||||
int flag;
|
||||
int wait;
|
||||
char name[0x20];
|
||||
};
|
||||
|
||||
void ReadyMapName(char *str);
|
||||
void PutMapName(bool bMini);
|
||||
void StartMapName();
|
||||
void RestoreMapName();
|
12
src/NpChar.cpp
Normal file
12
src/NpChar.cpp
Normal file
|
@ -0,0 +1,12 @@
|
|||
#include <stdint.h>
|
||||
|
||||
#include "NpChar.h"
|
||||
|
||||
#define NPC_MAX 0x200
|
||||
|
||||
NPCHAR gNPC[NPC_MAX];
|
||||
|
||||
bool LoadEvent(char *path_event)
|
||||
{
|
||||
return true;
|
||||
}
|
43
src/NpChar.h
Normal file
43
src/NpChar.h
Normal file
|
@ -0,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);
|
|
@ -41,6 +41,13 @@ bool LoadNpcTable(const char *path)
|
|||
fp->read(fp, &gNpcTable[i].hit, 4, 1);
|
||||
for (size_t i = 0; i < npcCount; i++) //view
|
||||
fp->read(fp, &gNpcTable[i].view, 4, 1);
|
||||
|
||||
|
||||
SDL_RWclose(fp);
|
||||
return true;
|
||||
}
|
||||
|
||||
void ReleaseNpcTable()
|
||||
{
|
||||
if (gNpcTable)
|
||||
free(gNpcTable);
|
||||
}
|
||||
|
|
|
@ -26,3 +26,4 @@ struct NPC_TABLE
|
|||
extern NPC_TABLE *gNpcTable;
|
||||
|
||||
bool LoadNpcTable(const char *path);
|
||||
void ReleaseNpcTable();
|
||||
|
|
632
src/Organya.cpp
Normal file
632
src/Organya.cpp
Normal file
|
@ -0,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);
|
||||
}
|
51
src/Organya.h
Normal file
51
src/Organya.h
Normal file
|
@ -0,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();
|
288
src/PixTone.cpp
Normal file
288
src/PixTone.cpp
Normal file
|
@ -0,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;
|
||||
}
|
5
src/PixTone.h
Normal file
5
src/PixTone.h
Normal file
|
@ -0,0 +1,5 @@
|
|||
#pragma once
|
||||
#include <stdint.h>
|
||||
|
||||
void MakeWaveTables();
|
||||
bool LoadPxt(char *name, uint8_t **buf, size_t *length);
|
24
src/Profile.cpp
Normal file
24
src/Profile.cpp
Normal file
|
@ -0,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;
|
||||
}
|
4
src/Profile.h
Normal file
4
src/Profile.h
Normal file
|
@ -0,0 +1,4 @@
|
|||
#pragma once
|
||||
#include <stdint.h>
|
||||
|
||||
bool IsProfile();
|
324
src/Sound.cpp
Normal file
324
src/Sound.cpp
Normal file
|
@ -0,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));
|
||||
}
|
96
src/Sound.h
Normal file
96
src/Sound.h
Normal file
|
@ -0,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);
|
229
src/Stage.cpp
Normal file
229
src/Stage.cpp
Normal file
|
@ -0,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;
|
||||
}
|
19
src/Stage.h
Normal file
19
src/Stage.h
Normal file
|
@ -0,0 +1,19 @@
|
|||
#pragma once
|
||||
|
||||
struct STAGE_TABLE
|
||||
{
|
||||
char parts[0x20];
|
||||
char map[0x20];
|
||||
int bkType;
|
||||
char back[0x20];
|
||||
char npc[0x20];
|
||||
char boss[0x20];
|
||||
char boss_no;
|
||||
char name[0x20];
|
||||
};
|
||||
|
||||
bool InitStageTable();
|
||||
void ReleaseStageTable();
|
||||
bool TransferStage(int no, int w, int x, int y);
|
||||
void ChangeMusic(int no);
|
||||
void ReCallMusic();
|
|
@ -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
|
||||
|
@ -61,3 +63,42 @@ void EncryptionBinaryData2(uint8_t *pData, int size)
|
|||
pData[i] += val1;
|
||||
}
|
||||
}
|
||||
|
||||
//Load stage .tsc
|
||||
bool LoadTextScript_Stage(char *name)
|
||||
{
|
||||
//Open Head.tsc
|
||||
char path[PATH_LENGTH];
|
||||
sprintf(path, "%s/%s", gDataPath, "Head.tsc");
|
||||
|
||||
SDL_RWops *fp = SDL_RWFromFile(path, "rb");
|
||||
if (!fp)
|
||||
return false;
|
||||
|
||||
//Read Head.tsc
|
||||
int head_size = SDL_RWsize(fp);
|
||||
|
||||
fp->read(fp, gTS.data, 1, head_size);
|
||||
EncryptionBinaryData2((uint8_t*)gTS.data, head_size);
|
||||
gTS.data[head_size] = 0;
|
||||
SDL_RWclose(fp);
|
||||
|
||||
//Open stage's .tsc
|
||||
sprintf(path, "%s/%s", gDataPath, name);
|
||||
|
||||
fp = SDL_RWFromFile(path, "rb");
|
||||
if (!fp)
|
||||
return false;
|
||||
|
||||
//Read stage's tsc
|
||||
int body_size = SDL_RWsize(fp);
|
||||
fp->read(fp, &gTS.data[head_size], 1, body_size);
|
||||
EncryptionBinaryData2((uint8_t*)&gTS.data[head_size], body_size);
|
||||
gTS.data[head_size + body_size] = 0;
|
||||
SDL_RWclose(fp);
|
||||
|
||||
//Set parameters
|
||||
gTS.size = head_size + body_size;
|
||||
strcpy(gTS.path, name);
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -57,3 +57,4 @@ struct TEXT_SCRIPT
|
|||
bool InitTextScript2();
|
||||
void EndTextScript();
|
||||
void EncryptionBinaryData2(uint8_t *pData, int size);
|
||||
bool LoadTextScript_Stage(char *name);
|
||||
|
|
Loading…
Add table
Reference in a new issue