mirror of
https://github.com/thornAvery/kep-hack.git
synced 2025-11-14 09:06:41 +13:00
Merge stag019/pokered
hg-commit-id: 601e69ebe196
This commit is contained in:
commit
5ca3748f4c
|
|
@ -89,9 +89,36 @@ TX_RAM: MACRO
|
|||
|
||||
; wram locations
|
||||
|
||||
; coordinates of the position of the cursor for the top menu item (id 0)
|
||||
W_TOPMENUITEMY EQU $CC24
|
||||
W_TOPMENUITEMX EQU $CC25
|
||||
|
||||
; the id of the currently selected menu item
|
||||
; the top item has id 0, the one below that has id 1, etc.
|
||||
W_CURMENUITEMID EQU $CC26
|
||||
|
||||
; the tile that was behind the menu cursor's current location
|
||||
W_TILEBEHINDCURSOR EQU $CC27
|
||||
|
||||
W_MAXMENUITEMID EQU $CC28 ; id of the bottom menu item
|
||||
|
||||
W_MENUWATCHEDKEYS EQU $CC29 ; bit mask of keys that the menu will respond to
|
||||
|
||||
W_OLDMENUITEMID EQU $CC2A ; id of previously selected menu item
|
||||
|
||||
; how many times should HandleMenuInput poll the joypad state before it returns?
|
||||
W_MENUJOYPADPOLLCOUNT EQU $CC34
|
||||
|
||||
W_PLAYERMOVELISTINDEX EQU $CC2E
|
||||
W_PLAYERMONNUMBER EQU $CC2F
|
||||
|
||||
; the address of the menu cursor's current location within C3A0-C507
|
||||
W_MENUCURSORLOCATION EQU $CC30 ; 2 bytes
|
||||
|
||||
; set to 1 if you can go from the bottom to the top or top to bottom of a menu
|
||||
; set to 0 if you can't go past the top or bottom of the menu
|
||||
W_MENUWRAPPINGENABLED EQU $CC4A
|
||||
|
||||
; current HP of player and enemy substitutes
|
||||
W_PLAYERSUBSITUTEHP EQU $CCD7
|
||||
W_ENEMYSUBSITUTEHP EQU $CCD8
|
||||
|
|
@ -699,6 +726,10 @@ W_BOXITEM50QTY EQU $D59E
|
|||
W_SAFARITIMER1 EQU $D70D ; use 01 for maximum
|
||||
W_SAFARITIMER2 EQU $D70E ; use F4 for maximum
|
||||
|
||||
; counters for blinking down arrow
|
||||
H_DOWNARROWBLINKCNT1 EQU $FF8B
|
||||
H_DOWNARROWBLINKCNT2 EQU $FF8C
|
||||
|
||||
; Note: the following multiplication and division addresses are used for multiple purposes
|
||||
; and so they overlap with each other
|
||||
|
||||
|
|
|
|||
333
main.asm
333
main.asm
|
|
@ -4847,7 +4847,338 @@ AddNTimes: ; 3A87
|
|||
jr nz,.loop\@
|
||||
ret
|
||||
|
||||
INCBIN "baserom.gbc",$3A8E,$3C49 - $3A8E
|
||||
; Compare strings, c bytes in length, at de and hl.
|
||||
; Often used to compare big endian numbers in battle calculations.
|
||||
StringCmp: ; 3A8E
|
||||
ld a,[de]
|
||||
cp [hl]
|
||||
ret nz
|
||||
inc de
|
||||
inc hl
|
||||
dec c
|
||||
jr nz,StringCmp
|
||||
ret
|
||||
|
||||
; INPUT:
|
||||
; a = oam block index (each block is 4 oam entries)
|
||||
; b = Y coordinate of upper left corner of sprite
|
||||
; c = X coordinate of upper left corner of sprite
|
||||
; de = base address of 4 tile number and attribute pairs
|
||||
WriteOAMBlock: ; 3A97
|
||||
ld h,$c3
|
||||
swap a ; multiply by 16
|
||||
ld l,a
|
||||
call .writeOneEntry\@ ; upper left
|
||||
push bc
|
||||
ld a,8
|
||||
add c
|
||||
ld c,a
|
||||
call .writeOneEntry\@ ; upper right
|
||||
pop bc
|
||||
ld a,8
|
||||
add b
|
||||
ld b,a
|
||||
call .writeOneEntry\@ ; lower left
|
||||
ld a,8
|
||||
add c
|
||||
ld c,a
|
||||
; lower right
|
||||
.writeOneEntry\@
|
||||
ld [hl],b ; Y coordinate
|
||||
inc hl
|
||||
ld [hl],c ; X coordinate
|
||||
inc hl
|
||||
ld a,[de] ; tile number
|
||||
inc de
|
||||
ld [hli],a
|
||||
ld a,[de] ; attribute
|
||||
inc de
|
||||
ld [hli],a
|
||||
ret
|
||||
|
||||
HandleMenuInput: ; 3ABE
|
||||
xor a
|
||||
ld [$d09b],a
|
||||
|
||||
HandleMenuInputPokemonSelection: ; 3AC2
|
||||
ld a,[H_DOWNARROWBLINKCNT1]
|
||||
push af
|
||||
ld a,[H_DOWNARROWBLINKCNT2]
|
||||
push af ; save existing values on stack
|
||||
xor a
|
||||
ld [H_DOWNARROWBLINKCNT1],a ; blinking down arrow timing value 1
|
||||
ld a,$06
|
||||
ld [H_DOWNARROWBLINKCNT2],a ; blinking down arrow timing value 2
|
||||
.loop1\@
|
||||
xor a
|
||||
ld [$d08b],a ; counter for pokemon shaking animation
|
||||
call PlaceMenuCursor
|
||||
call Delay3
|
||||
.loop2\@
|
||||
push hl
|
||||
ld a,[$d09b]
|
||||
and a ; is it a pokemon selection menu?
|
||||
jr z,.getJoypadState\@
|
||||
ld b,$1c
|
||||
ld hl,$56ff ; shake mini sprite of selected pokemon
|
||||
call Bankswitch
|
||||
.getJoypadState\@
|
||||
pop hl
|
||||
call GetJoypadStateLowSensitivity
|
||||
ld a,[$ffb5]
|
||||
and a ; was a key pressed?
|
||||
jr nz,.keyPressed\@
|
||||
push hl
|
||||
FuncCoord 18,11 ; coordinates of blinking down arrow in some menus
|
||||
ld hl,Coord
|
||||
call $3c04 ; blink down arrow (if any)
|
||||
pop hl
|
||||
ld a,[W_MENUJOYPADPOLLCOUNT]
|
||||
dec a
|
||||
jr z,.giveUpWaiting\@
|
||||
jr .loop2\@
|
||||
.giveUpWaiting\@
|
||||
; if a key wasn't pressed within the specified number of checks
|
||||
pop af
|
||||
ld [H_DOWNARROWBLINKCNT2],a
|
||||
pop af
|
||||
ld [H_DOWNARROWBLINKCNT1],a ; restore previous values
|
||||
xor a
|
||||
ld [W_MENUWRAPPINGENABLED],a ; disable menu wrapping
|
||||
ret
|
||||
.keyPressed\@
|
||||
xor a
|
||||
ld [$cc4b],a
|
||||
ld a,[$ffb5]
|
||||
ld b,a
|
||||
bit 6,a ; pressed Up key?
|
||||
jr z,.checkIfDownPressed\@
|
||||
.upPressed\@
|
||||
ld a,[W_CURMENUITEMID] ; selected menu item
|
||||
and a ; already at the top of the menu?
|
||||
jr z,.alreadyAtTop\@
|
||||
.notAtTop\@
|
||||
dec a
|
||||
ld [W_CURMENUITEMID],a ; move selected menu item up one space
|
||||
jr .checkOtherKeys\@
|
||||
.alreadyAtTop\@
|
||||
ld a,[W_MENUWRAPPINGENABLED]
|
||||
and a ; is wrapping around enabled?
|
||||
jr z,.noWrappingAround\@
|
||||
ld a,[W_MAXMENUITEMID]
|
||||
ld [W_CURMENUITEMID],a ; wrap to the bottom of the menu
|
||||
jr .checkOtherKeys\@
|
||||
.checkIfDownPressed\@
|
||||
bit 7,a
|
||||
jr z,.checkOtherKeys\@
|
||||
.downPressed\@
|
||||
ld a,[W_CURMENUITEMID]
|
||||
inc a
|
||||
ld c,a
|
||||
ld a,[W_MAXMENUITEMID]
|
||||
cp c
|
||||
jr nc,.notAtBottom\@
|
||||
.alreadyAtBottom\@
|
||||
ld a,[W_MENUWRAPPINGENABLED]
|
||||
and a ; is wrapping around enabled?
|
||||
jr z,.noWrappingAround\@
|
||||
ld c,$00 ; wrap from bottom to top
|
||||
.notAtBottom\@
|
||||
ld a,c
|
||||
ld [W_CURMENUITEMID],a
|
||||
.checkOtherKeys\@
|
||||
ld a,[W_MENUWATCHEDKEYS]
|
||||
and b ; does the menu care about any of the pressed keys?
|
||||
jp z,.loop1\@
|
||||
.checkIfAButtonOrBButtonPressed\@
|
||||
ld a,[$ffb5]
|
||||
and a,%00000011 ; pressed A button or B button?
|
||||
jr z,.skipPlayingSound\@
|
||||
.AButtonOrBButtonPressed\@
|
||||
push hl
|
||||
ld hl,$cd60
|
||||
bit 5,[hl]
|
||||
pop hl
|
||||
jr nz,.skipPlayingSound\@
|
||||
ld a,$90
|
||||
call $23b1 ; play sound
|
||||
.skipPlayingSound\@
|
||||
pop af
|
||||
ld [H_DOWNARROWBLINKCNT2],a
|
||||
pop af
|
||||
ld [H_DOWNARROWBLINKCNT1],a ; restore previous values
|
||||
xor a
|
||||
ld [W_MENUWRAPPINGENABLED],a ; disable menu wrapping
|
||||
ld a,[$ffb5]
|
||||
ret
|
||||
.noWrappingAround\@
|
||||
ld a,[$cc37]
|
||||
and a ; should we return if the user tried to go past the top or bottom?
|
||||
jr z,.checkOtherKeys\@
|
||||
jr .checkIfAButtonOrBButtonPressed\@
|
||||
|
||||
PlaceMenuCursor: ; 3B7C
|
||||
ld a,[W_TOPMENUITEMY]
|
||||
and a ; is the y coordinate 0?
|
||||
jr z,.adjustForXCoord\@
|
||||
ld hl,$c3a0
|
||||
ld bc,20 ; screen width
|
||||
.topMenuItemLoop\@
|
||||
add hl,bc
|
||||
dec a
|
||||
jr nz,.topMenuItemLoop\@
|
||||
.adjustForXCoord\@
|
||||
ld a,[W_TOPMENUITEMX]
|
||||
ld b,$00
|
||||
ld c,a
|
||||
add hl,bc
|
||||
push hl
|
||||
ld a,[W_OLDMENUITEMID]
|
||||
and a ; was the previous menu id 0?
|
||||
jr z,.checkForArrow1\@
|
||||
push af
|
||||
ld a,[$fff6]
|
||||
bit 1,a ; is the menu double spaced?
|
||||
jr z,.doubleSpaced1\@
|
||||
ld bc,20
|
||||
jr .getOldMenuItemScreenPosition\@
|
||||
.doubleSpaced1\@
|
||||
ld bc,40
|
||||
.getOldMenuItemScreenPosition\@
|
||||
pop af
|
||||
.oldMenuItemLoop\@
|
||||
add hl,bc
|
||||
dec a
|
||||
jr nz,.oldMenuItemLoop\@
|
||||
.checkForArrow1\@
|
||||
ld a,[hl]
|
||||
cp a,$ed ; was an arrow next to the previously selected menu item?
|
||||
jr nz,.skipClearingArrow\@
|
||||
.clearArrow\@
|
||||
ld a,[W_TILEBEHINDCURSOR]
|
||||
ld [hl],a
|
||||
.skipClearingArrow\@
|
||||
pop hl
|
||||
ld a,[W_CURMENUITEMID]
|
||||
and a
|
||||
jr z,.checkForArrow2\@
|
||||
push af
|
||||
ld a,[$fff6]
|
||||
bit 1,a ; is the menu double spaced?
|
||||
jr z,.doubleSpaced2\@
|
||||
ld bc,20
|
||||
jr .getCurrentMenuItemScreenPosition\@
|
||||
.doubleSpaced2\@
|
||||
ld bc,40
|
||||
.getCurrentMenuItemScreenPosition\@
|
||||
pop af
|
||||
.currentMenuItemLoop\@
|
||||
add hl,bc
|
||||
dec a
|
||||
jr nz,.currentMenuItemLoop\@
|
||||
.checkForArrow2\@
|
||||
ld a,[hl]
|
||||
cp a,$ed ; has the right arrow already been placed?
|
||||
jr z,.skipSavingTile\@ ; if so, don't lose the saved tile
|
||||
ld [W_TILEBEHINDCURSOR],a ; save tile before overwriting with right arrow
|
||||
.skipSavingTile\@
|
||||
ld a,$ed ; place right arrow
|
||||
ld [hl],a
|
||||
ld a,l
|
||||
ld [W_MENUCURSORLOCATION],a
|
||||
ld a,h
|
||||
ld [W_MENUCURSORLOCATION + 1],a
|
||||
ld a,[W_CURMENUITEMID]
|
||||
ld [W_OLDMENUITEMID],a
|
||||
ret
|
||||
|
||||
; Used when swapping positions of items in a list menu.
|
||||
; The item that the user selects first is marked with an outline of a right arrow
|
||||
; to distinguish it from the arrow being used to select the second item.
|
||||
PlaceUnfilledArrowMenuCursor: ; 3BEC
|
||||
ld b,a
|
||||
ld a,[W_MENUCURSORLOCATION]
|
||||
ld l,a
|
||||
ld a,[W_MENUCURSORLOCATION + 1]
|
||||
ld h,a
|
||||
ld [hl],$ec ; outline of right arrow
|
||||
ld a,b
|
||||
ret
|
||||
|
||||
; Replaces the menu cursor with a blank space.
|
||||
EraseMenuCursor: ; 3BF9
|
||||
ld a,[W_MENUCURSORLOCATION]
|
||||
ld l,a
|
||||
ld a,[W_MENUCURSORLOCATION + 1]
|
||||
ld h,a
|
||||
ld [hl],$7f ; blank space
|
||||
ret
|
||||
|
||||
; This toggles a blinking down arrow at hl on and off after a delay has passed.
|
||||
; This is often called even when no blinking is occurring.
|
||||
; The reason is that most functions that call this initialize H_DOWNARROWBLINKCNT1 to 0.
|
||||
; The effect is that if the tile at hl is initialized with a down arrow,
|
||||
; this function will toggle that down arrow on and off, but if the tile isn't
|
||||
; initliazed with a down arrow, this function does nothing.
|
||||
; That allows this to be called without worrying about if a down arrow should
|
||||
; be blinking.
|
||||
HandleDownArrowBlinkTiming: ; 3C04
|
||||
ld a,[hl]
|
||||
ld b,a
|
||||
ld a,$ee ; down arrow
|
||||
cp b
|
||||
jr nz,.downArrowOff\@
|
||||
.downArrowOn\@
|
||||
ld a,[H_DOWNARROWBLINKCNT1]
|
||||
dec a
|
||||
ld [H_DOWNARROWBLINKCNT1],a
|
||||
ret nz
|
||||
ld a,[H_DOWNARROWBLINKCNT2]
|
||||
dec a
|
||||
ld [H_DOWNARROWBLINKCNT2],a
|
||||
ret nz
|
||||
ld a,$7f ; blank space
|
||||
ld [hl],a
|
||||
ld a,$ff
|
||||
ld [H_DOWNARROWBLINKCNT1],a
|
||||
ld a,$06
|
||||
ld [H_DOWNARROWBLINKCNT2],a
|
||||
ret
|
||||
.downArrowOff\@
|
||||
ld a,[H_DOWNARROWBLINKCNT1]
|
||||
and a
|
||||
ret z
|
||||
dec a
|
||||
ld [H_DOWNARROWBLINKCNT1],a
|
||||
ret nz
|
||||
dec a
|
||||
ld [H_DOWNARROWBLINKCNT1],a
|
||||
ld a,[H_DOWNARROWBLINKCNT2]
|
||||
dec a
|
||||
ld [H_DOWNARROWBLINKCNT2],a
|
||||
ret nz
|
||||
ld a,$06
|
||||
ld [H_DOWNARROWBLINKCNT2],a
|
||||
ld a,$ee ; down arrow
|
||||
ld [hl],a
|
||||
ret
|
||||
|
||||
; The following code either enables or disables the automatic drawing of
|
||||
; text boxes by DisplayTextID. Both functions cause DisplayTextID to wait
|
||||
; for a button press after displaying text (unless [$cc47] is set).
|
||||
|
||||
EnableAutoTextBoxDrawing: ; 3C3C
|
||||
xor a
|
||||
jr AutoTextBoxDrawingCommon
|
||||
|
||||
DisableAutoTextBoxDrawing: ; 3C3F
|
||||
ld a,$01
|
||||
|
||||
AutoTextBoxDrawingCommon: ; 3C41
|
||||
ld [$cf0c],a ; control text box drawing
|
||||
xor a
|
||||
ld [$cc3c],a ; make DisplayTextID wait for button press
|
||||
ret
|
||||
|
||||
PrintText: ; 3C49
|
||||
; given a pointer in hl, print the text there
|
||||
|
|
|
|||
|
|
@ -10,12 +10,12 @@ public:
|
|||
AbstractData();
|
||||
|
||||
virtual std::string GenAsm(); // Generate Assembly Output
|
||||
virtual bool IsValid(unsigned char* byte); // Check for byte validity
|
||||
virtual bool Parse(unsigned char* byte); // Parse Given Data
|
||||
virtual unsigned int Arguments(); // Number of arguments taken
|
||||
|
||||
virtual bool GetError(); // Get Error (No Write, Error is read only)
|
||||
|
||||
virtual bool IsValid(unsigned char* byte); // Check for byte validity
|
||||
virtual unsigned int Arguments(); // Number of arguments taken
|
||||
|
||||
protected:
|
||||
bool error; // Whether there's an error in parsing or not
|
||||
};
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ Parser::Parser(std::string filename)
|
|||
fileLength = 0;
|
||||
filePos = 0;
|
||||
stop = false;
|
||||
stopAddress = 0;
|
||||
|
||||
SetFilename(filename);
|
||||
}
|
||||
|
|
@ -63,7 +64,9 @@ string Parser::GetParsedAsm()
|
|||
|
||||
for(unsigned int i = 0; i < parsedString.size(); i++)
|
||||
{
|
||||
tmpStr += parsedString[i] + "\n";
|
||||
// Ensure each line isn't already a new-line, this prevents double or tripple empty lines from piling up
|
||||
if(parsedString[i] != "\n") tmpStr += parsedString[i] + "\n";
|
||||
else tmpStr += parsedString[i];
|
||||
}
|
||||
|
||||
return tmpStr;
|
||||
|
|
@ -87,6 +90,8 @@ void Parser::Read()
|
|||
// Read filedata
|
||||
tmpFile.read(rawBytes, fileLength);
|
||||
tmpFile.close();
|
||||
|
||||
rawBytesFixed = (unsigned char*)rawBytes;
|
||||
}
|
||||
|
||||
// Code Operations
|
||||
|
|
@ -96,114 +101,165 @@ void Parser::Parse(unsigned int offset)
|
|||
ParseNext();
|
||||
}
|
||||
|
||||
template<class T>
|
||||
bool Parser::ParseData(unsigned int& pos, bool reado)
|
||||
{
|
||||
// Create the class to use if correct and a dummy class for validating
|
||||
T* tmpC = 0;
|
||||
T dummy;
|
||||
|
||||
// If the bytes are this data type then create and save it
|
||||
if(dummy.IsValid(&rawBytesFixed[pos]))
|
||||
{
|
||||
// Ensure this whole opperation isn't read-only (just peeking)
|
||||
if(!reado)
|
||||
{
|
||||
// Initialize the class
|
||||
tmpC = new T(&rawBytesFixed[pos]);
|
||||
|
||||
// Push it onto the stack and it's assembly generation onto the output class
|
||||
parsedBytes.push_back(tmpC); //
|
||||
parsedString.push_back(tmpC->GenAsm());
|
||||
|
||||
// If the class had any arguments, increment the counter that much forward
|
||||
pos += tmpC->Arguments();
|
||||
}
|
||||
return true; // Let the code know this class was valid
|
||||
}
|
||||
|
||||
return false; // Let the code know this class wasn't valid
|
||||
}
|
||||
|
||||
void Parser::ParseNext() // Parses the block immidiately following
|
||||
{
|
||||
stringstream tmpStr;
|
||||
unsigned char* rawBytesFixed = (unsigned char*)rawBytes;
|
||||
stop = false;
|
||||
|
||||
// Smart generation
|
||||
bool indent = false;
|
||||
bool firstNonNote = false; // First byte wasn't a note or octacve switch, add ";Setup" comment
|
||||
bool firstNote = false; // First note or octave
|
||||
bool firstNonNote = false; // (unused so far)First byte wasn't a note or octacve switch, add ";Setup" comment
|
||||
bool firstNote = false; // (unused so far) First note or octave
|
||||
unsigned char lDataType = DATA_NA;
|
||||
|
||||
stringstream pos;
|
||||
pos << "; " << hex << uppercase << (unsigned int)filePos;
|
||||
parsedString.push_back(pos.str());
|
||||
|
||||
unsigned int count = 1; // Counter for processed instructions
|
||||
for(unsigned int i = filePos; (i <= fileLength) && (stop == false); i++)
|
||||
{
|
||||
// There's a way to make this block shorter but for now it does it's job
|
||||
// First peek to see what kind of data it is, then perform any pre and post setup
|
||||
if(ParseData<Call>(i, true))
|
||||
{
|
||||
if(lDataType == DATA_NOTE) parsedString.push_back("\n"); // Insert a newline after notes
|
||||
|
||||
// Check to see if it's the correct data type and if so then use it
|
||||
if(tmpCall.IsValid(&rawBytesFixed[i])) // Should have made IsValid static
|
||||
ParseData<Call>(i);
|
||||
lDataType = DATA_CALL;
|
||||
}
|
||||
else if(ParseData<Duty>(i, true))
|
||||
{
|
||||
// Call data type
|
||||
if(lDataType == DATA_NOTE) parsedString.push_back("\n"); // Insert a newline after notes
|
||||
|
||||
// Create data type then move the increment pointer further up as needed
|
||||
parsedBytes.push_back(new Call(&rawBytesFixed[i]));
|
||||
parsedString.push_back(parsedBytes[parsedBytes.size() - 1]->GenAsm());
|
||||
i += tmpCall.Arguments(); // should have made Arguments static
|
||||
ParseData<Duty>(i);
|
||||
lDataType = DATA_DUTY;
|
||||
}
|
||||
else if(ParseData<Jump>(i, true))
|
||||
{
|
||||
if(lDataType == DATA_NOTE) parsedString.push_back("\n"); // Insert a newline after notes
|
||||
|
||||
Call* _tmp = (Call*)parsedBytes[parsedBytes.size() - 1];
|
||||
ParseData<Jump>(i);
|
||||
lDataType = DATA_JUMP;
|
||||
}
|
||||
else if(tmpDuty.IsValid(&rawBytesFixed[i]))
|
||||
else if(ParseData<Modulation>(i, true))
|
||||
{
|
||||
// Duty data type
|
||||
parsedBytes.push_back(new Duty(&rawBytesFixed[i]));
|
||||
parsedString.push_back(parsedBytes[parsedBytes.size() - 1]->GenAsm());
|
||||
i += tmpDuty.Arguments();
|
||||
}
|
||||
else if(tmpJump.IsValid(&rawBytesFixed[i]))
|
||||
{
|
||||
// Jump data type
|
||||
parsedBytes.push_back(new Jump(&rawBytesFixed[i]));
|
||||
parsedString.push_back(parsedBytes[parsedBytes.size() - 1]->GenAsm());
|
||||
i += tmpJump.Arguments();
|
||||
if(lDataType == DATA_NOTE) parsedString.push_back("\n"); // Insert a newline after notes
|
||||
|
||||
Jump* _tmp = (Jump*)parsedBytes[parsedBytes.size() - 1];
|
||||
ParseData<Modulation>(i);
|
||||
lDataType = DATA_MODULATION;
|
||||
}
|
||||
else if(tmpModulation.IsValid(&rawBytesFixed[i]))
|
||||
else if(ParseData<Note>(i, true))
|
||||
{
|
||||
// Modulation data type
|
||||
parsedBytes.push_back(new Modulation(&rawBytesFixed[i]));
|
||||
parsedString.push_back(parsedBytes[parsedBytes.size() - 1]->GenAsm());
|
||||
i += tmpModulation.Arguments();
|
||||
}
|
||||
else if(tmpNote.IsValid(&rawBytesFixed[i]))
|
||||
{
|
||||
// Note data type
|
||||
parsedBytes.push_back(new Note(&rawBytesFixed[i]));
|
||||
parsedString.push_back(parsedBytes[parsedBytes.size() - 1]->GenAsm());
|
||||
i += tmpNote.Arguments();
|
||||
}
|
||||
else if(tmpOctave.IsValid(&rawBytesFixed[i]))
|
||||
{
|
||||
// Octave data type
|
||||
parsedBytes.push_back(new Octave(&rawBytesFixed[i]));
|
||||
parsedString.push_back("\n" + parsedBytes[parsedBytes.size() - 1]->GenAsm());
|
||||
i += tmpOctave.Arguments();
|
||||
}
|
||||
else if(tmpStop.IsValid(&rawBytesFixed[i]))
|
||||
{
|
||||
// Stop data type
|
||||
parsedBytes.push_back(new Stop(&rawBytesFixed[i]));
|
||||
parsedString.push_back(parsedBytes[parsedBytes.size() - 1]->GenAsm());
|
||||
i += tmpStop.Arguments();
|
||||
// Insert a newline after certain types
|
||||
if((lDataType == DATA_UNKCODE) ||
|
||||
(lDataType == DATA_UNKEB)) parsedString.push_back("\n");
|
||||
|
||||
stop = true; // Stop all further processing, we've reached the end of the song
|
||||
}
|
||||
else if(tmpTempo.IsValid(&rawBytesFixed[i]))
|
||||
// If the previous item was a rest note then insert a new line
|
||||
else if(lDataType == DATA_NOTE)
|
||||
{
|
||||
// Tempo data type
|
||||
parsedBytes.push_back(new Tempo(&rawBytesFixed[i]));
|
||||
parsedString.push_back(parsedBytes[parsedBytes.size() - 1]->GenAsm());
|
||||
i += tmpTempo.Arguments();
|
||||
Note* _tmpNote = (Note*)parsedBytes[parsedBytes.size() - 1];
|
||||
if(_tmpNote->GetPitch() == _tmpNote->noteRst) parsedString.push_back("\n");
|
||||
}
|
||||
else if(tmpVelocity.IsValid(&rawBytesFixed[i]))
|
||||
{
|
||||
// Velocity data type
|
||||
parsedBytes.push_back(new Velocity(&rawBytesFixed[i]));
|
||||
parsedString.push_back(parsedBytes[parsedBytes.size() - 1]->GenAsm());
|
||||
i += tmpVelocity.Arguments();
|
||||
|
||||
ParseData<Note>(i);
|
||||
|
||||
// Further indent each note
|
||||
parsedString[parsedString.size() - 1] = "\t" + parsedString[parsedString.size() - 1];
|
||||
lDataType = DATA_NOTE;
|
||||
}
|
||||
else if(tmpVolume.IsValid(&rawBytesFixed[i]))
|
||||
else if(ParseData<Octave>(i, true))
|
||||
{
|
||||
// Volume data type
|
||||
parsedBytes.push_back(new Volume(&rawBytesFixed[i]));
|
||||
parsedString.push_back(parsedBytes[parsedBytes.size() - 1]->GenAsm());
|
||||
i += tmpVolume.Arguments();
|
||||
// Insert new-line if previous line isn't a newline
|
||||
if(parsedString[parsedString.size() - 1] != "\n") parsedString.push_back("\n");
|
||||
|
||||
ParseData<Octave>(i);
|
||||
lDataType = DATA_OCTAVE;
|
||||
}
|
||||
else if(ParseData<Tempo>(i, true))
|
||||
{
|
||||
if(lDataType == DATA_NOTE) parsedString.push_back("\n"); // Insert a newline after notes
|
||||
|
||||
ParseData<Tempo>(i);
|
||||
lDataType = DATA_TEMPO;
|
||||
}
|
||||
else if(ParseData<Velocity>(i, true))
|
||||
{
|
||||
if(lDataType == DATA_NOTE) parsedString.push_back("\n"); // Insert a newline after notes
|
||||
|
||||
ParseData<Velocity>(i);
|
||||
lDataType = DATA_VELOCITY;
|
||||
}
|
||||
else if(ParseData<Volume>(i, true))
|
||||
{
|
||||
if(lDataType == DATA_NOTE) parsedString.push_back("\n"); // Insert a newline after notes
|
||||
|
||||
ParseData<Volume>(i);
|
||||
lDataType = DATA_VOLUME;
|
||||
}
|
||||
else if(ParseData<UnkEB>(i, true)) // The opcode is 0xEB which is unknown and takes a 1-byte argument
|
||||
{
|
||||
if(lDataType == DATA_NOTE) parsedString.push_back("\n"); // Insert a newline after notes
|
||||
|
||||
ParseData<UnkEB>(i);
|
||||
lDataType = DATA_UNKEB;
|
||||
}
|
||||
else if(ParseData<Stop>(i, true))
|
||||
{
|
||||
if(lDataType == DATA_NOTE) parsedString.push_back("\n"); // Insert a newline after notes
|
||||
|
||||
ParseData<Stop>(i);
|
||||
stop = true; // Raise the stop flag informing the parser to stop
|
||||
lDataType = DATA_STOP;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Unknown code
|
||||
stringstream unkCode;
|
||||
short tmpByte = (short)rawBytesFixed[i];
|
||||
unkCode << "db $" << hex << uppercase << (short)rawBytesFixed[i];
|
||||
parsedString.push_back(unkCode.str());
|
||||
if(lDataType == DATA_NOTE) parsedString.push_back("\n"); // Insert a newline after notes
|
||||
|
||||
ParseData<UnkCode>(i); // The opcode is unknown - process the raw byte and move on
|
||||
lDataType = DATA_UNKCODE;
|
||||
}
|
||||
|
||||
// Put everything tabbed over at least 1 time to fix some weird RGBDS bug by pre-pending a tab character
|
||||
parsedString[parsedString.size() - 1] = "\t" + parsedString[parsedString.size() - 1];
|
||||
|
||||
// Append File Position in hexidecimal at end of line every 5 instructions
|
||||
if((count % 5) == 0)
|
||||
{
|
||||
stringstream _tmpCount;
|
||||
_tmpCount << hex << uppercase << i;
|
||||
parsedString[parsedString.size() - 1] = parsedString[parsedString.size() - 1] + "; " + _tmpCount.str();
|
||||
}
|
||||
|
||||
filePos = i;
|
||||
count++;
|
||||
|
||||
// If the stop address parameter is set, break when we get there
|
||||
if( (stopAddress != 0) && (i >= stopAddress) ) break;
|
||||
|
|
|
|||
|
|
@ -13,11 +13,12 @@
|
|||
#include "Modulation.h"
|
||||
#include "Note.h"
|
||||
#include "Octave.h"
|
||||
#include "Parser.h"
|
||||
#include "Stop.h"
|
||||
#include "Tempo.h"
|
||||
#include "Velocity.h"
|
||||
#include "Volume.h"
|
||||
#include "UnkCode.h"
|
||||
#include "UnkEB.h"
|
||||
|
||||
// This is the final class, it takes all of the data types, abstract class, and helper functions and uses them
|
||||
// for parsing
|
||||
|
|
@ -49,30 +50,40 @@ public:
|
|||
void Parse(unsigned int offset);
|
||||
void ParseNext(); // Parses the block immidiately following
|
||||
|
||||
// Templates
|
||||
template<class T>
|
||||
bool ParseData(unsigned int& pos, bool reado = false);
|
||||
|
||||
const enum dataType : unsigned char
|
||||
{
|
||||
DATA_NA,
|
||||
DATA_CALL,
|
||||
DATA_DUTY,
|
||||
DATA_JUMP,
|
||||
DATA_MODULATION,
|
||||
DATA_NOTE,
|
||||
DATA_OCTAVE,
|
||||
DATA_STOP,
|
||||
DATA_TEMPO,
|
||||
DATA_UNKCODE,
|
||||
DATA_UNKEB,
|
||||
DATA_VELOCITY,
|
||||
DATA_VOLUME
|
||||
};
|
||||
|
||||
private:
|
||||
std::string filename;
|
||||
std::vector<AbstractData*> parsedBytes;
|
||||
std::vector<std::string> parsedString;
|
||||
|
||||
char* rawBytes;
|
||||
unsigned char* rawBytesFixed;
|
||||
unsigned int fileLength;
|
||||
unsigned int filePos;
|
||||
bool stop;
|
||||
|
||||
// Optional Settings
|
||||
unsigned int stopAddress;
|
||||
|
||||
// A lot of tmp classes
|
||||
Call tmpCall;
|
||||
Duty tmpDuty;
|
||||
Jump tmpJump;
|
||||
Modulation tmpModulation;
|
||||
Note tmpNote;
|
||||
Octave tmpOctave;
|
||||
Stop tmpStop;
|
||||
Tempo tmpTempo;
|
||||
Velocity tmpVelocity;
|
||||
Volume tmpVolume;
|
||||
};
|
||||
|
||||
#endif
|
||||
67
music/pokeredmusicdisasm/UnkCode.cpp
Normal file
67
music/pokeredmusicdisasm/UnkCode.cpp
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
#include <sstream>
|
||||
|
||||
#include "Call.h"
|
||||
#include "Duty.h"
|
||||
#include "Jump.h"
|
||||
#include "Modulation.h"
|
||||
#include "Note.h"
|
||||
#include "Octave.h"
|
||||
#include "Stop.h"
|
||||
#include "Tempo.h"
|
||||
#include "Velocity.h"
|
||||
#include "Volume.h"
|
||||
|
||||
#include "UnkCode.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
UnkCode::UnkCode()
|
||||
{
|
||||
code = 0;
|
||||
}
|
||||
|
||||
UnkCode::UnkCode(unsigned char* byte)
|
||||
{
|
||||
code = 0;
|
||||
Parse(byte);
|
||||
}
|
||||
|
||||
UnkCode::UnkCode(unsigned char code, bool)
|
||||
{
|
||||
SetCode(code);
|
||||
}
|
||||
|
||||
// Getters / Setters
|
||||
unsigned char UnkCode::GetCode()
|
||||
{
|
||||
return code;
|
||||
}
|
||||
|
||||
void UnkCode::SetCode(unsigned char value)
|
||||
{
|
||||
code = value;
|
||||
}
|
||||
|
||||
// Re-implemented
|
||||
string UnkCode::GenAsm()
|
||||
{
|
||||
stringstream tmpAsmOut;
|
||||
tmpAsmOut << "db $" << hex << (short)code;
|
||||
return tmpAsmOut.str();
|
||||
}
|
||||
|
||||
bool UnkCode::Parse(unsigned char* byte)
|
||||
{
|
||||
code = byte[0];
|
||||
return true;
|
||||
}
|
||||
|
||||
bool UnkCode::IsValid(unsigned char* byte)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
unsigned int UnkCode::Arguments()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
29
music/pokeredmusicdisasm/UnkCode.h
Normal file
29
music/pokeredmusicdisasm/UnkCode.h
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
#ifndef UNKCODE_H
|
||||
#define UNKCODE_H
|
||||
|
||||
#include "AbstractData.h"
|
||||
|
||||
// Represents an unknown opcode
|
||||
class UnkCode : public AbstractData
|
||||
{
|
||||
public:
|
||||
// Constructors
|
||||
UnkCode();
|
||||
UnkCode(unsigned char* byte); // Parse Immidiately
|
||||
UnkCode(unsigned char code, bool); // Set Value
|
||||
|
||||
// Getters / Setters
|
||||
unsigned char GetCode();
|
||||
void SetCode(unsigned char value);
|
||||
|
||||
// Re-implemented
|
||||
virtual std::string GenAsm();
|
||||
virtual bool Parse(unsigned char* byte);
|
||||
virtual bool IsValid(unsigned char* byte);
|
||||
virtual unsigned int Arguments();
|
||||
|
||||
private:
|
||||
unsigned char code;
|
||||
};
|
||||
|
||||
#endif
|
||||
69
music/pokeredmusicdisasm/UnkEB.cpp
Normal file
69
music/pokeredmusicdisasm/UnkEB.cpp
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
#include <sstream>
|
||||
|
||||
#include "Call.h"
|
||||
#include "Duty.h"
|
||||
#include "Jump.h"
|
||||
#include "Modulation.h"
|
||||
#include "Note.h"
|
||||
#include "Octave.h"
|
||||
#include "Stop.h"
|
||||
#include "Tempo.h"
|
||||
#include "Velocity.h"
|
||||
#include "Volume.h"
|
||||
|
||||
#include "UnkEB.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
UnkEB::UnkEB()
|
||||
{
|
||||
param = 0;
|
||||
}
|
||||
|
||||
UnkEB::UnkEB(unsigned char* byte)
|
||||
{
|
||||
param = 0;
|
||||
Parse(byte);
|
||||
}
|
||||
|
||||
UnkEB::UnkEB(unsigned char code, bool)
|
||||
{
|
||||
SetParam(code);
|
||||
}
|
||||
|
||||
// Getters / Setters
|
||||
unsigned char UnkEB::GetParam()
|
||||
{
|
||||
return param;
|
||||
}
|
||||
|
||||
void UnkEB::SetParam(unsigned char value)
|
||||
{
|
||||
param = value;
|
||||
}
|
||||
|
||||
// Re-implemented
|
||||
string UnkEB::GenAsm()
|
||||
{
|
||||
stringstream tmpAsmOut;
|
||||
tmpAsmOut << hex << "db $" << (short)0xEB << ", $" << (short)param;
|
||||
return tmpAsmOut.str();
|
||||
}
|
||||
|
||||
bool UnkEB::Parse(unsigned char* byte)
|
||||
{
|
||||
param = byte[1];
|
||||
return true;
|
||||
}
|
||||
|
||||
bool UnkEB::IsValid(unsigned char* byte)
|
||||
{
|
||||
if(byte[0] == 0xEB) return true;
|
||||
else return false;
|
||||
}
|
||||
|
||||
unsigned int UnkEB::Arguments()
|
||||
{
|
||||
// 1 1-Byte param
|
||||
return 1;
|
||||
}
|
||||
29
music/pokeredmusicdisasm/UnkEB.h
Normal file
29
music/pokeredmusicdisasm/UnkEB.h
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
#ifndef UNKEB_H
|
||||
#define UNKEB_H
|
||||
|
||||
#include "AbstractData.h"
|
||||
|
||||
// Represents an unknown opcode
|
||||
class UnkEB : public AbstractData
|
||||
{
|
||||
public:
|
||||
// Constructors
|
||||
UnkEB();
|
||||
UnkEB(unsigned char* byte); // Parse Immidiately
|
||||
UnkEB(unsigned char code, bool); // Set Value
|
||||
|
||||
// Getters / Setters
|
||||
unsigned char GetParam();
|
||||
void SetParam(unsigned char value);
|
||||
|
||||
// Re-implemented
|
||||
virtual std::string GenAsm();
|
||||
virtual bool Parse(unsigned char* byte);
|
||||
virtual bool IsValid(unsigned char* byte);
|
||||
virtual unsigned int Arguments();
|
||||
|
||||
private:
|
||||
unsigned char param;
|
||||
};
|
||||
|
||||
#endif
|
||||
Loading…
Reference in a new issue