Subversion Repositories psp

[/] [branches/] [smsplus_adhoc/] [psp/] [menu.c] - Rev 354

Compare with Previous | Blame | View Log

#include "menu.h"
 
#include <time.h>
#include <psptypes.h>
#include <psprtc.h>
#include <malloc.h>
#include <string.h>
#include <pspkernel.h>
 
#include "emumain.h"
 
#include "types.h"
#include "loadrom.h"
#include "system.h"
#include "state.h"
#include "shared.h"
 
#include "file.h"
#include "image.h"
#include "ui.h"
#include "menu.h"
#include "ctrl.h"
#include "psp.h"
#include "util.h"
#include "init.h"
 
#define TAB_QUICKLOAD 0
#define TAB_STATE     1
#define TAB_CONTROL   2
#define TAB_OPTION    3
#define TAB_NETPLAY   4
#define TAB_SYSTEM    5
#define TAB_ABOUT     6
#define TAB_MAX       TAB_SYSTEM
 
#define OPTION_DISPLAY_MODE 1
#define OPTION_SYNC_FREQ    2
#define OPTION_FRAMESKIP    3
#define OPTION_VSYNC        4
#define OPTION_CLOCK_FREQ   5
#define OPTION_SHOW_FPS     6
#define OPTION_CONTROL_MODE 7
#define OPTION_ANIMATE      8
 
#define SYSTEM_SCRNSHOT     1
#define SYSTEM_RESET        2
#define SYSTEM_VERT_STRIP   3
#define SYSTEM_SOUND_ENGINE 4
#define SYSTEM_SOUND_BOOST  5
 
#define NETPLAY_HOST 1
#define NETPLAY_JOIN 2
#define NETPLAY_DISC 3
 
extern PspImage *Screen;
 
EmulatorOptions Options;
 
int AdhocMode;
PspMAC OpponentMAC;
 
static int TabIndex;
static int ResumeEmulation;
static PspImage *Background;
static PspImage *NoSaveIcon;
 
static const char *QuickloadFilter[] = { "SMS", "GG", "ZIP", '\0' },
  PresentSlotText[] = "\026\244\020 Save\t\026\001\020 Load\t\026\243\020 Delete",
  EmptySlotText[] = "\026\244\020 Save",
  ControlHelpText[] = "\026\250\020 Change mapping\t\026\001\020 Save to \271\t\026\243\020 Load defaults";
 
static const char *ScreenshotDir = "screens";
static const char *SaveStateDir = "savedata";
static const char *ButtonConfigFile = "buttons";
static const char *OptionsFile = "smsplus.ini";
 
char *GameName;
char *ScreenshotPath;
static char *SaveStatePath;
static char *GamePath;
 
#define WIDTH  256
#define HEIGHT 192
 
/* Tab labels */
static const char *TabLabel[] = 
{
  "Game",
  "Save/Load",
  "Controls",
  "Options",
  "Netplay",
  "System",
  "About"
};
 
static int JoinGame();
static int HostGame();
 
static void LoadOptions();
static int  SaveOptions();
 
static void InitButtonConfig();
static int  SaveButtonConfig();
static int  LoadButtonConfig();
 
static void        DisplayStateTab();
static PspImage*   LoadStateIcon(const char *path);
static int         LoadState(const char *path);
static PspImage*   SaveState(const char *path, PspImage *icon);
 
static int OnMenuItemChanged(const struct PspUiMenu *uimenu, PspMenuItem* item, 
  const PspMenuOption* option);
static int OnMenuOk(const void *uimenu, const void* sel_item);
static int OnMenuButtonPress(const struct PspUiMenu *uimenu, 
  PspMenuItem* sel_item, u32 button_mask);
 
static int OnSplashButtonPress(const struct PspUiSplash *splash, 
  u32 button_mask);
static void OnSplashRender(const void *uiobject, const void *null);
 
static int OnGenericCancel(const void *uiobject, const void *param);
static void OnGenericRender(const void *uiobject, const void *item_obj);
static int OnGenericButtonPress(const PspUiFileBrowser *browser, 
  const char *path, u32 button_mask);
 
static int OnSaveStateOk(const void *gallery, const void *item);
static int OnSaveStateButtonPress(const PspUiGallery *gallery, 
  PspMenuItem* item, u32 button_mask);
 
static int OnQuickloadOk(const void *browser, const void *path);
 
void OnSystemRender(const void *uiobject, const void *item_obj);
 
/* Define various menu options */
static const PspMenuOptionDef
  SoundEngineOptions[] = {
    MENU_OPTION("Disabled",      SND_NULL),
    MENU_OPTION("Faster",        SND_YM2413),
    MENU_OPTION("More accurate", SND_EMU2413),
    MENU_END_OPTIONS
  },
  SoundBoostOptions[] = {
    MENU_OPTION("Off", 0),
    MENU_OPTION("2x",  1),
    MENU_OPTION("4x",  2),
    MENU_END_OPTIONS
  },
  ToggleOptions[] = {
    MENU_OPTION("Disabled", 0),
    MENU_OPTION("Enabled",  1),
    MENU_END_OPTIONS
  },
  ScreenSizeOptions[] = {
    MENU_OPTION("Actual size",              DISPLAY_MODE_UNSCALED),
    MENU_OPTION("4:3 scaled (fit height)",  DISPLAY_MODE_FIT_HEIGHT),
    MENU_OPTION("16:9 scaled (fit screen)", DISPLAY_MODE_FILL_SCREEN),
    MENU_END_OPTIONS
  },
  FrameLimitOptions[] = {
    MENU_OPTION("Disabled",      0),
    MENU_OPTION("60 fps (NTSC)", 60),
    MENU_END_OPTIONS
  },
  FrameSkipOptions[] = {
    MENU_OPTION("No skipping",  0),
    MENU_OPTION("Skip 1 frame", 1),
    MENU_OPTION("Skip 2 frames",2),
    MENU_OPTION("Skip 3 frames",3),
    MENU_OPTION("Skip 4 frames",4),
    MENU_OPTION("Skip 5 frames",5),
    MENU_END_OPTIONS
  },
  PspClockFreqOptions[] = {
    MENU_OPTION("222 MHz", 222),
    MENU_OPTION("266 MHz", 266),
    MENU_OPTION("300 MHz", 300),
    MENU_OPTION("333 MHz", 333),
    MENU_END_OPTIONS
  },
  ControlModeOptions[] = {
    MENU_OPTION("\026\242\020 cancels, \026\241\020 confirms (US)",    0),
    MENU_OPTION("\026\241\020 cancels, \026\242\020 confirms (Japan)", 1),
    MENU_END_OPTIONS
  },
  ButtonMapOptions[] = {
    /* Unmapped */
    MENU_OPTION("None", 0),
    /* Special */
    MENU_OPTION("Special: Open Menu", SPC|SPC_MENU),
    /* Joystick */
    MENU_OPTION("Joystick Up",    JOY|INPUT_UP),
    MENU_OPTION("Joystick Down",  JOY|INPUT_DOWN),
    MENU_OPTION("Joystick Left",  JOY|INPUT_LEFT),
    MENU_OPTION("Joystick Right", JOY|INPUT_RIGHT),
    MENU_OPTION("Joystick Button I",  JOY|INPUT_BUTTON1),
    MENU_OPTION("Joystick Button II", JOY|INPUT_BUTTON2),
    /* Joystick */
    MENU_OPTION("Start (GG) / Pause (SMS)", SYS|INPUT_START|INPUT_PAUSE),
    MENU_OPTION("Soft Reset (SMS)", SYS|INPUT_RESET),
    MENU_END_OPTIONS
  };
 
static const PspMenuItemDef
  OptionMenuDef[] = {
    MENU_HEADER("Video"),
    MENU_ITEM("Screen size", OPTION_DISPLAY_MODE, ScreenSizeOptions, -1,
      "\026\250\020 Change screen size"),
    MENU_HEADER("Performance"),
    MENU_ITEM("Frame limiter", OPTION_SYNC_FREQ, FrameLimitOptions, -1, 
      "\026\250\020 Change screen update frequency"),
    MENU_ITEM("Frame skipping", OPTION_FRAMESKIP, FrameSkipOptions, -1, 
      "\026\250\020 Change number of frames skipped per update"),
    MENU_ITEM("VSync", OPTION_VSYNC, ToggleOptions, -1,
      "\026\250\020 Enable to reduce tearing; disable to increase speed"),
    MENU_ITEM("PSP clock frequency", OPTION_CLOCK_FREQ, PspClockFreqOptions, -1,
      "\026\250\020 Larger values: faster emulation, faster battery depletion (default: 222MHz)"),
    MENU_ITEM("Show FPS counter",    OPTION_SHOW_FPS, ToggleOptions, -1,
      "\026\250\020 Show/hide the frames-per-second counter"),
    MENU_HEADER("Menu"),
    MENU_ITEM("Button mode", OPTION_CONTROL_MODE, ControlModeOptions,  -1, 
      "\026\250\020 Change OK and Cancel button mapping"),
    MENU_ITEM("Animations", OPTION_ANIMATE, ToggleOptions,  -1, 
      "\026\250\020 Enable/disable in-menu animations"),
    MENU_END_ITEMS
  },
  ControlMenuDef[] = {
    MENU_ITEM(PSP_CHAR_ANALUP, MAP_ANALOG_UP, ButtonMapOptions, -1, 
      ControlHelpText),
    MENU_ITEM(PSP_CHAR_ANALDOWN, MAP_ANALOG_DOWN, ButtonMapOptions, -1, 
      ControlHelpText),
    MENU_ITEM(PSP_CHAR_ANALLEFT, MAP_ANALOG_LEFT, ButtonMapOptions, -1,
      ControlHelpText),
    MENU_ITEM(PSP_CHAR_ANALRIGHT, MAP_ANALOG_RIGHT, ButtonMapOptions, -1,
      ControlHelpText),
    MENU_ITEM(PSP_CHAR_UP, MAP_BUTTON_UP, ButtonMapOptions, -1, 
      ControlHelpText),
    MENU_ITEM(PSP_CHAR_DOWN, MAP_BUTTON_DOWN, ButtonMapOptions, -1, 
      ControlHelpText),
    MENU_ITEM(PSP_CHAR_LEFT, MAP_BUTTON_LEFT, ButtonMapOptions, -1,
      ControlHelpText),
    MENU_ITEM(PSP_CHAR_RIGHT, MAP_BUTTON_RIGHT, ButtonMapOptions, -1,
      ControlHelpText),
    MENU_ITEM(PSP_CHAR_SQUARE, MAP_BUTTON_SQUARE, ButtonMapOptions, -1,
      ControlHelpText),
    MENU_ITEM(PSP_CHAR_CROSS, MAP_BUTTON_CROSS, ButtonMapOptions, -1,
      ControlHelpText),
    MENU_ITEM(PSP_CHAR_CIRCLE, MAP_BUTTON_CIRCLE, ButtonMapOptions, -1,
      ControlHelpText),
    MENU_ITEM(PSP_CHAR_TRIANGLE, MAP_BUTTON_TRIANGLE, ButtonMapOptions, 
      -1, ControlHelpText),
    MENU_ITEM(PSP_CHAR_LTRIGGER, MAP_BUTTON_LTRIGGER, ButtonMapOptions, 
      -1, ControlHelpText),
    MENU_ITEM(PSP_CHAR_RTRIGGER, MAP_BUTTON_RTRIGGER, ButtonMapOptions, 
      -1, ControlHelpText),
    MENU_ITEM(PSP_CHAR_SELECT, MAP_BUTTON_SELECT, ButtonMapOptions, 
      -1, ControlHelpText),
    MENU_ITEM(PSP_CHAR_START, MAP_BUTTON_START, ButtonMapOptions, -1, 
      ControlHelpText),
    MENU_ITEM(PSP_CHAR_LTRIGGER"+"PSP_CHAR_RTRIGGER, 
      MAP_BUTTON_LRTRIGGERS, ButtonMapOptions, -1, ControlHelpText),
    MENU_ITEM(PSP_CHAR_START"+"PSP_CHAR_SELECT,
      MAP_BUTTON_STARTSELECT, ButtonMapOptions, -1, ControlHelpText),
    MENU_END_ITEMS
  },
  SystemMenuDef[] = {
    MENU_HEADER("Audio"),
    MENU_ITEM("FM Emulation", SYSTEM_SOUND_ENGINE, SoundEngineOptions, -1,
      "\026\250\020 Select FM emulation engine"),
    MENU_ITEM("Sound Boost", SYSTEM_SOUND_BOOST, SoundBoostOptions, -1,
      "\026\250\020 Adjust volume scaling factor"),
    MENU_HEADER("Video"),
    MENU_ITEM("Vertical bar", SYSTEM_VERT_STRIP, ToggleOptions, -1,
      "\026\250\020 Show/hide the leftmost vertical bar (SMS)"),
    MENU_HEADER("System"),
    MENU_ITEM("Reset", SYSTEM_RESET, NULL, -1, "\026\001\020 Reset"),
    MENU_ITEM("Save screenshot",  SYSTEM_SCRNSHOT, NULL, -1, 
      "\026\001\020 Save screenshot"),
    MENU_END_ITEMS
  },
  NetplayMenuDef[] = {
    MENU_HEADER("Game"),
    MENU_ITEM("Host game", NETPLAY_HOST, NULL, -1,
      "\026\001\020 Host a wi-fi game"),
    MENU_ITEM("Join game", NETPLAY_JOIN, NULL, -1,
      "\026\001\020 Join a wi-fi game"),
    MENU_HEADER("Connection"),
    MENU_ITEM("Disconnect", NETPLAY_DISC, NULL, -1,
      "\026\001\020 Disconnect from a game in progress"),
    MENU_END_ITEMS
  };
 
PspUiSplash SplashScreen =
{
  OnSplashRender,
  OnGenericCancel,
  OnSplashButtonPress,
  NULL
};
 
PspUiGallery SaveStateGallery = 
{
  NULL,                        /* PspMenu */
  OnGenericRender,             /* OnRender() */
  OnSaveStateOk,               /* OnOk() */
  OnGenericCancel,             /* OnCancel() */
  OnSaveStateButtonPress,      /* OnButtonPress() */
  NULL                         /* Userdata */
};
 
PspUiMenu OptionUiMenu =
{
  NULL,                  /* PspMenu */
  OnGenericRender,       /* OnRender() */
  OnMenuOk,              /* OnOk() */
  OnGenericCancel,       /* OnCancel() */
  OnMenuButtonPress,     /* OnButtonPress() */
  OnMenuItemChanged,     /* OnItemChanged() */
};
 
PspUiMenu ControlUiMenu =
{
  NULL,                  /* PspMenu */
  OnGenericRender,       /* OnRender() */
  OnMenuOk,              /* OnOk() */
  OnGenericCancel,       /* OnCancel() */
  OnMenuButtonPress,     /* OnButtonPress() */
  OnMenuItemChanged,     /* OnItemChanged() */
};
 
PspUiFileBrowser QuickloadBrowser = 
{
  OnGenericRender,
  OnQuickloadOk,
  OnGenericCancel,
  OnGenericButtonPress,
  QuickloadFilter,
  0
};
 
PspUiMenu SystemUiMenu =
{
  NULL,                  /* PspMenu */
  OnSystemRender,        /* OnRender() */
  OnMenuOk,              /* OnOk() */
  OnGenericCancel,       /* OnCancel() */
  OnMenuButtonPress,     /* OnButtonPress() */
  OnMenuItemChanged,     /* OnItemChanged() */
};
 
PspUiMenu NetplayUiMenu =
{
  NULL,                  /* PspMenu */
  OnGenericRender,       /* OnRender() */
  OnMenuOk,              /* OnOk() */
  OnGenericCancel,       /* OnCancel() */
  OnMenuButtonPress,     /* OnButtonPress() */
  OnMenuItemChanged,     /* OnItemChanged() */
};
 
/* Game configuration (includes button maps) */
struct ButtonConfig ActiveConfig;
 
/* Default configuration */
struct ButtonConfig DefaultConfig =
{
  {
    JOY|INPUT_UP,     /* Analog Up    */
    JOY|INPUT_DOWN,   /* Analog Down  */
    JOY|INPUT_LEFT,   /* Analog Left  */
    JOY|INPUT_RIGHT,  /* Analog Right */
    JOY|INPUT_UP,     /* D-pad Up     */
    JOY|INPUT_DOWN,   /* D-pad Down   */
    JOY|INPUT_LEFT,   /* D-pad Left   */
    JOY|INPUT_RIGHT,  /* D-pad Right  */
    JOY|INPUT_BUTTON2,/* Square       */
    JOY|INPUT_BUTTON1,/* Cross        */
    0,                /* Circle       */
    0,                /* Triangle     */
    0,                /* L Trigger    */
    0,                /* R Trigger    */
    0,                /* Select       */
    SYS|INPUT_START|INPUT_PAUSE,
                      /* Start        */
    SPC|SPC_MENU,     /* L+R Triggers */
    0,                /* Start+Select */
  }
};
 
/* Button masks */
const u64 ButtonMask[] = 
{
  PSP_CTRL_LTRIGGER | PSP_CTRL_RTRIGGER, 
  PSP_CTRL_START    | PSP_CTRL_SELECT,
  PSP_CTRL_ANALUP,    PSP_CTRL_ANALDOWN,
  PSP_CTRL_ANALLEFT,  PSP_CTRL_ANALRIGHT,
  PSP_CTRL_UP,        PSP_CTRL_DOWN,
  PSP_CTRL_LEFT,      PSP_CTRL_RIGHT,
  PSP_CTRL_SQUARE,    PSP_CTRL_CROSS,
  PSP_CTRL_CIRCLE,    PSP_CTRL_TRIANGLE,
  PSP_CTRL_LTRIGGER,  PSP_CTRL_RTRIGGER,
  PSP_CTRL_SELECT,    PSP_CTRL_START,
  0 /* End */
};
 
/* Button map ID's */
const int ButtonMapId[] = 
{
  MAP_BUTTON_LRTRIGGERS, 
  MAP_BUTTON_STARTSELECT,
  MAP_ANALOG_UP,       MAP_ANALOG_DOWN,
  MAP_ANALOG_LEFT,     MAP_ANALOG_RIGHT,
  MAP_BUTTON_UP,       MAP_BUTTON_DOWN,
  MAP_BUTTON_LEFT,     MAP_BUTTON_RIGHT,
  MAP_BUTTON_SQUARE,   MAP_BUTTON_CROSS,
  MAP_BUTTON_CIRCLE,   MAP_BUTTON_TRIANGLE,
  MAP_BUTTON_LTRIGGER, MAP_BUTTON_RTRIGGER,
  MAP_BUTTON_SELECT,   MAP_BUTTON_START,
  -1 /* End */
};
 
void InitMenu()
{
  /* Reset variables */
  TabIndex = TAB_ABOUT;
  Background = NULL;
  GameName = NULL;
  GamePath = NULL;
  AdhocMode = ADHOC_NONE;
 
  /* Initialize options */
  LoadOptions();
 
  InitEmulator();
 
  /* Load the background image */
  Background = pspImageLoadPng("background.png");
 
  /* Init NoSaveState icon image */
  NoSaveIcon=pspImageCreate(136, 114, PSP_IMAGE_16BPP);
  pspImageClear(NoSaveIcon, RGB(0x0c,0,0x3f));
 
  /* Initialize state menu */
  SaveStateGallery.Menu = pspMenuCreate();
  int i;
  PspMenuItem *item;
  for (i = 0; i < 10; i++)
  {
    item = pspMenuAppendItem(SaveStateGallery.Menu, NULL, i);
    pspMenuSetHelpText(item, EmptySlotText);
  }
 
  /* Initialize options menu */
  OptionUiMenu.Menu = pspMenuCreate();
  pspMenuLoad(OptionUiMenu.Menu, OptionMenuDef);
 
  /* Initialize control menu */
  ControlUiMenu.Menu = pspMenuCreate();
  pspMenuLoad(ControlUiMenu.Menu, ControlMenuDef);
 
  /* Initialize system menu */
  SystemUiMenu.Menu = pspMenuCreate();
  pspMenuLoad(SystemUiMenu.Menu, SystemMenuDef);
 
  /* Initialize netplay menu */
  NetplayUiMenu.Menu = pspMenuCreate();
  pspMenuLoad(NetplayUiMenu.Menu, NetplayMenuDef);
 
  /* Initialize paths */
  SaveStatePath 
    = (char*)malloc(sizeof(char) * (strlen(pspGetAppDirectory()) + strlen(SaveStateDir) + 2));
  sprintf(SaveStatePath, "%s%s/", pspGetAppDirectory(), SaveStateDir);
  ScreenshotPath 
    = (char*)malloc(sizeof(char) * (strlen(pspGetAppDirectory()) + strlen(ScreenshotDir) + 2));
  sprintf(ScreenshotPath, "%s%s/", pspGetAppDirectory(), ScreenshotDir);
 
  /* Load default configuration */
  LoadButtonConfig();
 
  /* Initialize UI components */
  UiMetric.Background = Background;
  UiMetric.Font = &PspStockFont;
  UiMetric.Left = 8;
  UiMetric.Top = 24;
  UiMetric.Right = 472;
  UiMetric.Bottom = 250;
  UiMetric.OkButton = (!Options.ControlMode) ? PSP_CTRL_CROSS : PSP_CTRL_CIRCLE;
  UiMetric.CancelButton = (!Options.ControlMode) ? PSP_CTRL_CIRCLE : PSP_CTRL_CROSS;
  UiMetric.ScrollbarColor = PSP_COLOR_GRAY;
  UiMetric.ScrollbarBgColor = 0x44ffffff;
  UiMetric.ScrollbarWidth = 10;
  UiMetric.TextColor = PSP_COLOR_GRAY;
  UiMetric.SelectedColor = PSP_COLOR_YELLOW;
  UiMetric.SelectedBgColor = COLOR(0xff,0xff,0xff,0x44);
  UiMetric.StatusBarColor = PSP_COLOR_WHITE;
  UiMetric.BrowserFileColor = PSP_COLOR_GRAY;
  UiMetric.BrowserDirectoryColor = PSP_COLOR_YELLOW;
  UiMetric.GalleryIconsPerRow = 5;
  UiMetric.GalleryIconMarginWidth = 8;
  UiMetric.MenuItemMargin = 20;
  UiMetric.MenuSelOptionBg = PSP_COLOR_BLACK;
  UiMetric.MenuOptionBoxColor = PSP_COLOR_GRAY;
  UiMetric.MenuOptionBoxBg = COLOR(0, 0, 33, 0xBB);
  UiMetric.MenuDecorColor = PSP_COLOR_YELLOW;
  UiMetric.DialogFogColor = COLOR(0, 0, 0, 88);
  UiMetric.TitlePadding = 4;
  UiMetric.TitleColor = PSP_COLOR_WHITE;
  UiMetric.MenuFps = 30;
  UiMetric.TabBgColor = COLOR(0x74,0x74,0xbe,0xff);
}
 
void DisplayMenu()
{
  int i;
  PspMenuItem *item;
 
  /* Menu loop */
  do
  {
    ResumeEmulation = 0;
 
    /* Set normal clock frequency */
    pspSetClockFrequency(222);
    /* Set buttons to autorepeat */
    pspCtrlSetPollingMode(PSP_CTRL_AUTOREPEAT);
 
    /* Display appropriate tab */
    switch (TabIndex)
    {
    case TAB_STATE:
      DisplayStateTab();
      break;
    case TAB_CONTROL:
      /* Load current button mappings */
      for (item = ControlUiMenu.Menu->First, i = 0; item; item = item->Next, i++)
        pspMenuSelectOptionByValue(item, (void*)ActiveConfig.ButtonMap[i]);
      pspUiOpenMenu(&ControlUiMenu, NULL);
      break;
    case TAB_QUICKLOAD:
      pspUiOpenBrowser(&QuickloadBrowser, (GameName) ? GameName : GamePath);
      break;
    case TAB_SYSTEM:
      item = pspMenuFindItemById(SystemUiMenu.Menu, SYSTEM_VERT_STRIP);
      pspMenuSelectOptionByValue(item, (void*)Options.VertStrip);
      item = pspMenuFindItemById(SystemUiMenu.Menu, SYSTEM_SOUND_ENGINE);
      pspMenuSelectOptionByValue(item, (void*)Options.SoundEngine);
      item = pspMenuFindItemById(SystemUiMenu.Menu, SYSTEM_SOUND_BOOST);
      pspMenuSelectOptionByValue(item, (void*)Options.SoundBoost);
      pspUiOpenMenu(&SystemUiMenu, NULL);
      break;
    case TAB_OPTION:
      /* Init menu options */
      item = pspMenuFindItemById(OptionUiMenu.Menu, OPTION_DISPLAY_MODE);
      pspMenuSelectOptionByValue(item, (void*)Options.DisplayMode);
      item = pspMenuFindItemById(OptionUiMenu.Menu, OPTION_SYNC_FREQ);
      pspMenuSelectOptionByValue(item, (void*)Options.UpdateFreq);
      item = pspMenuFindItemById(OptionUiMenu.Menu, OPTION_FRAMESKIP);
      pspMenuSelectOptionByValue(item, (void*)(int)Options.Frameskip);
      item = pspMenuFindItemById(OptionUiMenu.Menu, OPTION_VSYNC);
      pspMenuSelectOptionByValue(item, (void*)Options.VSync);
      item = pspMenuFindItemById(OptionUiMenu.Menu, OPTION_CLOCK_FREQ);
      pspMenuSelectOptionByValue(item, (void*)Options.ClockFreq);
      item = pspMenuFindItemById(OptionUiMenu.Menu, OPTION_SHOW_FPS);
      pspMenuSelectOptionByValue(item, (void*)Options.ShowFps);
      item = pspMenuFindItemById(OptionUiMenu.Menu, OPTION_CONTROL_MODE);
      pspMenuSelectOptionByValue(item, (void*)Options.ControlMode);
      item = pspMenuFindItemById(OptionUiMenu.Menu, OPTION_ANIMATE);
      pspMenuSelectOptionByValue(item, (void*)UiMetric.Animate);
 
      pspUiOpenMenu(&OptionUiMenu, NULL);
      break;
    case TAB_NETPLAY:
      pspUiOpenMenu(&NetplayUiMenu, NULL);
      break;
    case TAB_ABOUT:
      pspUiSplashScreen(&SplashScreen);
      break;
    }
 
    if (!ExitPSP)
    {
      /* Set buttons to normal mode */
      pspCtrlSetPollingMode(PSP_CTRL_NORMAL);
 
      /* Resume emulation */
      if (ResumeEmulation)
      {
        if (AdhocMode)
        {
          /* TODO */
          int code = pspUiBETA(OpponentMAC, AdhocMode == ADHOC_HOST);
          if (code == PSP_UI_NO)
          {
            pspAdhocShutdown();
            AdhocMode = ADHOC_NONE;
          }
          else if (code == PSP_UI_CANCEL)
          {
            ResumeEmulation = 0;
            continue;
          }
        }
 
        if (UiMetric.Animate) pspUiFadeout();
        RunEmulator();
        if (UiMetric.Animate) pspUiFadeout();
      }
    }
  } while (!ExitPSP);
}
 
int OnGenericCancel(const void *uiobject, const void* param)
{
  if (GameName) ResumeEmulation = 1;
  return 1;
}
 
void OnSplashRender(const void *splash, const void *null)
{
  int fh, i, x, y, height;
  const char *lines[] = 
  { 
    PSP_APP_NAME" version "PSP_APP_VER" ("__DATE__")",
    "\026http://psp.akop.org/smsplus",
    " ",
    "2007 Akop Karapetyan (port)",
    "1998-2004 Charles MacDonald (emulation)",
    NULL
  };
 
  fh = pspFontGetLineHeight(UiMetric.Font);
 
  for (i = 0; lines[i]; i++);
  height = fh * (i - 1);
 
  /* Render lines */
  for (i = 0, y = SCR_HEIGHT / 2 - height / 2; lines[i]; i++, y += fh)
  {
    x = SCR_WIDTH / 2 - pspFontGetTextWidth(UiMetric.Font, lines[i]) / 2;
    pspVideoPrint(UiMetric.Font, x, y, lines[i], PSP_COLOR_GRAY);
  }
 
  /* Render PSP status */
  OnGenericRender(splash, null);
}
 
int  OnSplashButtonPress(const struct PspUiSplash *splash, 
  u32 button_mask)
{
  return OnGenericButtonPress(NULL, NULL, button_mask);
}
 
/* Handles drawing of generic items */
void OnGenericRender(const void *uiobject, const void *item_obj)
{
  /* Draw tabs */
  int height = pspFontGetLineHeight(UiMetric.Font);
  int width;
  int i, x;
 
  for (i = 0, x = 5; i <= TAB_MAX; i++, x += width + 10)
  {
    width = -10;
 
    if (!GameName && (i == TAB_STATE || i == TAB_SYSTEM))
      continue;
 
    /* Determine width of text */
    width = pspFontGetTextWidth(UiMetric.Font, TabLabel[i]);
 
    /* Draw background of active tab */
    if (i == TabIndex)
      pspVideoFillRect(x - 5, 0, x + width + 5, height + 1, UiMetric.TabBgColor);
 
    /* Draw name of tab */
    pspVideoPrint(UiMetric.Font, x, 0, TabLabel[i], PSP_COLOR_WHITE);
  }
}
 
int OnGenericButtonPress(const PspUiFileBrowser *browser, 
  const char *path, u32 button_mask)
{
  int tab_index;
 
  /* If L or R are pressed, switch tabs */
  if (button_mask & PSP_CTRL_LTRIGGER)
  {
    TabIndex--;
    do
    {
      tab_index = TabIndex;
      if (!GameName && (TabIndex == TAB_STATE || TabIndex == TAB_SYSTEM)) TabIndex--;
      if (TabIndex < 0) TabIndex = TAB_MAX;
    } while (tab_index != TabIndex);
  }
  else if (button_mask & PSP_CTRL_RTRIGGER)
  {
    TabIndex++;
    do
    {
      tab_index = TabIndex;
      if (!GameName && (TabIndex == TAB_STATE || TabIndex == TAB_SYSTEM)) TabIndex++;
      if (TabIndex > TAB_MAX) TabIndex = 0;
    } while (tab_index != TabIndex);
  }
  else if ((button_mask & (PSP_CTRL_START | PSP_CTRL_SELECT)) 
    == (PSP_CTRL_START | PSP_CTRL_SELECT))
  {
    if (pspUtilSaveVramSeq(ScreenshotPath, "ui"))
      pspUiAlert("Saved successfully");
    else
      pspUiAlert("ERROR: Not saved");
    return 0;
  }
  else return 0;
 
  return 1;
}
 
int  OnMenuItemChanged(const struct PspUiMenu *uimenu, 
  PspMenuItem* item, const PspMenuOption* option)
{
  if (uimenu == &ControlUiMenu)
  {
    ActiveConfig.ButtonMap[item->ID] = (unsigned int)option->Value;
  }
  else if (uimenu == &SystemUiMenu)
  {
    switch(item->ID)
    {
    case SYSTEM_VERT_STRIP:
      Options.VertStrip = (int)option->Value;
      break;
    case SYSTEM_SOUND_ENGINE:
      if (Options.SoundEngine != (int)option->Value)
      {
        pspUiFlashMessage("Initializing sound\nPlease wait...");
        sound_shutdown();
        snd.fm_which = (Options.SoundEngine = (int)option->Value);
        sound_init();
      }
      break;
    case SYSTEM_SOUND_BOOST:
      Options.SoundBoost = (int)option->Value;
      break;
    }
  }
  else if (uimenu == &OptionUiMenu)
  {
    switch(item->ID)
    {
    case OPTION_DISPLAY_MODE:
      Options.DisplayMode = (int)option->Value;
      break;
    case OPTION_SYNC_FREQ:
      Options.UpdateFreq = (int)option->Value;
      break;
    case OPTION_FRAMESKIP:
      Options.Frameskip = (int)option->Value;
      break;
    case OPTION_VSYNC:
      Options.VSync = (int)option->Value;
      break;
    case OPTION_CLOCK_FREQ:
      Options.ClockFreq = (int)option->Value;
      break;
    case OPTION_SHOW_FPS:
      Options.ShowFps = (int)option->Value;
      break;
    case OPTION_CONTROL_MODE:
      Options.ControlMode = (int)option->Value;
      UiMetric.OkButton = (!(int)option->Value) ? PSP_CTRL_CROSS
        : PSP_CTRL_CIRCLE;
      UiMetric.CancelButton = (!(int)option->Value) ? PSP_CTRL_CIRCLE
        : PSP_CTRL_CROSS;
      break;
    case OPTION_ANIMATE:
      UiMetric.Animate = (int)option->Value;
      break;
    }
  }
 
  return 1;
}
 
int OnMenuOk(const void *uimenu, const void* sel_item)
{
  if (uimenu == &ControlUiMenu)
  {
    /* Save to MS */
    if (SaveButtonConfig())
      pspUiAlert("Changes saved");
    else
      pspUiAlert("ERROR: Changes not saved");
  }
  else if (uimenu == &SystemUiMenu)
  {
    switch (((const PspMenuItem*)sel_item)->ID)
    {
    case SYSTEM_RESET:
      /* Reset system */
      if (pspUiConfirm("Reset the system?"))
      {
        ResumeEmulation = 1;
        system_reset();
        return 1;
      }
      break;
 
    case SYSTEM_SCRNSHOT:
      /* Save screenshot */
      if (!pspUtilSavePngSeq(ScreenshotPath, pspFileGetFilename(GameName), Screen))
        pspUiAlert("ERROR: Screenshot not saved");
      else
        pspUiAlert("Screenshot saved successfully");
      break;
    }
  }
  else if (uimenu == &NetplayUiMenu)
  {
    switch (((const PspMenuItem*)sel_item)->ID)
    {
    case NETPLAY_HOST:
      if (HostGame())
      {
        ResumeEmulation = 1;
        return 1;
      }
      break;
    case NETPLAY_JOIN:
      if (JoinGame())
      {
        ResumeEmulation = 1;
        return 1;
      }
      break;
    case NETPLAY_DISC:
      if (AdhocMode)
      {
        pspAdhocShutdown();
        AdhocMode = ADHOC_NONE;
      }
      break;
    }
  }
 
  return 0;
}
 
int OnMenuButtonPress(const struct PspUiMenu *uimenu,
                      PspMenuItem* sel_item, 
                      u32 button_mask)
{
  if (uimenu == &ControlUiMenu)
  {
    if (button_mask & PSP_CTRL_TRIANGLE)
    {
      PspMenuItem *item;
      int i;
 
      /* Load default mapping */
      InitButtonConfig();
 
      /* Modify the menu */
      for (item = ControlUiMenu.Menu->First, i = 0; item; item = item->Next, i++)
        pspMenuSelectOptionByValue(item, (void*)DefaultConfig.ButtonMap[i]);
 
      return 0;
    }
  }
 
  return OnGenericButtonPress(NULL, NULL, button_mask);
}
 
int OnQuickloadOk(const void *browser, const void *path)
{
  if (GameName)
  {
    free(GameName);
    system_poweroff();
  }
 
  if (!load_rom((void*)path))
  {
    pspUiAlert("Error loading cartridge");
    return 0;
  }
 
  GameName = strdup(path);
 
  if (GamePath) free(GamePath);
  GamePath = pspFileGetParentDirectory(GameName);
 
  system_reinit();
  system_poweron();
 
  ResumeEmulation = 1;
  return 1;
}
 
int OnSaveStateOk(const void *gallery, const void *item)
{
  if (!GameName) { TabIndex++; return 0; }
 
  char *path;
  const char *config_name = pspFileGetFilename(GameName);
 
  path = (char*)malloc(strlen(SaveStatePath) + strlen(config_name) + 8);
  sprintf(path, "%s%s.s%02i", SaveStatePath, config_name,
    ((const PspMenuItem*)item)->ID);
 
  if (pspFileCheckIfExists(path) && pspUiConfirm("Load state?"))
  {
    if (LoadState(path))
    {
      ResumeEmulation = 1;
      pspMenuFindItemById(((const PspUiGallery*)gallery)->Menu,
        ((const PspMenuItem*)item)->ID);
      free(path);
 
      return 1;
    }
    pspUiAlert("ERROR: State failed to load");
  }
 
  free(path);
  return 0;
}
 
int OnSaveStateButtonPress(const PspUiGallery *gallery, 
      PspMenuItem *sel, u32 button_mask)
{
  if (!GameName) { TabIndex++; return 0; }
 
  if (button_mask & PSP_CTRL_SQUARE 
    || button_mask & PSP_CTRL_TRIANGLE)
  {
    char *path;
    char caption[32];
    const char *config_name = pspFileGetFilename(GameName);
    PspMenuItem *item = pspMenuFindItemById(gallery->Menu, sel->ID);
 
    path = (char*)malloc(strlen(SaveStatePath) + strlen(config_name) + 8);
    sprintf(path, "%s%s.s%02i", SaveStatePath, config_name, item->ID);
 
    do /* not a real loop; flow control construct */
    {
      if (button_mask & PSP_CTRL_SQUARE)
      {
        if (pspFileCheckIfExists(path) && !pspUiConfirm("Overwrite existing state?"))
          break;
 
        pspUiFlashMessage("Saving, please wait ...");
 
        PspImage *icon;
        if (!(icon = SaveState(path, Screen)))
        {
          pspUiAlert("ERROR: State not saved");
          break;
        }
 
        SceIoStat stat;
 
        /* Trash the old icon (if any) */
        if (item->Icon && item->Icon != NoSaveIcon)
          pspImageDestroy((PspImage*)item->Icon);
 
        /* Update icon, help text */
        item->Icon = icon;
        pspMenuSetHelpText(item, PresentSlotText);
 
        /* Get file modification time/date */
        if (sceIoGetstat(path, &stat) < 0)
          sprintf(caption, "ERROR");
        else
          sprintf(caption, "%02i/%02i/%02i %02i:%02i", 
            stat.st_mtime.month,
            stat.st_mtime.day,
            stat.st_mtime.year - (stat.st_mtime.year / 100) * 100,
            stat.st_mtime.hour,
            stat.st_mtime.minute);
 
        pspMenuSetCaption(item, caption);
      }
      else if (button_mask & PSP_CTRL_TRIANGLE)
      {
        if (!pspFileCheckIfExists(path) || !pspUiConfirm("Delete state?"))
          break;
 
        if (!pspFileDelete(path))
        {
          pspUiAlert("ERROR: State not deleted");
          break;
        }
 
        /* Trash the old icon (if any) */
        if (item->Icon && item->Icon != NoSaveIcon)
          pspImageDestroy((PspImage*)item->Icon);
 
        /* Update icon, caption */
        item->Icon = NoSaveIcon;
        pspMenuSetHelpText(item, EmptySlotText);
        pspMenuSetCaption(item, "Empty");
      }
    } while (0);
 
    if (path) free(path);
    return 0;
  }
 
  return OnGenericButtonPress(NULL, NULL, button_mask);
}
 
/* Handles any special drawing for the system menu */
void OnSystemRender(const void *uiobject, const void *item_obj)
{
  int w, h, x, y;
  w = Screen->Viewport.Width >> 1;
  h = Screen->Viewport.Height >> 1;
  x = SCR_WIDTH - w - 8;
  y = SCR_HEIGHT - h - 80;
 
  /* Draw a small representation of the screen */
  pspVideoShadowRect(x, y, x + w - 1, y + h - 1, PSP_COLOR_BLACK, 3);
  pspVideoPutImage(Screen, x, y, w, h);
  pspVideoDrawRect(x, y, x + w - 1, y + h - 1, PSP_COLOR_GRAY);
 
  OnGenericRender(uiobject, item_obj);
}
 
static void DisplayStateTab()
{
  if (!GameName) { TabIndex++; return; }
 
  ScePspDateTime latest;
  PspMenuItem *item, *sel = NULL;
  SceIoStat stat;
  char caption[32];
 
  const char *config_name = pspFileGetFilename(GameName);
  char *path = (char*)malloc(strlen(SaveStatePath) + strlen(config_name) + 8);
  char *game_name = strdup(config_name);
  char *dot = strrchr(game_name, '.');
  if (dot) *dot='\0';
 
  memset(&latest,0,sizeof(latest));
 
  /* Initialize icons */
  for (item = SaveStateGallery.Menu->First; item; item = item->Next)
  {
    sprintf(path, "%s%s.s%02i", SaveStatePath, config_name, item->ID);
 
    if (pspFileCheckIfExists(path))
    {
      if (sceIoGetstat(path, &stat) < 0)
        sprintf(caption, "ERROR");
      else
      {
        /* Determine the latest save state */
        if (pspUtilCompareDates(&latest, &stat.st_mtime) < 0)
        {
          sel = item;
          latest = stat.st_mtime;
        }
 
        sprintf(caption, "%02i/%02i/%02i %02i:%02i",
          stat.st_mtime.month,
          stat.st_mtime.day,
          stat.st_mtime.year - (stat.st_mtime.year / 100) * 100,
          stat.st_mtime.hour,
          stat.st_mtime.minute);
      }
 
      pspMenuSetCaption(item, caption);
      item->Icon = LoadStateIcon(path);
      pspMenuSetHelpText(item, PresentSlotText);
    }
    else
    {
      pspMenuSetCaption(item, "Empty");
      item->Icon = NoSaveIcon;
      pspMenuSetHelpText(item, EmptySlotText);
    }
  }
 
  free(path);
 
  /* Highlight the latest save state if none are selected */
  if (SaveStateGallery.Menu->Selected == NULL)
    SaveStateGallery.Menu->Selected = sel;
 
  pspUiOpenGallery(&SaveStateGallery, game_name);
  free(game_name);
 
  /* Destroy any icons */
  for (item = SaveStateGallery.Menu->First; item; item = item->Next)
    if (item->Icon != NULL && item->Icon != NoSaveIcon)
      pspImageDestroy((PspImage*)item->Icon);
}
 
/* Initialize game configuration */
static void InitButtonConfig()
{
  memcpy(&ActiveConfig, &DefaultConfig, sizeof(struct ButtonConfig));
}
 
/* Load game configuration */
static int LoadButtonConfig()
{
  char *path;
  if (!(path = (char*)malloc(sizeof(char) * (strlen(pspGetAppDirectory()) + strlen(ButtonConfigFile) + 6))))
    return 0;
  sprintf(path, "%s%s.cnf", pspGetAppDirectory(), ButtonConfigFile);
 
  /* Open file for reading */
  FILE *file = fopen(path, "r");
  free(path);
 
  /* If no configuration, load defaults */
  if (!file)
  {
    InitButtonConfig();
    return 1;
  }
 
  /* Read contents of struct */
  int nread = fread(&ActiveConfig, sizeof(struct ButtonConfig), 1, file);
  fclose(file);
 
  if (nread != 1)
  {
    InitButtonConfig();
    return 0;
  }
 
  return 1;
}
 
/* Save game configuration */
static int SaveButtonConfig()
{
  char *path;
  if (!(path = (char*)malloc(sizeof(char) * (strlen(pspGetAppDirectory()) + strlen(ButtonConfigFile) + 6))))
    return 0;
  sprintf(path, "%s%s.cnf", pspGetAppDirectory(), ButtonConfigFile);
 
  /* Open file for writing */
  FILE *file = fopen(path, "w");
  free(path);
  if (!file) return 0;
 
  /* Write contents of struct */
  int nwritten = fwrite(&ActiveConfig, sizeof(struct ButtonConfig), 1, file);
  fclose(file);
 
  return (nwritten == 1);
}
 
/* Load options */
void LoadOptions()
{
  char *path = (char*)malloc(sizeof(char) * (strlen(pspGetAppDirectory()) + strlen(OptionsFile) + 1));
  sprintf(path, "%s%s", pspGetAppDirectory(), OptionsFile);
 
  /* Initialize INI structure */
  PspInit *init = pspInitCreate();
 
  /* Read the file */
  pspInitLoad(init, path);
 
  /* Load values */
  Options.DisplayMode = pspInitGetInt(init, "Video", "Display Mode", DISPLAY_MODE_UNSCALED);
  Options.UpdateFreq = pspInitGetInt(init, "Video", "Update Frequency", 60);
  Options.Frameskip = pspInitGetInt(init, "Video", "Frameskip", 1);
  Options.VSync = pspInitGetInt(init, "Video", "VSync", 0);
  Options.ClockFreq = pspInitGetInt(init, "Video", "PSP Clock Frequency", 222);
  Options.ShowFps = pspInitGetInt(init, "Video", "Show FPS", 0);
  Options.ControlMode = pspInitGetInt(init, "Menu", "Control Mode", 0);
  UiMetric.Animate = pspInitGetInt(init, "Menu", "Animate", 1);
  Options.VertStrip = pspInitGetInt(init, "Game", "Vertical Strip", 1);
  Options.SoundEngine = pspInitGetInt(init, "System", "FM Engine", SND_NULL);
  Options.SoundBoost = pspInitGetInt(init, "System", "Sound Boost", 0);
 
  if (GamePath) free(GamePath);
  GamePath = pspInitGetString(init, "File", "Game Path", NULL);
 
  /* Clean up */
  free(path);
  pspInitDestroy(init);
}
 
/* Save options */
static int SaveOptions()
{
  char *path = (char*)malloc(sizeof(char) * (strlen(pspGetAppDirectory()) + strlen(OptionsFile) + 1));
  sprintf(path, "%s%s", pspGetAppDirectory(), OptionsFile);
 
  /* Initialize INI structure */
  PspInit *init = pspInitCreate();
 
  /* Set values */
  pspInitSetInt(init, "Video", "Display Mode", Options.DisplayMode);
  pspInitSetInt(init, "Video", "Update Frequency", Options.UpdateFreq);
  pspInitSetInt(init, "Video", "Frameskip", Options.Frameskip);
  pspInitSetInt(init, "Video", "VSync", Options.VSync);
  pspInitSetInt(init, "Video", "PSP Clock Frequency",Options.ClockFreq);
  pspInitSetInt(init, "Video", "Show FPS", Options.ShowFps);
  pspInitSetInt(init, "Menu", "Control Mode", Options.ControlMode);
  pspInitSetInt(init, "Menu", "Animate", UiMetric.Animate);
  pspInitSetInt(init, "Game", "Vertical Strip", Options.VertStrip);
  pspInitSetInt(init, "System", "FM Engine", Options.SoundEngine);
  pspInitSetInt(init, "System", "Sound Boost", Options.SoundBoost);
 
  if (GamePath) pspInitSetString(init, "File", "Game Path", GamePath);
 
  /* Save INI file */
  int status = pspInitSave(init, path);
 
  /* Clean up */
  pspInitDestroy(init);
  free(path);
 
  return status;
}
 
/* Load state icon */
PspImage* LoadStateIcon(const char *path)
{
  /* Open file for reading */
  FILE *f = fopen(path, "r");
  if (!f) return NULL;
 
  /* Load image */
  PspImage *image = pspImageLoadPngFd(f);
  fclose(f);
 
  return image;
}
 
/* Load state */
int LoadState(const char *path)
{
  /* Open file for reading */
  FILE *f = fopen(path, "r");
  if (!f) return 0;
 
  /* Load image into temporary object */
  PspImage *image = pspImageLoadPngFd(f);
  pspImageDestroy(image);
 
  system_load_state(f);
  fclose(f);
 
  return 1;
}
 
/* Save state */
PspImage* SaveState(const char *path, PspImage *icon)
{
  /* Open file for writing */
  FILE *f;
  if (!(f = fopen(path, "w")))
    return NULL;
 
  /* Create thumbnail */
  PspImage *thumb;
  thumb = (icon->Viewport.Width < 200)
    ? pspImageCreateCopy(icon) : pspImageCreateThumbnail(icon);
  if (!thumb) { fclose(f); return NULL; }
 
  /* Write the thumbnail */
  if (!pspImageSavePngFd(f, thumb))
  {
    pspImageDestroy(thumb);
    fclose(f);
    return NULL;
  }
 
  /* Save state */
  system_save_state(f);
 
  fclose(f);
  return thumb;
}
 
/* Release menu resources */
void TrashMenu()
{
  TrashEmulator();
 
  /* Save options */
  SaveOptions();
 
  /* Trash menus */
  pspMenuDestroy(OptionUiMenu.Menu);
  pspMenuDestroy(ControlUiMenu.Menu);
  pspMenuDestroy(SaveStateGallery.Menu);
  pspMenuDestroy(SystemUiMenu.Menu);
  pspMenuDestroy(NetplayUiMenu.Menu);
 
  /* Trash images */
  if (Background) pspImageDestroy(Background);
  if (NoSaveIcon) pspImageDestroy(NoSaveIcon);
 
  if (GameName) free(GameName);
  if (GamePath) free(GamePath);
 
  free(ScreenshotPath);
  free(SaveStatePath);
}
 
/* Save or load SRAM */
void system_manage_sram(uint8 *sram, int slot, int mode)
{
  if (AdhocMode)
  {
    memset(sram, 0x00, 0x8000);
    return;
  }
 
  FILE *fd;
  const char *config_name = pspFileGetFilename(GameName);
  char *path = (char*)malloc(sizeof(char)
    * (strlen(SaveStatePath) + strlen(config_name) + 8));
  sprintf(path, "%s%s.srm", SaveStatePath, config_name);
 
  switch(mode)
  {
  case SRAM_SAVE:
    if(sms.save)
    {
      fd = fopen(path, "w");
      if(fd)
      {
        fwrite(sram, 0x8000, 1, fd);
        fclose(fd);
      }
    }
    break;
 
  case SRAM_LOAD:
    fd = fopen(path, "r");
    if(fd)
    {
      sms.save = 1;
      fread(sram, 0x8000, 1, fd);
      fclose(fd);
    }
    else
    {
      /* No SRAM file, so initialize memory */
      memset(sram, 0x00, 0x8000);
    }
    break;
  }
 
  free(path);
}
 
static int JoinGame()
{
  if (AdhocMode && !pspUiConfirm("You are currently connected. Disconnect?"))
    return 0;
 
  PspMAC mac;
  AdhocMode = ADHOC_NONE;
 
  if (!pspUiAdhocJoin(mac))
    return 0;
 
  sceKernelDelayThread(1000000);
  pspUiFlashMessage("Receiving game...");
 
  /* TODO: this needs to be done elsewhere */
  if (GameName)
  {
    free(GameName);
    system_poweroff();
  }
 
  /* Receive ROM */
  int size = 0;
  if (cart.rom)
  {
    free(cart.rom);
    cart.rom = NULL;
  }
 
  if (!pspAdhocRecvBlob((void*)&cart.rom, &size))
  {
    pspAdhocShutdown();
    pspUiAlert("An error occurred while receiving game");
    return 0;
  }
 
  /* TODO? this is from loadrom.c */
  cart.pages    = (size / 0x4000);
  cart.mapper   = MAPPER_SEGA;
  sms.display   = DISPLAY_NTSC;
  sms.territory = TERRITORY_EXPORT;
  sms.console   = CONSOLE_SMS;
  system_assign_device(PORT_A, DEVICE_PAD2B);
  system_assign_device(PORT_B, DEVICE_PAD2B);
 
  GameName = strdup((GamePath) ? GamePath : pspGetAppDirectory()); /* TODO */
 
  /* TODO: this needs to be done elsewhere */
  system_reinit();
  system_poweron();
 
  AdhocMode = ADHOC_CLIENT;
  memcpy(OpponentMAC, mac, sizeof(PspMAC));
 
  return 1;
}
 
static int HostGame()
{
  if (!GameName)
  {
    pspUiAlert("No game is currently loaded. Load a game and try again");
    return 0;
  }
 
  if (sms.console != CONSOLE_SMS)
  {
    pspUiAlert("Only Master System games are currently supported for net play");
    return 0;
  }
 
  if ((AdhocMode && !pspUiConfirm("You are currently connected. Disconnect?"))
    || (!AdhocMode && !pspUiConfirm("Any game progress will be lost. Proceed?")))
    return 0;
 
  system_poweroff();
 
  PspMAC mac;
  AdhocMode = ADHOC_NONE;
 
  if (!pspUiAdhocHost(pspFileGetFilename(GamePath), mac))
    return 0;
 
  sceKernelDelayThread(3000000);
  pspUiFlashMessage("Sending game...");
 
  /* Send ROM */
  int size = cart.pages * 0x4000;
  if (!pspAdhocSendBlob(mac, cart.rom, size))
  {
    pspAdhocShutdown();
    pspUiAlert("An error occurred while sending game");
    return 0;
  }
 
  system_reinit();
  system_poweron();
 
  AdhocMode = ADHOC_HOST;
  memcpy(OpponentMAC, mac, sizeof(PspMAC));
 
  return 1;
}
 

Compare with Previous | Blame | View Log