diff --git a/Makefile.gc b/Makefile.gc index 580f199..fb9cdeb 100644 --- a/Makefile.gc +++ b/Makefile.gc @@ -18,7 +18,7 @@ include $(DEVKITPPC)/gamecube_rules TARGET := snes9xgx-gc TARGETDIR := executables BUILD := build_gc -SOURCES := source/ngc/images source/ngc/sounds source/ngc/fonts \ +SOURCES := source/ngc/images source/ngc/sounds source/ngc/fonts source/ngc/lang \ source/ngc/gui source/ngc source/snes9x source/sz INCLUDES := source/snes9x source/ngc @@ -71,6 +71,7 @@ CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp))) sFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s))) SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.S))) TTFFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.ttf))) +LANGFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.lang))) PNGFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.png))) PCMFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.pcm))) @@ -85,7 +86,8 @@ endif export OFILES := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) \ $(sFILES:.s=.o) $(SFILES:.S=.o) \ - $(TTFFILES:.ttf=.ttf.o) $(PNGFILES:.png=.png.o) \ + $(TTFFILES:.ttf=.ttf.o) $(LANGFILES:.lang=.lang.o) \ + $(PNGFILES:.png=.png.o) \ $(PCMFILES:.pcm=.pcm.o) #--------------------------------------------------------------------------------- @@ -137,11 +139,15 @@ $(OUTPUT).dol: $(OUTPUT).elf $(OUTPUT).elf: $(OFILES) #--------------------------------------------------------------------------------- -# This rule links in binary data with .ttf, .png, and .mp3 extensions +# This rule links in binary data with these extensions: ttf lang png pcm #--------------------------------------------------------------------------------- %.ttf.o : %.ttf @echo $(notdir $<) $(bin2o) + +%.lang.o : %.lang + @echo $(notdir $<) + $(bin2o) %.png.o : %.png @echo $(notdir $<) diff --git a/Makefile.wii b/Makefile.wii index d3dc5c9..f37df85 100644 --- a/Makefile.wii +++ b/Makefile.wii @@ -18,7 +18,7 @@ include $(DEVKITPPC)/wii_rules TARGET := snes9xgx-wii TARGETDIR := executables BUILD := build_wii -SOURCES := source/ngc/images source/ngc/sounds source/ngc/fonts \ +SOURCES := source/ngc/images source/ngc/sounds source/ngc/fonts source/ngc/lang \ source/ngc/gui source/ngc source/snes9x source/sz source/unzip INCLUDES := source/snes9x source/ngc source/unzip @@ -71,6 +71,7 @@ CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp))) sFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s))) SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.S))) TTFFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.ttf))) +LANGFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.lang))) PNGFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.png))) OGGFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.ogg))) PCMFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.pcm))) @@ -86,7 +87,8 @@ endif export OFILES := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) \ $(sFILES:.s=.o) $(SFILES:.S=.o) \ - $(TTFFILES:.ttf=.ttf.o) $(PNGFILES:.png=.png.o) \ + $(TTFFILES:.ttf=.ttf.o) $(LANGFILES:.lang=.lang.o) \ + $(PNGFILES:.png=.png.o) \ $(OGGFILES:.ogg=.ogg.o) $(PCMFILES:.pcm=.pcm.o) #--------------------------------------------------------------------------------- @@ -138,11 +140,15 @@ $(OUTPUT).dol: $(OUTPUT).elf $(OUTPUT).elf: $(OFILES) #--------------------------------------------------------------------------------- -# This rule links in binary data with .ttf, .png, and .mp3 extensions +# This rule links in binary data with these extensions: ttf lang png ogg pcm #--------------------------------------------------------------------------------- %.ttf.o : %.ttf @echo $(notdir $<) $(bin2o) + +%.lang.o : %.lang + @echo $(notdir $<) + $(bin2o) %.png.o : %.png @echo $(notdir $<) diff --git a/source/ngc/filelist.h b/source/ngc/filelist.h index 5c8b36b..033c777 100644 --- a/source/ngc/filelist.h +++ b/source/ngc/filelist.h @@ -14,9 +14,32 @@ #include +// Fonts extern const u8 font_ttf[]; extern const u32 font_ttf_size; +// Languages +extern const u8 jp_lang[]; +extern const u32 jp_lang_size; +extern const u8 en_lang[]; +extern const u32 en_lang_size; +extern const u8 de_lang[]; +extern const u32 de_lang_size; +extern const u8 fr_lang[]; +extern const u32 fr_lang_size; +extern const u8 es_lang[]; +extern const u32 es_lang_size; +extern const u8 it_lang[]; +extern const u32 it_lang_size; +extern const u8 nl_lang[]; +extern const u32 nl_lang_size; +extern const u8 zh_lang[]; +extern const u32 zh_lang_size; +extern const u8 ko_lang[]; +extern const u32 ko_lang_size; + +// Sounds + extern const u8 bg_music_ogg[]; extern const u32 bg_music_ogg_size; @@ -32,6 +55,8 @@ extern const u32 button_over_pcm_size; extern const u8 button_click_pcm[]; extern const u32 button_click_pcm_size; +// Graphics + extern const u8 logo_png[]; extern const u32 logo_png_size; diff --git a/source/ngc/gettext.cpp b/source/ngc/gettext.cpp new file mode 100644 index 0000000..687c99c --- /dev/null +++ b/source/ngc/gettext.cpp @@ -0,0 +1,286 @@ +#include +#include +#include +#include +#include + +#include "gettext.h" +#include "filelist.h" +#include "snes9xGX.h" + +typedef struct _MSG +{ + u32 id; + char* msgstr; + struct _MSG *next; +} MSG; +static MSG *baseMSG = 0; + +#define HASHWORDBITS 32 + +/* Defines the so called `hashpjw' function by P.J. Weinberger + [see Aho/Sethi/Ullman, COMPILERS: Principles, Techniques and Tools, + 1986, 1987 Bell Telephone Laboratories, Inc.] */ +static inline u32 hash_string(const char *str_param) +{ + u32 hval, g; + const char *str = str_param; + + /* Compute the hash value for the given string. */ + hval = 0; + while (*str != '\0') + { + hval <<= 4; + hval += (u8) * str++; + g = hval & ((u32) 0xf << (HASHWORDBITS - 4)); + if (g != 0) + { + hval ^= g >> (HASHWORDBITS - 8); + hval ^= g; + } + } + return hval; +} + +/* Expand some escape sequences found in the argument string. */ +static char * +expand_escape(const char *str) +{ + char *retval, *rp; + const char *cp = str; + + retval = (char *) malloc(strlen(str) + 1); + if (retval == NULL) + return NULL; + rp = retval; + + while (cp[0] != '\0' && cp[0] != '\\') + *rp++ = *cp++; + if (cp[0] == '\0') + goto terminate; + do + { + + /* Here cp[0] == '\\'. */ + switch (*++cp) + { + case '\"': /* " */ + *rp++ = '\"'; + ++cp; + break; + case 'a': /* alert */ + *rp++ = '\a'; + ++cp; + break; + case 'b': /* backspace */ + *rp++ = '\b'; + ++cp; + break; + case 'f': /* form feed */ + *rp++ = '\f'; + ++cp; + break; + case 'n': /* new line */ + *rp++ = '\n'; + ++cp; + break; + case 'r': /* carriage return */ + *rp++ = '\r'; + ++cp; + break; + case 't': /* horizontal tab */ + *rp++ = '\t'; + ++cp; + break; + case 'v': /* vertical tab */ + *rp++ = '\v'; + ++cp; + break; + case '\\': + *rp = '\\'; + ++cp; + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + { + int ch = *cp++ - '0'; + + if (*cp >= '0' && *cp <= '7') + { + ch *= 8; + ch += *cp++ - '0'; + + if (*cp >= '0' && *cp <= '7') + { + ch *= 8; + ch += *cp++ - '0'; + } + } + *rp = ch; + } + break; + default: + *rp = '\\'; + break; + } + + while (cp[0] != '\0' && cp[0] != '\\') + *rp++ = *cp++; + } while (cp[0] != '\0'); + + /* Terminate string. */ + terminate: *rp = '\0'; + return retval; +} + +static MSG *findMSG(u32 id) +{ + MSG *msg; + for (msg = baseMSG; msg; msg = msg->next) + { + if (msg->id == id) + return msg; + } + return NULL; +} + +static MSG *setMSG(const char *msgid, const char *msgstr) +{ + u32 id = hash_string(msgid); + MSG *msg = findMSG(id); + if (!msg) + { + msg = (MSG *) malloc(sizeof(MSG)); + msg->id = id; + msg->msgstr = NULL; + msg->next = baseMSG; + baseMSG = msg; + } + if (msg) + { + if (msgstr) + { + if (msg->msgstr) + free(msg->msgstr); + //msg->msgstr = strdup(msgstr); + msg->msgstr = expand_escape(msgstr); + } + return msg; + } + return NULL; +} + +static void gettextCleanUp(void) +{ + while (baseMSG) + { + MSG *nextMsg = baseMSG->next; + free(baseMSG->msgstr); + free(baseMSG); + baseMSG = nextMsg; + } +} + +static char * memfgets(char * dst, int maxlen, char * src) +{ + if(!src || !dst || maxlen <= 0) + return NULL; + + char * newline = strchr(src, '\n'); + + if(newline == NULL) + return NULL; + + memcpy(dst, src, (newline-src)); + dst[(newline-src)] = 0; + return ++newline; +} + +bool LoadLanguage() +{ + char line[200]; + char *lastID = NULL; + + char *file, *eof; + + switch(GCSettings.language) + { + case LANG_JAPANESE: file = (char *)jp_lang; eof = file + jp_lang_size; break; + case LANG_ENGLISH: file = (char *)en_lang; eof = file + en_lang_size; break; + case LANG_GERMAN: file = (char *)de_lang; eof = file + de_lang_size; break; + case LANG_FRENCH: file = (char *)fr_lang; eof = file + fr_lang_size; break; + case LANG_SPANISH: file = (char *)es_lang; eof = file + es_lang_size; break; + case LANG_ITALIAN: file = (char *)it_lang; eof = file + it_lang_size; break; + case LANG_DUTCH: file = (char *)nl_lang; eof = file + nl_lang_size; break; + case LANG_SIMP_CHINESE: + case LANG_TRAD_CHINESE: file = (char *)zh_lang; eof = file + zh_lang_size; break; + case LANG_KOREAN: file = (char *)ko_lang; eof = file + ko_lang_size; break; + default: return false; + } + + gettextCleanUp(); + + while (file && file < eof) + { + file = memfgets(line, sizeof(line), file); + + if(!file) + break; + + // lines starting with # are comments + if (line[0] == '#') + continue; + + if (strncmp(line, "msgid \"", 7) == 0) + { + char *msgid, *end; + if (lastID) + { + free(lastID); + lastID = NULL; + } + msgid = &line[7]; + end = strrchr(msgid, '"'); + if (end && end - msgid > 1) + { + *end = 0; + lastID = strdup(msgid); + } + } + else if (strncmp(line, "msgstr \"", 8) == 0) + { + char *msgstr, *end; + + if (lastID == NULL) + continue; + + msgstr = &line[8]; + end = strrchr(msgstr, '"'); + if (end && end - msgstr > 1) + { + *end = 0; + setMSG(lastID, msgstr); + } + free(lastID); + lastID = NULL; + } + } + return true; +} + +const char *gettext(const char *msgid) +{ + MSG *msg = findMSG(hash_string(msgid)); + + if (msg && msg->msgstr) + { + return msg->msgstr; + } + return msgid; +} diff --git a/source/ngc/gettext.h b/source/ngc/gettext.h new file mode 100644 index 0000000..1309e93 --- /dev/null +++ b/source/ngc/gettext.h @@ -0,0 +1,12 @@ +#ifndef _GETTEXT_H_ +#define _GETTEXT_H_ + +bool LoadLanguage(); + +/* + * input msg = a text in ASCII + * output = the translated msg in utf-8 + */ +const char *gettext(const char *msg); + +#endif /* _GETTEXT_H_ */ diff --git a/source/ngc/gui/gui.h b/source/ngc/gui/gui.h index 4136954..289e8d4 100644 --- a/source/ngc/gui/gui.h +++ b/source/ngc/gui/gui.h @@ -393,11 +393,15 @@ class GuiElement //!\param hor Horizontal alignment (ALIGN_LEFT, ALIGN_RIGHT, ALIGN_CENTRE) //!\param vert Vertical alignment (ALIGN_TOP, ALIGN_BOTTOM, ALIGN_MIDDLE) virtual void SetAlignment(int hor, int vert); + //!Called when the language has changed, to obtain new text values for all text elements + virtual void ResetText(); //!Called constantly to allow the element to respond to the current input data //!\param t Pointer to a GuiTrigger, containing the current input data from PAD/WPAD virtual void Update(GuiTrigger * t); //!Called constantly to redraw the element virtual void Draw(); + //!Called constantly to redraw the element's tooltip + virtual void DrawTooltip(); protected: GuiTrigger * trigger[2]; //!< GuiTriggers (input actions) that this element responds to UpdateCallback updateCB; //!< Callback function to call when this element is updated @@ -495,8 +499,12 @@ class GuiWindow : public GuiElement //!Moves the selected element to the element above or below //!\param d Direction to move (-1 = up, 1 = down) void MoveSelectionVert(int d); + //!Resets the text for all contained elements + void ResetText(); //!Draws all the elements in this GuiWindow void Draw(); + //!Draws all of the tooltips in this GuiWindow + void DrawTooltip(); //!Updates the window and all elements contains within //!Allows the GuiWindow and all elements to respond to the input data specified //!\param t Pointer to a GuiTrigger, containing the current input data from PAD/WPAD @@ -647,6 +655,8 @@ class GuiText : public GuiElement //!\param hor Horizontal alignment (ALIGN_LEFT, ALIGN_RIGHT, ALIGN_CENTRE) //!\param vert Vertical alignment (ALIGN_TOP, ALIGN_BOTTOM, ALIGN_MIDDLE) void SetAlignment(int hor, int vert); + //!Updates the text to the selected language + void ResetText(); //!Constantly called to draw the text void Draw(); protected: @@ -664,6 +674,32 @@ class GuiText : public GuiElement bool wrap; //!< Wrapping toggle }; +//!Display, manage, and manipulate tooltips in the GUI +class GuiTooltip : public GuiElement +{ + public: + //!Constructor + //!\param t Text + GuiTooltip(const char *t); + //!Destructor + ~GuiTooltip(); + //!Gets the element's current scale + float GetScale(); + //!Sets the text of the GuiTooltip element + //!\param t Text + void SetText(const char * t); + //!Constantly called to draw the GuiTooltip + void DrawTooltip(); + + time_t time1, time2; //!< Tooltip times + + protected: + GuiImage leftImage; //!< Tooltip left image + GuiImage tileImage; //!< Tooltip tile image + GuiImage rightImage; //!< Tooltip right image + GuiText *text; //!< Tooltip text +}; + //!Display, manage, and manipulate buttons in the GUI. Buttons can have images, icons, text, and sound set (all of which are optional) class GuiButton : public GuiElement { @@ -671,7 +707,7 @@ class GuiButton : public GuiElement //!Constructor //!\param w Width //!\param h Height - GuiButton(int w, int h); + GuiButton(int w = 0, int h = 0); //!Destructor ~GuiButton(); //!Sets the button's image @@ -723,8 +759,15 @@ class GuiButton : public GuiElement //!Sets the sound to play on click //!\param s Pointer to GuiSound object void SetSoundClick(GuiSound * s); + //!Sets the tooltip for the button + //!\param t Tooltip + void SetTooltip(GuiTooltip * t); //!Constantly called to draw the GuiButton void Draw(); + //!Constantly called to draw the GuiButton's tooltip + void DrawTooltip(); + //!Resets the text for all contained elements + void ResetText(); //!Constantly called to allow the GuiButton to respond to updated input data //!\param t Pointer to a GuiTrigger, containing the current input data from PAD/WPAD void Update(GuiTrigger * t); @@ -744,6 +787,7 @@ class GuiButton : public GuiElement GuiSound * soundOver; //!< Sound to play for STATE_SELECTED GuiSound * soundHold; //!< Sound to play for STATE_HELD GuiSound * soundClick; //!< Sound to play for STATE_CLICKED + GuiTooltip * tooltip; //!< Tooltip to display on over }; typedef struct _keytype { @@ -808,6 +852,7 @@ class GuiOptionBrowser : public GuiElement public: GuiOptionBrowser(int w, int h, OptionList * l); ~GuiOptionBrowser(); + void SetCol1Position(int x); void SetCol2Position(int x); int FindMenuItem(int c, int d); int GetClickedOption(); @@ -815,6 +860,7 @@ class GuiOptionBrowser : public GuiElement void SetFocus(int f); void Draw(); void TriggerUpdate(); + void ResetText(); void Update(GuiTrigger * t); GuiText * optionVal[PAGESIZE]; protected: @@ -921,6 +967,7 @@ class GuiFileBrowser : public GuiElement void ResetState(); void SetFocus(int f); void Draw(); + void DrawTooltip(); void TriggerUpdate(); void Update(GuiTrigger * t); GuiButton * fileList[FILE_PAGESIZE]; diff --git a/source/ngc/gui/gui_button.cpp b/source/ngc/gui/gui_button.cpp index f5cddee..3b4dd5e 100644 --- a/source/ngc/gui/gui_button.cpp +++ b/source/ngc/gui/gui_button.cpp @@ -37,6 +37,7 @@ GuiButton::GuiButton(int w, int h) soundOver = NULL; soundHold = NULL; soundClick = NULL; + tooltip = NULL; selectable = true; holdable = false; clickable = true; @@ -121,6 +122,12 @@ void GuiButton::SetSoundClick(GuiSound * snd) { soundClick = snd; } +void GuiButton::SetTooltip(GuiTooltip* t) +{ + tooltip = t; + if(t) + tooltip->SetParent(this); +} /** * Draw the button on screen @@ -177,6 +184,23 @@ void GuiButton::Draw() this->UpdateEffects(); } +void GuiButton::DrawTooltip() +{ + if(tooltip) + tooltip->DrawTooltip(); +} + +void GuiButton::ResetText() +{ + for(int i=0; i<3; i++) + { + if(label[i]) + label[i]->ResetText(); + if(labelOver[i]) + labelOver[i]->ResetText(); + } +} + void GuiButton::Update(GuiTrigger * t) { if(state == STATE_CLICKED || state == STATE_DISABLED || !t) diff --git a/source/ngc/gui/gui_element.cpp b/source/ngc/gui/gui_element.cpp index c44f3bf..09f3725 100644 --- a/source/ngc/gui/gui_element.cpp +++ b/source/ngc/gui/gui_element.cpp @@ -511,13 +511,18 @@ int GuiElement::GetSelected() return -1; } -/** - * Draw an element on screen. - */ +void GuiElement::ResetText() +{ +} + void GuiElement::Draw() { } +void GuiElement::DrawTooltip() +{ +} + bool GuiElement::IsInside(int x, int y) { if(unsigned(x - this->GetLeft()) < unsigned(width) diff --git a/source/ngc/gui/gui_filebrowser.cpp b/source/ngc/gui/gui_filebrowser.cpp index ca9b70a..4caf25f 100644 --- a/source/ngc/gui/gui_filebrowser.cpp +++ b/source/ngc/gui/gui_filebrowser.cpp @@ -224,6 +224,10 @@ void GuiFileBrowser::Draw() this->UpdateEffects(); } +void GuiFileBrowser::DrawTooltip() +{ +} + void GuiFileBrowser::Update(GuiTrigger * t) { if(state == STATE_DISABLED || !t) diff --git a/source/ngc/gui/gui_optionbrowser.cpp b/source/ngc/gui/gui_optionbrowser.cpp index 2d5cd90..616a529 100644 --- a/source/ngc/gui/gui_optionbrowser.cpp +++ b/source/ngc/gui/gui_optionbrowser.cpp @@ -134,6 +134,12 @@ GuiOptionBrowser::~GuiOptionBrowser() } } +void GuiOptionBrowser::SetCol1Position(int x) +{ + for(int i=0; iSetPosition(x,0); +} + void GuiOptionBrowser::SetCol2Position(int x) { for(int i=0; i= 0) + { + optionBtn[i]->ResetText(); + next = this->FindMenuItem(next, 1); + } + else + break; + } +} + void GuiOptionBrowser::Update(GuiTrigger * t) { if(state == STATE_DISABLED || !t) diff --git a/source/ngc/gui/gui_text.cpp b/source/ngc/gui/gui_text.cpp index c42eb88..11d431b 100644 --- a/source/ngc/gui/gui_text.cpp +++ b/source/ngc/gui/gui_text.cpp @@ -9,6 +9,7 @@ ***************************************************************************/ #include "gui.h" +#include "../gettext.h" static GXColor presetColor = (GXColor){255, 255, 255, 255}; static int currentSize = 0; @@ -46,7 +47,7 @@ GuiText::GuiText(const char * t, int s, GXColor c) if(t) { origText = strdup(t); - text = charToWideChar(t); + text = charToWideChar(gettext(t)); } } @@ -75,7 +76,7 @@ GuiText::GuiText(const char * t) if(t) { origText = strdup(t); - text = charToWideChar(t); + text = charToWideChar(gettext(t)); } } @@ -110,7 +111,7 @@ void GuiText::SetText(const char * t) if(t) { origText = strdup(t); - text = charToWideChar(t); + text = charToWideChar(gettext(t)); } } @@ -200,6 +201,16 @@ void GuiText::SetAlignment(int hor, int vert) alignmentVert = vert; } +void GuiText::ResetText() +{ + if(!origText) + return; + if(text) + delete[] text; + + text = charToWideChar(gettext(origText)); +} + /** * Draw the text on screen */ diff --git a/source/ngc/gui/gui_window.cpp b/source/ngc/gui/gui_window.cpp index 5933e3a..92981c2 100644 --- a/source/ngc/gui/gui_window.cpp +++ b/source/ngc/gui/gui_window.cpp @@ -99,6 +99,18 @@ void GuiWindow::Draw() Menu_DrawRectangle(0,0,screenwidth,screenheight,(GXColor){0xbe, 0xca, 0xd5, 0x70},1); } +void GuiWindow::DrawTooltip() +{ + if(_elements.size() == 0 || !this->IsVisible()) + return; + + for (u8 i = 0; i < _elements.size(); i++) + { + try { _elements.at(i)->DrawTooltip(); } + catch (const std::exception& e) { } + } +} + void GuiWindow::ResetState() { if(state != STATE_DISABLED) @@ -384,6 +396,15 @@ void GuiWindow::MoveSelectionVert(int dir) } } +void GuiWindow::ResetText() +{ + for (u8 i = 0; i < _elements.size(); i++) + { + try { _elements.at(i)->ResetText(); } + catch (const std::exception& e) { } + } +} + void GuiWindow::Update(GuiTrigger * t) { if(_elements.size() == 0 || (state == STATE_DISABLED && parentElement)) diff --git a/source/ngc/menu.cpp b/source/ngc/menu.cpp index 96cea7f..a1a33f1 100644 --- a/source/ngc/menu.cpp +++ b/source/ngc/menu.cpp @@ -263,6 +263,9 @@ UpdateGUI (void *arg) UpdatePads(); mainWindow->Draw(); + if (mainWindow->GetState() != STATE_DISABLED) + mainWindow->DrawTooltip(); + #ifdef HW_RVL i = 3; do diff --git a/source/ngc/snes9xGX.cpp b/source/ngc/snes9xGX.cpp index c2cf715..66c1633 100644 --- a/source/ngc/snes9xGX.cpp +++ b/source/ngc/snes9xGX.cpp @@ -346,7 +346,7 @@ void USBGeckoOutput() int main(int argc, char *argv[]) { - //USBGeckoOutput(); // uncomment to enable USB gecko output + USBGeckoOutput(); // uncomment to enable USB gecko output __exception_setreload(8); #ifdef HW_DOL diff --git a/source/ngc/snes9xGX.h b/source/ngc/snes9xGX.h index b93e3e1..42999dd 100644 --- a/source/ngc/snes9xGX.h +++ b/source/ngc/snes9xGX.h @@ -61,6 +61,19 @@ enum const char ctrlName[6][24] = { "SNES Controller", "SNES Mouse", "Superscope", "Justifier", "SNES Controllers (2)", "SNES Controllers (4)" }; +enum { + LANG_JAPANESE = 0, + LANG_ENGLISH, + LANG_GERMAN, + LANG_FRENCH, + LANG_SPANISH, + LANG_ITALIAN, + LANG_DUTCH, + LANG_SIMP_CHINESE, + LANG_TRAD_CHINESE, + LANG_KOREAN +}; + struct SGCSettings{ int AutoLoad; int AutoSave; @@ -89,6 +102,7 @@ struct SGCSettings{ int MusicVolume; int SFXVolume; int Rumble; + int language; }; void ExitApp(); diff --git a/source/ngc/sram.cpp b/source/ngc/sram.cpp index a43ddc0..9f4a4e3 100644 --- a/source/ngc/sram.cpp +++ b/source/ngc/sram.cpp @@ -84,11 +84,8 @@ LoadSRAMAuto (bool silent) return false; if(LoadSRAM(filepath2, silent)) - { - // rename this file - append Auto - rename(filepath2, filepath); // rename file (to avoid duplicates) return true; - } + return false; } @@ -141,8 +138,21 @@ SaveSRAMAuto (bool silent) { char filepath[1024]; - if(!MakeFilePath(filepath, FILE_SRAM, Memory.ROMFilename, 0)) + // look for file with no number or Auto appended + if(!MakeFilePath(filepath, FILE_SRAM, Memory.ROMFilename, -1)) return false; + FILE * fp = fopen (filepath, "rb"); + + if(fp) // file found + { + fclose (fp); + } + else + { + if(!MakeFilePath(filepath, FILE_SRAM, Memory.ROMFilename, 0)) + return false; + } + return SaveSRAM(filepath, silent); }