- Added a new wilcard for importing savegames, which basically shows all saves (gci, gcs and sav). This is set as default (I really got frustrated of having to change the type every single time when making tests for GCMM, and I think it makes more sense at user level to just show all saves regardless the format)

- In icon retrieving I removed the "format check" as it shouldn't really matter to have mixed icon formats. Also removed the "Time splitters hack" as there's no reason for it since we are only checking the last 3 bits and I'm pretty sure having bits 1 and 2 set is the same as having them unset.
- Icon retrieving uses AnimSpeed as stop signal (every icon must have an speed set, the first speed that is 0 means there are no more icons)
- Also, in icon retrieving I added support for "blank frames"(Luigi's Mansion and Pikmin that I know of). With this the base for icon animation is complete.
- Fixed PSOIII savegame patch which was wrong before.

Signed-off-by: LPFaint99 <lpfaint99@gmail.com>
This commit is contained in:
sulokuTDCmago 2012-10-18 00:01:45 -07:00 committed by LPFaint99
parent 5dd49edaec
commit d032c40a58
4 changed files with 68 additions and 21 deletions

View File

@ -31,7 +31,7 @@ const int lut3to8[] = { 0x00,0x24,0x48,0x6D,0x91,0xB6,0xDA,0xFF };
u32 Decode5A3(u16 val) u32 Decode5A3(u16 val)
{ {
const u32 bg_color = 0x00000000; const u32 bg_color = 0xFFFFFFFF;
int r, g, b, a; int r, g, b, a;

View File

@ -473,11 +473,20 @@ std::string GCMemcard::DEntry_IconFmt(u8 index) const
return format; return format;
} }
u16 GCMemcard::DEntry_AnimSpeed(u8 index) const std::string GCMemcard::DEntry_AnimSpeed(u8 index) const
{ {
if (!m_valid || index > DIRLEN) if (!m_valid || index > DIRLEN)
return 0xFF; return "";
return BE16(CurrentDir->Dir[index].AnimSpeed); int x = CurrentDir->Dir[index].AnimSpeed[0];
std::string speed;
for(int i = 0; i < 16; i++)
{
if (i == 8) x = CurrentDir->Dir[index].AnimSpeed[1];
speed.push_back((x & 0x80) ? '1' : '0');
x = x << 1;
}
speed.push_back(0);
return speed;
} }
std::string GCMemcard::DEntry_Permissions(u8 index) const std::string GCMemcard::DEntry_Permissions(u8 index) const
@ -1086,15 +1095,18 @@ u32 GCMemcard::ReadAnimRGBA8(u8 index, u32* buffer, u8 *delays) const
// To ensure only one type of icon is used // To ensure only one type of icon is used
// Sonic Heroes it the only game I have seen that tries to use a CI8 and RGB5A3 icon // Sonic Heroes it the only game I have seen that tries to use a CI8 and RGB5A3 icon
int fmtCheck = 0; //int fmtCheck = 0;
int formats = BE16(CurrentDir->Dir[index].IconFmt); int formats = BE16(CurrentDir->Dir[index].IconFmt);
int fdelays = BE16(CurrentDir->Dir[index].AnimSpeed); int fdelays = BE16(CurrentDir->Dir[index].AnimSpeed);
int flags = CurrentDir->Dir[index].BIFlags; int flags = CurrentDir->Dir[index].BIFlags;
// Timesplitters 2 is the only game that I see this in // Timesplitters 2 and 3 is the only game that I see this in
// May be a hack // May be a hack
if (flags == 0xFB) flags = ~flags; //if (flags == 0xFB) flags = ~flags;
// Batten Kaitos has 0x65 as flag too. Everything but the first 3 bytes seems irrelevant.
// Something similar happens with Wario Ware Inc. AnimSpeed
int bnrFormat = (flags&3); int bnrFormat = (flags&3);
u32 DataOffset = BE32(CurrentDir->Dir[index].ImageOffset); u32 DataOffset = BE32(CurrentDir->Dir[index].ImageOffset);
@ -1110,7 +1122,6 @@ u32 GCMemcard::ReadAnimRGBA8(u8 index, u32* buffer, u8 *delays) const
switch (bnrFormat) switch (bnrFormat)
{ {
case 1: case 1:
case 3:
animData += 96*32 + 2*256; // image+palette animData += 96*32 + 2*256; // image+palette
break; break;
case 2: case 2:
@ -1122,40 +1133,48 @@ u32 GCMemcard::ReadAnimRGBA8(u8 index, u32* buffer, u8 *delays) const
u8* data[8]; u8* data[8];
int frames = 0; int frames = 0;
for (int i = 0; i < 8; i++) for (int i = 0; i < 8; i++)
{ {
fmts[i] = (formats >> (2*i))&3; fmts[i] = (formats >> (2*i))&3;
delays[i] = ((fdelays >> (2*i))&3) << 2; delays[i] = ((fdelays >> (2*i))&3);
data[i] = animData; data[i] = animData;
if (!fmtCheck) fmtCheck = fmts[i]; if (!delays[i])
if (fmtCheck == fmts[i]) {
//First icon_speed = 0 indicates there aren't any more icons
break;
}
//If speed is set there is an icon (it can be a "blank frame")
frames++;
if (fmts[i] != 0)
{ {
switch (fmts[i]) switch (fmts[i])
{ {
case CI8SHARED: // CI8 with shared palette case CI8SHARED: // CI8 with shared palette
animData += 32*32; animData += 32*32;
frames++;
break; break;
case RGB5A3: // RGB5A3 case RGB5A3: // RGB5A3
animData += 32*32*2; animData += 32*32*2;
frames++;
break; break;
case CI8: // CI8 with own palette case CI8: // CI8 with own palette
animData += 32*32 + 2*256; animData += 32*32 + 2*256;
frames++;
break; break;
} }
} }
} }
u16* sharedPal = (u16*)(animData); u16* sharedPal = (u16*)(animData);
int j = 0;
for (int i = 0; i < 8; i++) for (int i = 0; i < 8; i++)
{ {
if (fmtCheck == fmts[i]) if (!delays[i])
{
//First icon_speed = 0 indicates there aren't any more icons
break;
}
if (fmts[i] != 0)
{ {
switch (fmts[i]) switch (fmts[i])
{ {
@ -1165,6 +1184,7 @@ u32 GCMemcard::ReadAnimRGBA8(u8 index, u32* buffer, u8 *delays) const
break; break;
case RGB5A3: // RGB5A3 case RGB5A3: // RGB5A3
decode5A3image(buffer, (u16*)(data[i]), 32, 32); decode5A3image(buffer, (u16*)(data[i]), 32, 32);
buffer += 32*32;
break; break;
case CI8: // CI8 with own palette case CI8: // CI8 with own palette
u16 *paldata = (u16*)(data[i] + 32*32); u16 *paldata = (u16*)(data[i] + 32*32);
@ -1173,6 +1193,33 @@ u32 GCMemcard::ReadAnimRGBA8(u8 index, u32* buffer, u8 *delays) const
break; break;
} }
} }
else
{
//Speed is set but there's no actual icon
//This is used to reduce animation speed in Pikmin and Luigi's Mansion for example
//These "blank frames" show the next icon
for(j=i; j<8;++j)
{
if (fmts[j] != 0)
{
switch (fmts[j])
{
case CI8SHARED: // CI8 with shared palette
decodeCI8image(buffer,data[j],sharedPal,32,32);
break;
case RGB5A3: // RGB5A3
decode5A3image(buffer, (u16*)(data[j]), 32, 32);
buffer += 32*32;
break;
case CI8: // CI8 with own palette
u16 *paldata = (u16*)(data[j] + 32*32);
decodeCI8image(buffer, data[j], paldata, 32, 32);
buffer += 32*32;
break;
}
}
}
}
} }
return frames; return frames;
@ -1269,7 +1316,6 @@ void GCMemcard::FormatInternal(GCMC_Header &GCP)
calc_checksumsBE((u16*)p_bat_backup+2, 0xFFE, &p_bat_backup->Checksum, &p_bat_backup->Checksum_Inv); calc_checksumsBE((u16*)p_bat_backup+2, 0xFFE, &p_bat_backup->Checksum, &p_bat_backup->Checksum_Inv);
} }
void GCMemcard::CARD_GetSerialNo(u32 *serial1,u32 *serial2) void GCMemcard::CARD_GetSerialNo(u32 *serial1,u32 *serial2)
{ {
u32 serial[8]; u32 serial[8];
@ -1349,7 +1395,7 @@ s32 GCMemcard::PSO_MakeSaveGameValid(DEntry& direntry, std::vector<GCMBlock> &Fi
if (strcmp((char*)direntry.Filename,"PSO_SYSTEM")!=0) if (strcmp((char*)direntry.Filename,"PSO_SYSTEM")!=0)
{ {
// check for PSO3 system file // check for PSO3 system file
if (strcmp((char*)&FileBuffer[0].block[0x08],"PSO3_SYSTEM")==0) if (strcmp((char*)direntry.Filename,"PSO3_SYSTEM")==0)
{ {
// PSO3 data block size adjustment // PSO3 data block size adjustment
pso3offset = 0x10; pso3offset = 0x10;

View File

@ -116,8 +116,8 @@ private:
// bits 0 and 1: image format // bits 0 and 1: image format
// 00 no banner // 00 no banner
// 01 CI8 banner // 01 CI8 banner
// 01 RGB5A3 banner // 10 RGB5A3 banner
// 11 ? maybe ==01? haven't seen it // 11 ? maybe ==00? Time Splitters 2 and 3 have it and don't have banner
// //
u8 Filename[DENTRY_STRLEN]; //0x08 0x20 filename u8 Filename[DENTRY_STRLEN]; //0x08 0x20 filename
u8 ModTime[4]; //0x28 0x04 Time of file's last modification in seconds since 12am, January 1st, 2000 u8 ModTime[4]; //0x28 0x04 Time of file's last modification in seconds since 12am, January 1st, 2000
@ -213,7 +213,7 @@ public:
u32 DEntry_ModTime(u8 index) const; u32 DEntry_ModTime(u8 index) const;
u32 DEntry_ImageOffset(u8 index) const; u32 DEntry_ImageOffset(u8 index) const;
std::string DEntry_IconFmt(u8 index) const; std::string DEntry_IconFmt(u8 index) const;
u16 DEntry_AnimSpeed(u8 index) const; std::string DEntry_AnimSpeed(u8 index) const;
std::string DEntry_Permissions(u8 index) const; std::string DEntry_Permissions(u8 index) const;
u8 DEntry_CopyCounter(u8 index) const; u8 DEntry_CopyCounter(u8 index) const;
// get first block for file // get first block for file

View File

@ -520,6 +520,7 @@ void CMemcardManager::CopyDeleteClick(wxCommandEvent& event)
? wxString::FromAscii("") ? wxString::FromAscii("")
: wxString::From8BitData(DefaultIOPath.c_str()), : wxString::From8BitData(DefaultIOPath.c_str()),
wxEmptyString, wxEmptyString, wxEmptyString, wxEmptyString,
_("GameCube Savegame files(*.gci;*.gcs;*.sav)") + wxString(wxT("|*.gci;*.gcs;*.sav|")) +
_("Native GCI files(*.gci)") + wxString(wxT("|*.gci|")) + _("Native GCI files(*.gci)") + wxString(wxT("|*.gci|")) +
_("MadCatz Gameshark files(*.gcs)") + wxString(wxT("|*.gcs|")) + _("MadCatz Gameshark files(*.gcs)") + wxString(wxT("|*.gcs|")) +
_("Datel MaxDrive/Pro files(*.sav)") + wxString(wxT("|*.sav")), _("Datel MaxDrive/Pro files(*.sav)") + wxString(wxT("|*.sav")),