WiiFlow_Lite/source/menu/menu_game.cpp
fix94.1 63dbed3f68 -changed a few things about the addition in r183 again, if
you want to have the gamecube games in the usb folder
"ngc" you now also just need to set the ini to "ngc",
no need for "%s:/ngc" anymore (thanks r-win for few tips)
2012-03-07 21:03:27 +00:00

1350 lines
38 KiB
C++

#include "menu.hpp"
#include "loader/patchcode.h"
#include "loader/sys.h"
#include "loader/wdvd.h"
#include "loader/alt_ios.h"
#include "loader/playlog.h"
#include <ogc/machine/processor.h>
#include <unistd.h>
#include <time.h>
#include "network/http.h"
#include "network/gcard.h"
#include "DeviceHandler.hpp"
#include "loader/wbfs.h"
#include "savefile.h"
#include "wip.h"
#include "channel_launcher.h"
#include "devicemounter/sdhc.h"
#include "loader/frag.h"
#include "loader/fst.h"
#include "gui/WiiMovie.hpp"
#include "gui/GameTDB.hpp"
#include "channels.h"
#include "nand.hpp"
#include "alt_ios.h"
#include "gecko.h"
#include "homebrew.h"
#include "defines.h"
#include "gc/gc.h"
//#define DML_THROUGH_MEM /*** Load game through mem.. Not compatible with regulair DML ***/
using namespace std;
extern const u8 btngamecfg_png[];
extern const u8 btngamecfgs_png[];
extern const u8 stopkidon_png[];
extern const u8 stopkidons_png[];
extern const u8 stopkidoff_png[];
extern const u8 stopkidoffs_png[];
extern const u8 favoriteson_png[];
extern const u8 favoritesons_png[];
extern const u8 favoritesoff_png[];
extern const u8 favoritesoffs_png[];
extern const u8 delete_png[];
extern const u8 deletes_png[];
//gc sound
extern const u8 gc_ogg[];
extern const u32 gc_ogg_size;
extern u32 sector_size;
extern int mainIOS;
static u64 sm_title_id[8] ATTRIBUTE_ALIGN(32);
const string CMenu::_translations[23] = {
"Default",
"Arab",
"Brazilian",
"Chinese_S",
"Chinese_T",
"Danish",
"Dutch",
"English",
"Finnish",
"French",
"Gallego",
"German",
"Hungarian",
"Italian",
"Japanese",
"Norwegian",
"Polish",
"Portuguese",
"Russian",
"Spanish",
"Swedish",
"Tagalog",
"Turkish"
};
const CMenu::SOption CMenu::_languages[11] = {
{ "lngdef", L"Default" },
{ "lngjap", L"Japanese" },
{ "lngeng", L"English" },
{ "lngger", L"German" },
{ "lngfre", L"French" },
{ "lngspa", L"Spanish" },
{ "lngita", L"Italian" },
{ "lngdut", L"Dutch" },
{ "lngsch", L"S. Chinese" },
{ "lngtch", L"T. Chinese" },
{ "lngkor", L"Korean" }
};
const CMenu::SOption CMenu::_videoModes[7] = {
{ "viddef", L"Default" },
{ "vidp50", L"PAL 50Hz" },
{ "vidp60", L"PAL 60Hz" },
{ "vidntsc", L"NTSC" },
{ "vidpatch", L"Auto Patch" },
{ "vidsys", L"System" },
{ "vidprog", L"Progressive" }
};
const CMenu::SOption CMenu::_GlobalDMLvideoModes[3] = {
{ "DMLdefG", L"Game" },
{ "DMLpal", L"PAL 576i" },
{ "DMLntsc", L"NTSC 480i" }
};
const CMenu::SOption CMenu::_DMLvideoModes[4] = {
{ "DMLdef", L"Default" },
{ "DMLdefG", L"Game" },
{ "DMLpal", L"PAL 576i" },
{ "DMLntsc", L"NTSC 480i" }
};
const CMenu::SOption CMenu::_GlobalGClanguages[7] = {
{ "lngsys", L"System" },
{ "lngeng", L"English" },
{ "lngger", L"German" },
{ "lngfre", L"French" },
{ "lngspa", L"Spanish" },
{ "lngita", L"Italian" },
{ "lngdut", L"Dutch" }
};
const CMenu::SOption CMenu::_GClanguages[8] = {
{ "lngdef", L"Default" },
{ "lngsys", L"System" },
{ "lngeng", L"English" },
{ "lngger", L"German" },
{ "lngfre", L"French" },
{ "lngspa", L"Spanish" },
{ "lngita", L"Italian" },
{ "lngdut", L"Dutch" }
};
const CMenu::SOption CMenu::_NandEmu[3] = {
{ "NANDoff", L"Off" },
{ "NANDpart", L"Partial" },
{ "NANDfull", L"Full" },
};
const CMenu::SOption CMenu::_GlobalSaveEmu[3] = {
{ "SaveOffG", L"Off" },
{ "SavePartG", L"Partial" },
{ "SaveFullG", L"Full" },
};
const CMenu::SOption CMenu::_SaveEmu[4] = {
{ "SaveDef", L"Default" },
{ "SaveOff", L"Off" },
{ "SavePart", L"Partial" },
{ "SaveFull", L"Full" },
};
const CMenu::SOption CMenu::_AspectRatio[3] = {
{ "aspectDef", L"Default" },
{ "aspect43", L"Force 4:3" },
{ "aspect169", L"Force 16:9" },
};
const CMenu::SOption CMenu::_vidModePatch[4] = {
{ "vmpnone", L"None" },
{ "vmpnormal", L"Normal" },
{ "vmpmore", L"More" },
{ "vmpall", L"All" }
};
const CMenu::SOption CMenu::_hooktype[8] = {
{ "disabled", L"Disabled" },
{ "hooktype1", L"VBI" },
{ "hooktype2", L"KPAD read" },
{ "hooktype3", L"Joypad" },
{ "hooktype4", L"GXDraw" },
{ "hooktype5", L"GXFlush" },
{ "hooktype6", L"OSSleepThread" },
{ "hooktype7", L"AXNextFrame" },
};
/*
0 No Hook
1 VBI
2 KPAD read
3 Joypad Hook
4 GXDraw Hook
5 GXFlush Hook
6 OSSleepThread Hook
7 AXNextFrame Hook
*/
std::map<u8, u8> CMenu::_installed_cios;
u8 banner_title[84];
static inline int loopNum(int i, int s)
{
return i < 0 ? (s - (-i % s)) % s : i % s;
}
static void _extractBannerTitle(Banner *bnr, int language)
{
if (bnr != NULL)
{
memset(banner_title, 0, 84);
bnr->GetName(banner_title, language);
}
}
static Banner *_extractChannelBnr(const u64 chantitle)
{
return Channels::GetBanner(chantitle);
}
static Banner *_extractBnr(dir_discHdr *hdr)
{
Banner *banner = NULL;
wbfs_disc_t *disc = WBFS_OpenDisc((u8 *) &hdr->hdr.id, (char *) hdr->path);
if (disc != NULL)
{
void *bnr = NULL;
if (wbfs_extract_file(disc, (char *) "opening.bnr", &bnr) > 0)
{
banner = new Banner((u8 *) bnr);
}
WBFS_CloseDisc(disc);
}
return banner;
}
static int GetLanguage(const char *lang)
{
if (strncmp(lang, "JP", 2) == 0) return CONF_LANG_JAPANESE;
else if (strncmp(lang, "EN", 2) == 0) return CONF_LANG_ENGLISH;
else if (strncmp(lang, "DE", 2) == 0) return CONF_LANG_GERMAN;
else if (strncmp(lang, "FR", 2) == 0) return CONF_LANG_FRENCH;
else if (strncmp(lang, "ES", 2) == 0) return CONF_LANG_SPANISH;
else if (strncmp(lang, "IT", 2) == 0) return CONF_LANG_ITALIAN;
else if (strncmp(lang, "NL", 2) == 0) return CONF_LANG_DUTCH;
else if (strncmp(lang, "ZHTW", 4) == 0) return CONF_LANG_TRAD_CHINESE;
else if (strncmp(lang, "ZH", 2) == 0) return CONF_LANG_SIMP_CHINESE;
else if (strncmp(lang, "KO", 2) == 0) return CONF_LANG_KOREAN;
return CONF_LANG_ENGLISH; // Default to EN
}
static u8 GetRequestedGameIOS(dir_discHdr *hdr)
{
u8 IOS = 0;
wbfs_disc_t *disc = WBFS_OpenDisc((u8 *) &hdr->hdr.id, (char *) hdr->path);
if (!disc) return IOS;
u8 *titleTMD = NULL;
u32 tmd_size = wbfs_extract_file(disc, (char *) "TMD", (void **)&titleTMD);
WBFS_CloseDisc(disc);
if(!titleTMD) return IOS;
if(tmd_size > 0x18B)
IOS = titleTMD[0x18B];
return IOS;
}
void CMenu::_hideGame(bool instant)
{
m_gameSelected = false;
m_fa.unload();
m_cf.showCover();
m_btnMgr.hide(m_gameBtnPlay, instant);
m_btnMgr.hide(m_gameBtnDelete, instant);
m_btnMgr.hide(m_gameBtnSettings, instant);
m_btnMgr.hide(m_gameBtnBack, instant);
m_btnMgr.hide(m_gameBtnFavoriteOn, instant);
m_btnMgr.hide(m_gameBtnFavoriteOff, instant);
m_btnMgr.hide(m_gameBtnAdultOn, instant);
m_btnMgr.hide(m_gameBtnAdultOff, instant);
for (u32 i = 0; i < ARRAY_SIZE(m_gameLblUser); ++i)
if (m_gameLblUser[i] != -1u)
m_btnMgr.hide(m_gameLblUser[i], instant);
}
void CMenu::_showGame(void)
{
m_cf.showCover();
if (m_fa.load(m_cfg, m_fanartDir.c_str(), m_cf.getId().c_str()))
{
STexture bg, bglq;
m_fa.getBackground(bg, bglq);
_setBg(bg, bglq);
if (m_fa.hideCover())
m_cf.hideCover();
}
else
_setBg(m_mainBg, m_mainBgLQ);
m_btnMgr.show(m_gameBtnPlay);
m_btnMgr.show(m_gameBtnBack);
for (u32 i = 0; i < ARRAY_SIZE(m_gameLblUser); ++i)
if (m_gameLblUser[i] != -1u)
m_btnMgr.show(m_gameLblUser[i]);
}
static void setLanguage(int l)
{
if (l > 0 && l <= 10)
configbytes[0] = l - 1;
else
configbytes[0] = 0xCD;
}
void CMenu::_game(bool launch)
{
m_gcfg1.load(sfmt("%s/gameconfig1.ini", m_settingsDir.c_str()).c_str());
if (!launch)
{
SetupInput();
m_cf.stopCoverLoader();
_playGameSound();
_showGame();
m_gameSelected = true;
}
s8 startGameSound = 1;
while (true)
{
if(startGameSound < 1) startGameSound++;
string id(m_cf.getId());
u64 chantitle = m_cf.getChanTitle();
if (startGameSound == -5)
{
_playGameSound();
_showGame();
}
_mainLoopCommon(true);
if (startGameSound == 0)
{
m_gameSelected = true;
startGameSound = 1;
}
if (BTN_HOME_PRESSED || BTN_B_PRESSED)
{
m_gameSound.Stop();
CheckGameSoundThread();
break;
}
else if (BTN_PLUS_PRESSED && m_GameTDBLoaded)
{
_hideGame();
m_gameSelected = true;
_gameinfo();
_showGame();
if (!m_gameSound.IsPlaying()) startGameSound = -6;
}
else if (BTN_MINUS_PRESSED)
{
string videoPath = sfmt("%s/%.3s.thp", m_videoDir.c_str(), id.c_str());
FILE *file = fopen(videoPath.c_str(), "rb");
if (file)
{
SAFE_CLOSE(file);
_hideGame();
WiiMovie movie(videoPath.c_str());
movie.SetScreenSize(m_cfg.getInt("GENERAL", "tv_width", 640), m_cfg.getInt("GENERAL", "tv_height", 480), m_cfg.getInt("GENERAL", "tv_x", 0), m_cfg.getInt("GENERAL", "tv_y", 0));
movie.SetVolume(m_cfg.getInt("GENERAL", "sound_volume_bnr", 255));
//_stopSounds();
movie.Play();
m_video_playing = true;
STexture videoBg;
while (!BTN_B_PRESSED && !BTN_A_PRESSED && !BTN_HOME_PRESSED && movie.GetNextFrame(&videoBg))
{
_setBg(videoBg, videoBg);
m_bgCrossFade = 10;
_mainLoopCommon(); // Redraw the background every frame
}
movie.Stop();
_showGame();
m_video_playing = false;
//m_gameSound.play(m_bnrSndVol);
}
}
else if ((BTN_1_PRESSED) || (BTN_2_PRESSED))
{
s8 direction = BTN_1_PRESSED ? 1 : -1;
const char *domain = _domainFromView();
int cfVersion = 1+loopNum((m_cfg.getInt(domain, "last_cf_mode", 1)-1) + direction, m_numCFVersions);
_loadCFLayout(cfVersion);
m_cf.applySettings();
m_cfg.setInt(domain, "last_cf_mode" , cfVersion);
}
else if (launch || BTN_A_PRESSED)
{
if (m_btnMgr.selected(m_mainBtnQuit))
break;
else if (m_btnMgr.selected(m_gameBtnDelete))
{
if (!m_locked)
{
_hideGame();
if (_wbfsOp(CMenu::WO_REMOVE_GAME))
{
m_gameSound.Stop();
CheckGameSoundThread();
break;
}
_showGame();
}
}
else if (m_btnMgr.selected(m_gameBtnFavoriteOn) || m_btnMgr.selected(m_gameBtnFavoriteOff))
m_gcfg1.setBool("FAVORITES", id, !m_gcfg1.getBool("FAVORITES", id, false));
else if (m_btnMgr.selected(m_gameBtnAdultOn) || m_btnMgr.selected(m_gameBtnAdultOff))
m_gcfg1.setBool("ADULTONLY", id, !m_gcfg1.getBool("ADULTONLY", id, false));
else if (m_btnMgr.selected(m_gameBtnBack))
{
m_gameSound.Stop();
CheckGameSoundThread();
break;
}
else if (m_btnMgr.selected(m_gameBtnSettings))
{
_hideGame();
m_gameSelected = true;
_gameSettings();
_showGame();
if (!m_gameSound.IsPlaying()) startGameSound = -6;
}
else if (launch || m_btnMgr.selected(m_gameBtnPlay) || (!WPadIR_Valid(0) && !WPadIR_Valid(1) && !WPadIR_Valid(2) && !WPadIR_Valid(3) && m_btnMgr.selected((u32)-1)))
{
_hideGame();
dir_discHdr *hdr = m_cf.getHdr();
if(currentPartition != SD && m_current_view == COVERFLOW_DML)
{
char gcfolder[300];
sprintf(gcfolder, "%s [%s]", m_cf.getTitle().toUTF8().c_str(), (char *)hdr->hdr.id);
if (DML_GameIsInstalled((char *)hdr->hdr.id, DeviceName[SD], DML_DIR))
{
memset(hdr->path, 0, sizeof(hdr->path));
snprintf(hdr->path, sizeof(hdr->path), "%s", (char*)hdr->hdr.id);
}
else if(DML_GameIsInstalled(gcfolder, DeviceName[SD], DML_DIR))
{
memset(hdr->path, 0, sizeof(hdr->path));
snprintf(hdr->path, sizeof(hdr->path), "%s", gcfolder);
}
else if(!DML_GameIsInstalled(hdr->path, DeviceName[SD], DML_DIR) && !_wbfsOp(CMenu::WO_COPY_GAME))
break;
currentPartition = SD;
}
m_cf.clear();
_showWaitMessage();
if (m_current_view != COVERFLOW_HOMEBREW)
{
// Get banner_title
Banner * banner = m_current_view == COVERFLOW_CHANNEL ? _extractChannelBnr(chantitle) : m_current_view == COVERFLOW_USB ? _extractBnr(hdr) : NULL;
if (banner != NULL)
{
if (banner->IsValid())
_extractBannerTitle(banner, GetLanguage(m_loc.getString(m_curLanguage, "gametdb_code", "EN").c_str()));
delete banner;
}
banner = NULL;
if (Playlog_Update(id.c_str(), banner_title) < 0)
Playlog_Delete();
}
gprintf("Launching game\n");
_launch(hdr);
if(m_exit || bootHB) break;
_hideWaitMessage();
launch = false;
for(int chan = WPAD_MAX_WIIMOTES-1; chan >= 0; chan--)
WPAD_SetVRes(chan, m_vid.width() + m_cursor[chan].width(), m_vid.height() + m_cursor[chan].height());
_showGame();
_initCF();
m_cf.select();
}
else
{
for(int chan = WPAD_MAX_WIIMOTES-1; chan >= 0; chan--)
if (m_cf.mouseOver(m_vid, m_cursor[chan].x(), m_cursor[chan].y()))
m_cf.flip();
}
}
if ((startGameSound == 1 || startGameSound < -8) && (BTN_UP_REPEAT || RIGHT_STICK_UP))
{
m_cf.up();
startGameSound = -10;
}
if ((startGameSound == 1 || startGameSound < -8) && (BTN_RIGHT_REPEAT || RIGHT_STICK_RIGHT))
{
m_cf.right();
startGameSound = -10;
}
if ((startGameSound == 1 || startGameSound < -8) && (BTN_DOWN_REPEAT || RIGHT_STICK_DOWN))
{
m_cf.down();
startGameSound = -10;
}
if ((startGameSound == 1 || startGameSound < -8) && (BTN_LEFT_REPEAT || RIGHT_STICK_LEFT))
{
m_cf.left();
startGameSound = -10;
}
if (startGameSound == -10)
{
m_gameSound.Stop();
m_gameSelected = false;
m_fa.unload();
_setBg(m_mainBg, m_mainBgLQ);
}
if (m_show_zone_game)
{
bool b = m_gcfg1.getBool("FAVORITES", id, false);
m_btnMgr.show(b ? m_gameBtnFavoriteOn : m_gameBtnFavoriteOff);
m_btnMgr.hide(b ? m_gameBtnFavoriteOff : m_gameBtnFavoriteOn);
m_btnMgr.show(m_gameBtnPlay);
m_btnMgr.show(m_gameBtnBack);
for (u32 i = 0; i < ARRAY_SIZE(m_gameLblUser); ++i)
if (m_gameLblUser[i] != -1u)
m_btnMgr.show(m_gameLblUser[i]);
if (!m_locked) {
b = m_gcfg1.getBool("ADULTONLY", id, false);
m_btnMgr.show(b ? m_gameBtnAdultOn : m_gameBtnAdultOff);
m_btnMgr.hide(b ? m_gameBtnAdultOff : m_gameBtnAdultOn);
m_btnMgr.show(m_gameBtnSettings);
}
if ((m_current_view == COVERFLOW_USB || m_current_view == COVERFLOW_DML) && !m_locked)
m_btnMgr.show(m_gameBtnDelete);
}
else
{
m_btnMgr.hide(m_gameBtnFavoriteOn);
m_btnMgr.hide(m_gameBtnFavoriteOff);
m_btnMgr.hide(m_gameBtnAdultOn);
m_btnMgr.hide(m_gameBtnAdultOff);
m_btnMgr.hide(m_gameBtnSettings);
m_btnMgr.hide(m_gameBtnDelete);
m_btnMgr.hide(m_gameBtnPlay);
m_btnMgr.hide(m_gameBtnBack);
for (u32 i = 0; i < ARRAY_SIZE(m_gameLblUser); ++i)
if (m_gameLblUser[i] != -1u)
m_btnMgr.hide(m_gameLblUser[i]);
}
}
m_gcfg1.save(true);
_hideGame();
}
void CMenu::_directlaunch(const string &id)
{
m_directLaunch = true;
for (int i = USB1; i < USB8; i++)
{
if(!DeviceHandler::Instance()->IsInserted(i)) continue;
DeviceHandler::Instance()->Open_WBFS(i);
CList<dir_discHdr> list;
string path = sfmt(GAMES_DIR, DeviceName[i]);
safe_vector<string> pathlist;
list.GetPaths(pathlist, id.c_str(), path,
strncasecmp(DeviceHandler::Instance()->PathToFSName(path.c_str()), "WBFS", 4) == 0);
m_gameList.clear();
list.GetHeaders(pathlist, m_gameList, m_settingsDir, m_curLanguage);
if(m_gameList.size() > 0)
{
gprintf("Game found on partition #%i\n", i);
_launch(&m_gameList[0]); // Launch will exit wiiflow
}
}
error(sfmt("Cannot find the game with ID: %s", id.c_str()));
}
void CMenu::_launch(dir_discHdr *hdr)
{
m_gcfg2.load(sfmt("%s/gameconfig2.ini", m_settingsDir.c_str()).c_str());
switch(m_current_view)
{
case COVERFLOW_HOMEBREW:
_launchHomebrew( (char *)hdr->path, m_homebrewArgs );
break;
case COVERFLOW_CHANNEL:
_launchChannel( hdr );
break;
case COVERFLOW_DML:
_launchGC( hdr, true );
break;
case COVERFLOW_USB:
default:
_launchGame( hdr, false );
break;
}
}
extern "C" {extern void USBStorage_Deinit(void);}
void CMenu::_launchGC(dir_discHdr *hdr, bool DML)
{
Nand::Instance()->Disable_Emu();
u8 DMLvideoMode = 0;
u8 GClanguage = 0;
if(has_enabled_providers() && _initNetwork() == 0)
add_game_to_card((char *)hdr->hdr.id);
if(DML)
{
#ifdef DML_THROUGH_MEM /*** Need special DML for this ***/
gprintf("Wiiflow DML: Launch game 'sd:/games/%s/game.iso' through memory\n", hdr->path);
*(vu32*)0x800A0000 = 0x4e444d4c;
memcpy((void *)0x800A0004, hdr->path, strlen(hdr->path) + 1);
DCFlushRange((void *)(0x800A0000), 4);
ICInvalidateRange((void *)(0x800A0000), 4);
#else
gprintf("Wiiflow DML: Launch game 'sd:/games/%s/game.iso' through boot.bin\n", hdr->path);
FILE *f;
f = fopen("sd:/games/boot.bin", "wb");
fwrite(hdr->path, 1, strlen(hdr->path) + 1, f);
fclose(f);
#endif
DMLvideoMode = min((u32)m_gcfg2.getInt((char *)hdr->hdr.id, "dml_video_mode", 0), ARRAY_SIZE(CMenu::_DMLvideoModes) - 1u);
if(DMLvideoMode == 0)
DMLvideoMode = min((u32)m_cfg.getInt("DML", "video_mode", 0), ARRAY_SIZE(CMenu::_GlobalDMLvideoModes) - 1u);
else
DMLvideoMode--;
GClanguage = min((u32)m_gcfg2.getInt((char *)hdr->hdr.id, "gc_language", 0), ARRAY_SIZE(CMenu::_GClanguages) - 1u);
if(GClanguage == 0)
GClanguage = min((u32)m_cfg.getInt("DML", "game_language", 0), ARRAY_SIZE(CMenu::_GlobalGClanguages) - 1u);
else
GClanguage--;
m_cfg.setString("DML", "current_item", (char *)hdr->hdr.id);
m_gcfg1.setInt("PLAYCOUNT", (char *)hdr->hdr.id, m_gcfg1.getInt("PLAYCOUNT", (char *)hdr->hdr.id, 0) + 1);
m_gcfg1.setUInt("LASTPLAYED", (char *)hdr->hdr.id, time(NULL));
m_gcfg1.save(true);
m_cfg.save(true);
CheckGameSoundThread();
cleanup();
Close_Inputs();
USBStorage_Deinit();
SDHC_Init();
WDVD_Init();
WDVD_StopMotor();
WDVD_Close();
//Tell DML to boot the game from sd card
*(vu32*)0x80001800 = 0xB002D105;
DCFlushRange((void *)(0x80001800), 4);
ICInvalidateRange((void *)(0x80001800), 4);
}
memcpy((char *)0x80000000, (char *)hdr->hdr.id, 6);
if((((char)hdr->hdr.id[3] == 'P') && (DMLvideoMode == 0)) || (DMLvideoMode == 1))
{
set_video_mode(1);
}
if((((char)hdr->hdr.id[3] != 'P') && (DMLvideoMode == 0)) || (DMLvideoMode == 2))
{
set_video_mode(0);
}
set_language(GClanguage);
VIDEO_SetBlack(TRUE);
VIDEO_Flush();
VIDEO_WaitVSync();
*(vu32*)0xCC003024 |= 7;
if(WII_LaunchTitle(0x100000100LL) < 0 )
Sys_LoadMenu();
}
void CMenu::_launchHomebrew(const char *filepath, safe_vector<std::string> arguments)
{
if(LoadHomebrew(filepath))
{
m_gcfg1.save(true);
m_gcfg2.save(true);
m_cat.save(true);
m_cfg.save(true);
AddBootArgument(filepath);
for(u32 i = 0; i < arguments.size(); ++i)
AddBootArgument(arguments[i].c_str());
Playlog_Delete();
cleanup();
Close_Inputs();
USBStorage_Deinit();
Nand::Instance()->Disable_Emu();
bootHB = true;
}
m_exit = true;
}
static const char systems[11] = { 'C', 'E', 'F', 'J', 'L', 'M', 'N', 'P', 'Q', 'W', 'H' };
void CMenu::_launchChannel(dir_discHdr *hdr)
{
Channels channel;
u8 ios = channel.GetRequestedIOS(hdr->hdr.chantitle);
u8 *data = NULL;
string id = string((const char *) hdr->hdr.id);
bool forwarder = true;
for (u8 num = 0; num < ARRAY_SIZE(systems); num++)
{
if(id[0] == systems[num])
{
forwarder = false;
break;
}
}
forwarder = m_gcfg2.getBool(id, "custom", forwarder) || strncmp(id.c_str(), "WIMC", 4) == 0;
if(!forwarder)
data = channel.Load(hdr->hdr.chantitle, (char *)id.c_str());
Nand::Instance()->Disable_Emu();
if(!forwarder && data == NULL) return;
bool vipatch = m_gcfg2.testOptBool(id, "vipatch", m_cfg.getBool("GENERAL", "vipatch", false));
bool cheat = m_gcfg2.testOptBool(id, "cheat", m_cfg.getBool("NAND", "cheat", false));
bool countryPatch = m_gcfg2.testOptBool(id, "country_patch", m_cfg.getBool("GENERAL", "country_patch", false));
u8 videoMode = (u8)min((u32)m_gcfg2.getInt(id, "video_mode", 0), ARRAY_SIZE(CMenu::_videoModes) - 1u);
int language = min((u32)m_gcfg2.getInt(id, "language", 0), ARRAY_SIZE(CMenu::_languages) - 1u);
const char *rtrn = m_gcfg2.getBool(id, "returnto", true) ? m_cfg.getString("GENERAL", "returnto").c_str() : NULL;
u8 patchVidMode = min((u32)m_gcfg2.getInt(id, "patch_video_modes", 0), ARRAY_SIZE(CMenu::_vidModePatch) - 1u);
bool disableIOSreload = m_gcfg2.testOptBool(id, "reload_block", m_cfg.getBool("GENERAL", "reload_block", false));
int aspectRatio = min((u32)m_gcfg2.getInt(id, "aspect_ratio", 0), ARRAY_SIZE(CMenu::_AspectRatio) - 1u)-1;
int gameIOS = 0;
if(!forwarder)
{
int userIOS = 0;
if (m_gcfg2.getInt(id, "ios", &userIOS) && _installed_cios.size() > 0)
{
for(CIOSItr itr = _installed_cios.begin(); itr != _installed_cios.end(); itr++)
{
if(itr->second == userIOS || itr->first == userIOS)
{
gameIOS = itr->first;
break;
}
else gameIOS = 0;
}
}
hooktype = (u32) m_gcfg2.getInt(id, "hooktype", 0);
debuggerselect = m_gcfg2.getBool(id, "debugger", false) ? 1 : 0;
if ((debuggerselect || cheat) && hooktype == 0) hooktype = 1;
if (!debuggerselect && !cheat) hooktype = 0;
if (videoMode == 0) videoMode = (u8)min((u32)m_cfg.getInt("GENERAL", "video_mode", 0), ARRAY_SIZE(CMenu::_videoModes) - 1);
if (language == 0) language = min((u32)m_cfg.getInt("GENERAL", "game_language", 0), ARRAY_SIZE(CMenu::_languages) - 1);
}
m_cfg.setString("NAND", "current_item", id);
m_gcfg1.setInt("PLAYCOUNT", id, m_gcfg1.getInt("PLAYCOUNT", id, 0) + 1);
m_gcfg1.setUInt("LASTPLAYED", id, time(NULL));
if(!forwarder && has_enabled_providers() && _initNetwork() == 0)
add_game_to_card(id.c_str());
bool emu_disabled = m_cfg.getBool("NAND", "disable", true);
bool emulate_mode = false;
int i = min(max(0, m_cfg.getInt("NAND", "emulation", 0)), (int)ARRAY_SIZE(CMenu::_NandEmu) - 1);
if (i==2)
emulate_mode = true;
m_gcfg1.save(true);
m_gcfg2.save(true);
m_cat.save(true);
m_cfg.save(true);
bool iosLoaded = false;
if(!forwarder)
{
setLanguage(language);
SmartBuf cheatFile;
u32 cheatSize = 0;
if (cheat) _loadFile(cheatFile, cheatSize, m_cheatDir.c_str(), fmt("%s.gct", hdr->hdr.id));
ocarina_load_code((u8 *) &hdr->hdr.id, cheatFile.get(), cheatSize);
// Reload IOS, if requested
if (gameIOS != mainIOS)
{
if(gameIOS < 0x64)
{
if ( _installed_cios.size() <= 0)
{
error(sfmt("No cios found!"));
Sys_LoadMenu();
}
u8 IOS[3];
IOS[0] = gameIOS == 0 ? ios : gameIOS;
IOS[1] = 56;
IOS[2] = 57;
bool found = false;
for(u8 num = 0; !found && num < 4; num++)
{
if(IOS[num] == 0) num++;
for(CIOSItr itr = _installed_cios.begin(); !found && itr != _installed_cios.end(); itr++)
{
if(itr->second == IOS[num] || itr->first == IOS[num])
{
gameIOS = itr->first;
found = true;
}
}
}
if(!found)
{
error(sfmt("Couldn't find a cIOS using base %i, or 56/57", IOS[0]));
return;
}
}
if (gameIOS != mainIOS)
{
gprintf("Reloading IOS into %d\n", gameIOS);
cleanup(true);
if(!loadIOS(gameIOS, true))
{
error(sfmt("Couldn't load IOS %i", gameIOS));
return;
}
iosLoaded = true;
}
}
}
if(!emu_disabled)
{
if(iosLoaded) ISFS_Deinitialize();
ISFS_Initialize();
Nand::Instance()->Set_FullMode(emulate_mode);
if(Nand::Instance()->Enable_Emu() < 0)
{
Nand::Instance()->Disable_Emu();
error(L"Enabling emu after reload failed!");
if(iosLoaded) Sys_LoadMenu();
return;
}
}
if (rtrn != NULL && strlen(rtrn) == 4)
{
int rtrnID = rtrn[0] << 24 | rtrn[1] << 16 | rtrn[2] << 8 | rtrn[3];
static ioctlv vector[1] ATTRIBUTE_ALIGN(32);
sm_title_id[0] = (((u64)(0x00010001) << 32) | (rtrnID&0xFFFFFFFF));
vector[0].data = sm_title_id;
vector[0].len = 8;
s32 ESHandle = IOS_Open("/dev/es", 0);
gprintf("Return to channel %s. Using new d2x way\n", IOS_Ioctlv(ESHandle, 0xA1, 1, 0, vector) != -101 ? "Succeeded" : "Failed!" );
IOS_Close(ESHandle);
}
CheckGameSoundThread();
cleanup();
Close_Inputs();
USBStorage_Deinit();
if(currentPartition == 0 && !forwarder)
SDHC_Init();
if(forwarder)
{
WII_Initialize();
if (WII_LaunchTitle(hdr->hdr.chantitle) < 0)
Sys_LoadMenu();
}
else if(!channel.Launch(data, hdr->hdr.chantitle, videoMode, vipatch, countryPatch, patchVidMode, disableIOSreload, aspectRatio))
Sys_LoadMenu();
}
void CMenu::_launchGame(dir_discHdr *hdr, bool dvd)
{
string id = string((const char *) hdr->hdr.id);
Nand::Instance()->Disable_Emu();
bool gc = false;
if (dvd)
{
u32 cover = 0;
Disc_SetUSB(NULL);
if (WDVD_GetCoverStatus(&cover) < 0)
{
error(L"WDVDGetCoverStatus Failed!");
if (BTN_B_PRESSED) return;
}
if (!(cover & 0x2))
{
error(L"Please insert a game disc.");
do {
WDVD_GetCoverStatus(&cover);
if (BTN_B_PRESSED) return;
} while(!(cover & 0x2));
}
/* Open Disc */
if (Disc_Open() < 0)
{
error(L"Cannot Read DVD.");
if (BTN_B_PRESSED) return;
}
/* Check disc */
if (Disc_IsWii() < 0)
{
if (Disc_IsGC() < 0)
{
error(L"This is not a Wii or GC disc");
if (BTN_B_PRESSED) return;
}
else
gc = true;
}
/* Read header */
struct discHdr *header = (struct discHdr *)MEM2_alloc(sizeof(struct discHdr));
Disc_ReadHeader(header);
for (int i = 0;i < 6; i++)
id[i] = header->id[i];
SAFE_FREE(header);
}
bool vipatch = m_gcfg2.testOptBool(id, "vipatch", m_cfg.getBool("GENERAL", "vipatch", false));
bool cheat = m_gcfg2.testOptBool(id, "cheat", m_cfg.getBool("GAMES", "cheat", false));
bool countryPatch = m_gcfg2.testOptBool(id, "country_patch", m_cfg.getBool("GENERAL", "country_patch", false));
u8 videoMode = (u8)min((u32)m_gcfg2.getInt(id, "video_mode", 0), ARRAY_SIZE(CMenu::_videoModes) - 1u);
int language = min((u32)m_gcfg2.getInt(id, "language", 0), ARRAY_SIZE(CMenu::_languages) - 1u);
const char *rtrn = m_gcfg2.getBool(id, "returnto", true) ? m_cfg.getString("GENERAL", "returnto").c_str() : NULL;
bool disableIOSreload = m_gcfg2.testOptBool(id, "reload_block", m_cfg.getBool("GENERAL", "reload_block", false));
int aspectRatio = min((u32)m_gcfg2.getInt(id, "aspect_ratio", 0), ARRAY_SIZE(CMenu::_AspectRatio) - 1u)-1;
int emuPartition = m_cfg.getInt("GAMES", "savepartition", -1);
if(emuPartition == -1)
emuPartition = m_cfg.getInt("NAND", "partition", 0);
string emuPath = m_cfg.getString("GAMES", "savepath", m_cfg.getString("NAND", "path", ""));
u8 emuSave = min((u32)m_gcfg2.getInt(id, "emulate_save", 0), ARRAY_SIZE(CMenu::_SaveEmu) - 1u);
if (emuSave == 0)
{
emuSave = min(max(0, m_cfg.getInt("GAMES", "save_emulation", 0)), (int)ARRAY_SIZE(CMenu::_GlobalSaveEmu) - 1);
if (emuSave != 0)
emuSave++;
}
else if (emuSave == 1)
emuSave = 0;
if (!dvd && get_frag_list((u8 *) hdr->hdr.id, (char *) hdr->path, currentPartition == 0 ? 0x200 : sector_size) < 0)
return;
if(!dvd && emuSave)
{
char basepath[64];
snprintf(basepath, 64, "%s:%s", DeviceName[emuPartition], emuPath.c_str());
CreateSavePath(basepath, hdr);
}
int gameIOS = 0;
int userIOS = 0;
if (m_gcfg2.getInt(id, "ios", &userIOS) && _installed_cios.size() > 0)
{
for(CIOSItr itr = _installed_cios.begin(); itr != _installed_cios.end(); itr++)
{
if(itr->second == userIOS || itr->first == userIOS)
{
gameIOS = itr->first;
break;
}
else gameIOS = 0;
}
}
u8 patchVidMode = min((u32)m_gcfg2.getInt(id, "patch_video_modes", 0), ARRAY_SIZE(CMenu::_vidModePatch) - 1u);
hooktype = (u32) m_gcfg2.getInt(id, "hooktype", 0); // hooktype is defined in patchcode.h
debuggerselect = m_gcfg2.getBool(id, "debugger", false) ? 1 : 0; // debuggerselect is defined in fst.h
if ((debuggerselect || cheat) && hooktype == 0) hooktype = 1;
if (!debuggerselect && !cheat) hooktype = 0;
if (id == "RPWE41" || id == "RPWZ41" || id == "SPXP41") // Prince of Persia, Rival Swords
debuggerselect = false;
SmartBuf cheatFile, gameconfig;
u32 cheatSize = 0, gameconfigSize = 0;
bool iosLoaded = false;
CheckGameSoundThread();
if (videoMode == 0) videoMode = (u8)min((u32)m_cfg.getInt("GENERAL", "video_mode", 0), ARRAY_SIZE(CMenu::_videoModes) - 1);
if (language == 0) language = min((u32)m_cfg.getInt("GENERAL", "game_language", 0), ARRAY_SIZE(CMenu::_languages) - 1);
m_cfg.setString("GAMES", "current_item", id);
m_gcfg1.setInt("PLAYCOUNT", id, m_gcfg1.getInt("PLAYCOUNT", id, 0) + 1);
m_gcfg1.setUInt("LASTPLAYED", id, time(NULL));
if (has_enabled_providers() && _initNetwork() == 0)
add_game_to_card(id.c_str());
m_gcfg1.save(true);
m_gcfg2.save(true);
m_cat.save(true);
m_cfg.save(true);
setLanguage(language);
if (cheat) _loadFile(cheatFile, cheatSize, m_cheatDir.c_str(), fmt("%s.gct", hdr->hdr.id));
_loadFile(gameconfig, gameconfigSize, m_txtCheatDir.c_str(), "gameconfig.txt");
load_wip_patches((u8 *) m_wipDir.c_str(), (u8 *) &hdr->hdr.id);
app_gameconfig_load((u8 *) &hdr->hdr.id, gameconfig.get(), gameconfigSize);
ocarina_load_code((u8 *) &hdr->hdr.id, cheatFile.get(), cheatSize);
net_wc24cleanup();
// Reload IOS, if requested
if (!dvd && gameIOS != mainIOS)
{
if(gameIOS < 0x64)
{
if ( _installed_cios.size() <= 0)
{
error(sfmt("No cios found!"));
Sys_LoadMenu();
}
u8 IOS[3];
IOS[0] = gameIOS == 0 ? GetRequestedGameIOS(hdr) : gameIOS;
IOS[1] = 56;
IOS[2] = 57;
gprintf("Game requested IOS: %u\n", IOS[0]);
bool found = false;
for(u8 num = 0; !found && num < 4; num++)
{
if(IOS[num] == 0) num++;
for(CIOSItr itr = _installed_cios.begin(); !found && itr != _installed_cios.end(); itr++)
{
if(itr->second == IOS[num])
{
gameIOS = itr->first;
found = true;
}
}
}
if(!found)
{
error(sfmt("Couldn't find a cIOS using base %i, or 56/57", IOS[0]));
return;
}
}
if (gameIOS != mainIOS)
{
gprintf("Reloading IOS into %d\n", gameIOS);
cleanup(true);
if(!loadIOS(gameIOS, true))
{
error(sfmt("Couldn't load IOS %i", gameIOS));
return;
}
iosLoaded = true;
}
}
if(emuSave)
{
if(iosLoaded) ISFS_Deinitialize();
ISFS_Initialize();
Nand::Instance()->Init(emuPath.c_str(), emuPartition, false);
DeviceHandler::Instance()->UnMount(emuPartition);
if (emuSave == 3)
Nand::Instance()->Set_FullMode(true);
else
Nand::Instance()->Set_FullMode(false);
if(Nand::Instance()->Enable_Emu() < 0)
{
Nand::Instance()->Disable_Emu();
error(L"Enabling emu after reload failed!");
if (iosLoaded) Sys_LoadMenu();
return;
}
if(!DeviceHandler::Instance()->IsInserted(currentPartition))
DeviceHandler::Instance()->Mount(currentPartition);
DeviceHandler::Instance()->Mount(emuPartition);
}
if (!m_directLaunch)
{
if (rtrn != NULL && strlen(rtrn) == 4)
{
int rtrnID = rtrn[0] << 24 | rtrn[1] << 16 | rtrn[2] << 8 | rtrn[3];
static ioctlv vector[1] ATTRIBUTE_ALIGN(32);
sm_title_id[0] = (((u64)(0x00010001) << 32) | (rtrnID&0xFFFFFFFF));
vector[0].data = sm_title_id;
vector[0].len = 8;
s32 ESHandle = IOS_Open("/dev/es", 0);
gprintf("Return to channel %s. Using new d2x way\n", IOS_Ioctlv(ESHandle, 0xA1, 1, 0, vector) != -101 ? "succeeded" : "failed!");
IOS_Close(ESHandle);
}
}
if (!dvd)
{
s32 ret = Disc_SetUSB((u8 *) hdr->hdr.id);
if (ret < 0)
{
gprintf("Set USB failed: %d\n", ret);
error(wfmt(L"Set USB failed: %d\n", ret).c_str());
if (iosLoaded) Sys_LoadMenu();
return;
}
if (Disc_Open() < 0)
{
error(L"Disc_Open failed");
if (iosLoaded) Sys_LoadMenu();
return;
}
}
cleanup();
Close_Inputs();
USBStorage_Deinit();
if(currentPartition == 0)
SDHC_Init();
if(gc)
{
memcpy((char*)hdr->hdr.id, id.c_str(),6);
_launchGC( hdr, false );
}
else
{
gprintf("Booting game\n");
if (Disc_WiiBoot(videoMode, vipatch, countryPatch, patchVidMode, disableIOSreload, aspectRatio) < 0)
Sys_LoadMenu();
}
}
void CMenu::_initGameMenu(CMenu::SThemeData &theme)
{
CColor fontColor(0xD0BFDFFF);
STexture texFavOn;
STexture texFavOnSel;
STexture texFavOff;
STexture texFavOffSel;
STexture texAdultOn;
STexture texAdultOnSel;
STexture texAdultOff;
STexture texAdultOffSel;
STexture texDelete;
STexture texDeleteSel;
STexture texSettings;
STexture texSettingsSel;
STexture bgLQ;
texFavOn.fromPNG(favoriteson_png);
texFavOnSel.fromPNG(favoritesons_png);
texFavOff.fromPNG(favoritesoff_png);
texFavOffSel.fromPNG(favoritesoffs_png);
texAdultOn.fromPNG(stopkidon_png);
texAdultOnSel.fromPNG(stopkidons_png);
texAdultOff.fromPNG(stopkidoff_png);
texAdultOffSel.fromPNG(stopkidoffs_png);
texDelete.fromPNG(delete_png);
texDeleteSel.fromPNG(deletes_png);
texSettings.fromPNG(btngamecfg_png);
texSettingsSel.fromPNG(btngamecfgs_png);
_addUserLabels(theme, m_gameLblUser, ARRAY_SIZE(m_gameLblUser), "GAME");
m_gameBg = _texture(theme.texSet, "GAME/BG", "texture", theme.bg);
if (m_theme.loaded() && STexture::TE_OK == bgLQ.fromPNGFile(sfmt("%s/%s", m_themeDataDir.c_str(), m_theme.getString("GAME/BG", "texture").c_str()).c_str(), GX_TF_CMPR, ALLOC_MEM2, 64, 64))
m_gameBgLQ = bgLQ;
m_gameBtnPlay = _addButton(theme, "GAME/PLAY_BTN", theme.btnFont, L"", 420, 344, 200, 56, theme.btnFontColor);
m_gameBtnBack = _addButton(theme, "GAME/BACK_BTN", theme.btnFont, L"", 420, 400, 200, 56, theme.btnFontColor);
m_gameBtnFavoriteOn = _addPicButton(theme, "GAME/FAVORITE_ON", texFavOn, texFavOnSel, 460, 170, 48, 48);
m_gameBtnFavoriteOff = _addPicButton(theme, "GAME/FAVORITE_OFF", texFavOff, texFavOffSel, 460, 170, 48, 48);
m_gameBtnAdultOn = _addPicButton(theme, "GAME/ADULTONLY_ON", texAdultOn, texAdultOnSel, 532, 170, 48, 48);
m_gameBtnAdultOff = _addPicButton(theme, "GAME/ADULTONLY_OFF", texAdultOff, texAdultOffSel, 532, 170, 48, 48);
m_gameBtnSettings = _addPicButton(theme, "GAME/SETTINGS_BTN", texSettings, texSettingsSel, 460, 242, 48, 48);
m_gameBtnDelete = _addPicButton(theme, "GAME/DELETE_BTN", texDelete, texDeleteSel, 532, 242, 48, 48);
m_gameButtonsZone.x = m_theme.getInt("GAME/ZONES", "buttons_x", 0);
m_gameButtonsZone.y = m_theme.getInt("GAME/ZONES", "buttons_y", 0);
m_gameButtonsZone.w = m_theme.getInt("GAME/ZONES", "buttons_w", 640);
m_gameButtonsZone.h = m_theme.getInt("GAME/ZONES", "buttons_h", 480);
m_gameButtonsZone.hide = m_theme.getBool("GAME/ZONES", "buttons_hide", true);
_setHideAnim(m_gameBtnPlay, "GAME/PLAY_BTN", 200, 0, 1.f, 0.f);
_setHideAnim(m_gameBtnBack, "GAME/BACK_BTN", 200, 0, 1.f, 0.f);
_setHideAnim(m_gameBtnFavoriteOn, "GAME/FAVORITE_ON", 0, 0, -1.5f, -1.5f);
_setHideAnim(m_gameBtnFavoriteOff, "GAME/FAVORITE_OFF", 0, 0, -1.5f, -1.5f);
_setHideAnim(m_gameBtnAdultOn, "GAME/ADULTONLY_ON", 0, 0, -1.5f, -1.5f);
_setHideAnim(m_gameBtnAdultOff, "GAME/ADULTONLY_OFF", 0, 0, -1.5f, -1.5f);
_setHideAnim(m_gameBtnSettings, "GAME/SETTINGS_BTN", 0, 0, -1.5f, -1.5f);
_setHideAnim(m_gameBtnDelete, "GAME/DELETE_BTN", 0, 0, -1.5f, -1.5f);
_hideGame(true);
_textGame();
}
void CMenu::_textGame(void)
{
m_btnMgr.setText(m_gameBtnPlay, _t("gm1", L"Play"));
m_btnMgr.setText(m_gameBtnBack, _t("gm2", L"Back"));
}
struct IMD5Header
{
u32 fcc;
u32 filesize;
u8 zeroes[8];
u8 crypto[16];
} __attribute__((packed));
SmartBuf gameSoundThreadStack;
void CMenu::_gameSoundThread(CMenu *m)
{
if(m->m_current_view == COVERFLOW_DML)
{
m->m_gameSound.Load(gc_ogg, gc_ogg_size, false);
m->m_gamesound_changed = true;
return;
}
m->m_gamesound_changed = false;
u32 sndSize = 0;
m->m_gameSoundHdr = m->m_cf.getHdr();
Banner *banner = m->m_current_view == COVERFLOW_USB ?
_extractBnr(m->m_gameSoundHdr) : m->m_current_view == COVERFLOW_CHANNEL ?
_extractChannelBnr(m->m_gameSoundHdr->hdr.chantitle) : NULL;
m->m_gameSoundHdr = NULL;
if (banner == NULL || !banner->IsValid())
{
gprintf("no valid banner found\n");
SAFE_DELETE(banner);
return;
}
_extractBannerTitle(banner, GetLanguage(m->m_loc.getString(m->m_curLanguage, "gametdb_code", "EN").c_str()));
const u8 *soundBin = banner->GetFile((char *) "sound.bin", &sndSize);
SAFE_DELETE(banner);
if (soundBin == NULL || (((IMD5Header *)soundBin)->fcc != 'IMD5' && ((IMD5Header *)soundBin)->fcc != 'RIFF'))
{
gprintf("Failed to load banner sound!\n\n");
return;
}
m->m_gameSound.Load(soundBin, sndSize, false);
m->m_gamesound_changed = true;
}
void CMenu::_playGameSound(void)
{
m_gamesound_changed = false;
if (m_bnrSndVol == 0) return;
CheckGameSoundThread();
unsigned int stack_size = (unsigned int)32768;
SMART_FREE(gameSoundThreadStack);
gameSoundThreadStack = smartMem2Alloc(stack_size);
LWP_CreateThread(&m_gameSoundThread, (void *(*)(void *))CMenu::_gameSoundThread, (void *)this, gameSoundThreadStack.get(), stack_size, 40);
}
void CMenu::CheckGameSoundThread()
{
if(LWP_ThreadIsSuspended(m_gameSoundThread))
LWP_ResumeThread(m_gameSoundThread);
LWP_JoinThread(m_gameSoundThread, NULL);
SMART_FREE(gameSoundThreadStack);
m_gameSoundThread = LWP_THREAD_NULL;
}
void CMenu::CheckThreads()
{
//CheckGameSoundThread(force);
//m_vid.CheckWaitThread(force);
#ifdef SHOWMEMGECKO
mem1 = SYS_GetArena1Size();
mem2 = MEM2_freesize();
if( mem1 != mem1old )
{
mem1old = mem1;
gprintf("Mem1 Free: %u\n", mem1);
}
if( mem2 != mem2old )
{
mem2old = mem2;
gprintf("Mem2 Free: %u\n", mem2);
}
#endif
}