diff --git a/.gitignore b/.gitignore index 81a3690..f44c1e3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,18 +1,13 @@ *.o *.pro.* *.bak -*.vert.xxd -*.frag.xxd -*.ttf.xxd +*.xxd -Makefile +Makefile* -mkxp -xxd+ +Game +Game.exe +qmake-win.sh /build -# Codeblocks -mkxp.layout -mkxp.cbp - diff --git a/assets/icon.ico b/assets/icon.ico new file mode 100644 index 0000000..a27a7e3 Binary files /dev/null and b/assets/icon.ico differ diff --git a/assets/icon.png b/assets/icon.png index 906f73b..6068433 100644 Binary files a/assets/icon.png and b/assets/icon.png differ diff --git a/assets/manifest.xml b/assets/manifest.xml new file mode 100644 index 0000000..9a8044c --- /dev/null +++ b/assets/manifest.xml @@ -0,0 +1,11 @@ + + + + + + + diff --git a/assets/resources.rc b/assets/resources.rc new file mode 100644 index 0000000..6415ac9 --- /dev/null +++ b/assets/resources.rc @@ -0,0 +1,3 @@ +#include +1 RT_MANIFEST "assets/manifest.xml" +MAINICON ICON "assets/icon.ico" diff --git a/binding-mri/binding-mri.cpp b/binding-mri/binding-mri.cpp index 5cb518e..d4dbcba 100644 --- a/binding-mri/binding-mri.cpp +++ b/binding-mri/binding-mri.cpp @@ -75,6 +75,8 @@ void graphicsBindingInit(); void fileIntBindingInit(); +void oneshotBindingInit(); + RB_METHOD(mriPrint); RB_METHOD(mriP); RB_METHOD(mkxpDataDirectory); @@ -111,6 +113,7 @@ static void mriBindingInit() graphicsBindingInit(); fileIntBindingInit(); + oneshotBindingInit(); if (rgssVer >= 3) { @@ -151,7 +154,11 @@ static void mriBindingInit() static void showMsg(const std::string &msg) { +#ifdef NDEBUG shState->eThread().showMessageBox(msg.c_str()); +#else + Debug() << msg.c_str(); +#endif } static void printP(int argc, VALUE *argv, @@ -193,7 +200,7 @@ RB_METHOD(mriP) RB_METHOD(mkxpDataDirectory) { RB_UNUSED_PARAM; - + const std::string &path = shState->config().customDataPath; const char *s = path.empty() ? "." : path.c_str(); @@ -473,10 +480,7 @@ static void runRMXPScripts(BacktraceData &btData) char buf[512]; int len; - if (conf.useScriptNames) - len = snprintf(buf, sizeof(buf), "%03ld:%s", i, scriptName); - else - len = snprintf(buf, sizeof(buf), SCRIPT_SECTION_FMT, i); + len = snprintf(buf, sizeof(buf), "%03ld:%s", i, scriptName); fname = newStringUTF8(buf, len); btData.scriptNames.insert(buf, scriptName); @@ -588,11 +592,7 @@ static void mriBindingExecute() mriBindingInit(); - std::string &customScript = conf.customScript; - if (!customScript.empty()) - runCustomScript(customScript); - else - runRMXPScripts(btData); + runRMXPScripts(btData); VALUE exc = rb_errinfo(); if (!NIL_P(exc) && !rb_obj_is_kind_of(exc, rb_eSystemExit)) diff --git a/binding-mri/oneshot-binding.cpp b/binding-mri/oneshot-binding.cpp new file mode 100644 index 0000000..8359405 --- /dev/null +++ b/binding-mri/oneshot-binding.cpp @@ -0,0 +1,46 @@ +#include "oneshot.h" +#include "etc.h" +#include "sharedstate.h" +#include "binding-util.h" +#include "binding-types.h" + +RB_METHOD(oneshotSetYesNo) +{ + RB_UNUSED_PARAM; + + const char *yes; + const char *no; + rb_get_args(argc, argv, "zz", &yes, &no RB_ARG_END); + shState->oneshot().setYesNo(yes, no); + return Qnil; +} + +RB_METHOD(oneshotMsgBox) +{ + RB_UNUSED_PARAM; + + int type; + const char *body; + const char *title = 0; + rb_get_args(argc, argv, "iz|z", &type, &body, &title RB_ARG_END); + return rb_bool_new(shState->oneshot().msgbox(type, body, title)); +} + +void oneshotBindingInit() +{ + VALUE module = rb_define_module("Oneshot"); + VALUE msg = rb_define_module_under(module, "Msg"); + + //Constants + rb_const_set(module, rb_intern("USER_NAME"), rb_str_new2(shState->oneshot().userName().c_str())); + rb_const_set(module, rb_intern("SAVE_PATH"), rb_str_new2(shState->oneshot().savePath().c_str())); + rb_const_set(module, rb_intern("LANG"), ID2SYM(rb_intern(shState->oneshot().lang().c_str()))); + rb_const_set(msg, rb_intern("INFO"), INT2FIX(Oneshot::MSG_INFO)); + rb_const_set(msg, rb_intern("YESNO"), INT2FIX(Oneshot::MSG_YESNO)); + rb_const_set(msg, rb_intern("WARN"), INT2FIX(Oneshot::MSG_WARN)); + rb_const_set(msg, rb_intern("ERR"), INT2FIX(Oneshot::MSG_ERR)); + + //Functions + _rb_define_module_function(module, "set_yes_no", oneshotSetYesNo); + _rb_define_module_function(module, "msgbox", oneshotMsgBox); +} diff --git a/mkxp.conf.sample b/mkxp.conf.sample index b88f216..c5aa528 100644 --- a/mkxp.conf.sample +++ b/mkxp.conf.sample @@ -2,24 +2,14 @@ # # About filesystem paths specified in this config: # The "gameFolder" path is resolved either relative -# to the directory containing the mkxp executable +# to the directory containing the Oneshot executable # (the default behavior), or relative to the current -# working directory (when compiled with +# working directory (when compiled with # -DWORKDIR_CURRENT). All other paths are resolved # relative to gameFolder and ignoring both RTPs and # encrypted archives. -# Specify the RGSS version to run under. -# Possible values are 0, 1, 2, 3. If set to 0, -# mkxp will try to guess the required version -# based on the game files found in gameFolder. -# If this fails, the version defaults to 1. -# (default: 0) -# -# rgssVersion=1 - - # Create a debug context and log # OpenGL debug information to the console # (default: disabled) @@ -36,9 +26,9 @@ # Game window is resizable -# (default: disabled) +# (default: enabled) # -# winResizable=false +# winResizable=true # Start game in fullscreen (this can @@ -57,9 +47,9 @@ # Apply linear interpolation when game screen # is upscaled -# (default: enabled) +# (default: disabled) # -# smoothScaling=true +# smoothScaling=false # Sync screen redraws to the monitor refresh rate @@ -133,14 +123,14 @@ # Use either right or left Alt + Enter to toggle # fullscreen # (default: disabled) -# +# # anyAltToggleFS=false # Enable F12 game reset -# (default: enabled) +# (default: disabled) # -# enableReset=true +# enableReset=false # Allow symlinks for game assets to be followed @@ -168,13 +158,6 @@ # iconPath=/path/to/icon.png -# Instead of playing an RPG Maker game, -# execute a single plain text script instead -# (default: none) -# -# customScript=/path/to/script.rb - - # Define raw scripts to be executed before the # actual Scripts.rxdata execution starts # (default: none) @@ -199,12 +182,6 @@ # RTP=/path/to/game.rgssad -# Use the script's name as filename in warnings and error messages -# (default: disabled) -# -# useScriptNames=false - - # Font substitutions allow drop-in replacements of fonts # to be used without changing the RGSS scripts, # eg. providing 'Open Sans' when the game thinkgs it's @@ -254,25 +231,3 @@ # this number. Maximum: 64. # # SE.sourceCount=6 - - -# The Windows game executable name minus ".exe". By default -# this is "Game", but some developers manually rename it. -# mkxp needs this name because both the .ini (game -# configuration) and .rgssad (encrypted data archive) must -# carry the same name minus their extension, and we cannot -# guess the executable's name. -# You could just as well rename them both to "Game.ini" and -# "Game.rgssad", but specifying the executable name here -# is a tiny bit less intrusive. -# -# execName=Game - - -# Give a hint on which language the game title as -# specified in the Game.ini is, useful if the encoding -# is being falsely detected. Relevant only if mkxp was -# built with automatic encoding conversion (INI_ENCODING). -# (default: none) -# -# titleLanguage=japanese diff --git a/mkxp.pro b/mkxp.pro index 558727a..b715d5f 100644 --- a/mkxp.pro +++ b/mkxp.pro @@ -2,12 +2,14 @@ TEMPLATE = app QT = -TARGET = mkxp +TARGET = Game DEPENDPATH += src shader assets INCLUDEPATH += . src CONFIG(release, debug|release): DEFINES += NDEBUG +CONFIG -= INI_ENCODING + isEmpty(BINDING) { BINDING = MRI } @@ -43,6 +45,7 @@ unix { CONFIG += link_pkgconfig PKGCONFIG += sigc++-2.0 pixman-1 zlib physfs vorbisfile \ sdl2 SDL2_image SDL2_ttf SDL_sound openal + LIBS += -ldl SHARED_FLUID { PKGCONFIG += fluidsynth @@ -76,6 +79,39 @@ unix { LIBS += -lboost_program_options$$BOOST_LIB_SUFFIX } +win32 { + CONFIG += link_pkgconfig + PKGCONFIG += sigc++-2.0 pixman-1 zlib \ + sdl2 SDL2_image SDL2_ttf openal SDL_sound vorbisfile + LIBS += -lphysfs -lboost_program_options-mt -lsecur32 + + # Deal with boost paths... + isEmpty(BOOST_I) { + BOOST_I = $$(BOOST_I) + } + isEmpty(BOOST_I) {} + else { + INCLUDEPATH += $$BOOST_I + } + + isEmpty(BOOST_L) { + BOOST_L = $$(BOOST_L) + } + isEmpty(BOOST_L) {} + else { + LIBS += -L$$BOOST_L + } + + # Ruby console bug + !console { + DEFINES += NOCONSOLE + } + + release { + RC_FILE = assets/resources.rc + } +} + # Input HEADERS += \ src/quadarray.h \ @@ -135,7 +171,8 @@ HEADERS += \ src/tileatlasvx.h \ src/sharedmidistate.h \ src/fluid-fun.h \ - src/sdl-util.h + src/sdl-util.h \ + src/oneshot.h SOURCES += \ src/main.cpp \ @@ -180,7 +217,8 @@ SOURCES += \ src/tileatlasvx.cpp \ src/autotilesvx.cpp \ src/midisource.cpp \ - src/fluid-fun.cpp + src/fluid-fun.cpp \ + src/oneshot.cpp EMBED = \ shader/common.h \ @@ -279,7 +317,8 @@ BINDING_MRUBY { BINDING_MRI { isEmpty(MRIVERSION) { - MRIVERSION = 2.1 + win32:MRIVERSION = 2.1 + unix:MRIVERSION = 2.2 } PKGCONFIG += ruby-$$MRIVERSION @@ -320,7 +359,8 @@ BINDING_MRI { binding-mri/module_rpg.cpp \ binding-mri/filesystem-binding.cpp \ binding-mri/windowvx-binding.cpp \ - binding-mri/tilemapvx-binding.cpp + binding-mri/tilemapvx-binding.cpp \ + binding-mri/oneshot-binding.cpp } OTHER_FILES += $$EMBED diff --git a/src/aldatasource.h b/src/aldatasource.h index 6db63db..4f391eb 100644 --- a/src/aldatasource.h +++ b/src/aldatasource.h @@ -24,6 +24,10 @@ #include "al-util.h" +#ifdef _WIN32 +#include +#endif + struct ALDataSource { enum Status diff --git a/src/audiostream.cpp b/src/audiostream.cpp index 1d96553..5302497 100644 --- a/src/audiostream.cpp +++ b/src/audiostream.cpp @@ -98,14 +98,15 @@ void AudioStream::play(const std::string &filename, return; } - /* If all parameters except volume match the current ones, - * we update the volume and continue streaming */ + /* If the filenames are equal, + * we update the volume and pitch and continue streaming */ if (filename == current.filename - && _pitch == current.pitch && (sState == ALStream::Playing || sState == ALStream::Paused)) { setVolume(Base, _volume); + stream.setPitch(_pitch); current.volume = _volume; + current.pitch = _pitch; unlockStream(); return; } diff --git a/src/config.cpp b/src/config.cpp index 9173acc..903d461 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -145,13 +145,12 @@ Config::Config() void Config::read(int argc, char *argv[]) { #define PO_DESC_ALL \ - PO_DESC(rgssVersion, int, 0) \ PO_DESC(debugMode, bool, false) \ PO_DESC(printFPS, bool, false) \ - PO_DESC(winResizable, bool, false) \ + PO_DESC(winResizable, bool, true) \ PO_DESC(fullscreen, bool, false) \ PO_DESC(fixedAspectRatio, bool, true) \ - PO_DESC(smoothScaling, bool, true) \ + PO_DESC(smoothScaling, bool, false) \ PO_DESC(vsync, bool, false) \ PO_DESC(defScreenW, int, 0) \ PO_DESC(defScreenH, int, 0) \ @@ -162,20 +161,17 @@ void Config::read(int argc, char *argv[]) PO_DESC(subImageFix, bool, false) \ PO_DESC(gameFolder, std::string, ".") \ PO_DESC(anyAltToggleFS, bool, false) \ - PO_DESC(enableReset, bool, true) \ + PO_DESC(enableReset, bool, false) \ PO_DESC(allowSymlinks, bool, false) \ PO_DESC(dataPathOrg, std::string, "") \ PO_DESC(dataPathApp, std::string, "") \ PO_DESC(iconPath, std::string, "") \ PO_DESC(execName, std::string, "Game") \ - PO_DESC(titleLanguage, std::string, "") \ PO_DESC(midi.soundFont, std::string, "") \ PO_DESC(midi.chorus, bool, false) \ PO_DESC(midi.reverb, bool, false) \ PO_DESC(SE.sourceCount, int, 6) \ - PO_DESC(customScript, std::string, "") \ - PO_DESC(pathCache, bool, true) \ - PO_DESC(useScriptNames, bool, false) + PO_DESC(pathCache, bool, true) // Not gonna take your shit boost #define GUARD_ALL( exp ) try { exp } catch(...) {} @@ -244,7 +240,16 @@ void Config::read(int argc, char *argv[]) if (!dataPathOrg.empty() && !dataPathApp.empty()) customDataPath = prefPath(dataPathOrg.c_str(), dataPathApp.c_str()); - commonDataPath = prefPath(".", "mkxp"); + commonDataPath = prefPath(".", "Oneshot"); + + //Hardcode some ini/version settings + rgssVersion = 1; + game.title = "Oneshot"; + game.scripts = "Data/Scripts.rxdata"; + if (defScreenW <= 0) + defScreenW = 640; + if (defScreenH <= 0) + defScreenH = 480; } static std::string baseName(const std::string &path) @@ -256,145 +261,3 @@ static std::string baseName(const std::string &path) return path.substr(pos + 1); } - -static void setupScreenSize(Config &conf) -{ - if (conf.defScreenW <= 0) - conf.defScreenW = (conf.rgssVersion == 1 ? 640 : 544); - - if (conf.defScreenH <= 0) - conf.defScreenH = (conf.rgssVersion == 1 ? 480 : 416); -} - -void Config::readGameINI() -{ - if (!customScript.empty()) - { - game.title = baseName(customScript); - - if (rgssVersion == 0) - rgssVersion = 1; - - setupScreenSize(*this); - - return; - } - - po::options_description podesc; - podesc.add_options() - ("Game.Title", po::value()) - ("Game.Scripts", po::value()) - ; - - po::variables_map vm; - std::string iniFilename = execName + ".ini"; - SDLRWStream iniFile(iniFilename.c_str(), "r"); - - if (iniFile) - { - try - { - po::store(po::parse_config_file(iniFile.stream(), podesc, true), vm); - po::notify(vm); - } - catch (po::error &error) - { - Debug() << iniFilename + ":" << error.what(); - } - } - else - { - Debug() << "FAILED to open" << iniFilename; - } - - GUARD_ALL( game.title = vm["Game.Title"].as(); ); - GUARD_ALL( game.scripts = vm["Game.Scripts"].as(); ); - - strReplace(game.scripts, '\\', '/'); - -#ifdef INI_ENCODING - /* Can add more later */ - const char *languages[] = - { - titleLanguage.c_str(), - GUESS_REGION_JP, /* Japanese */ - GUESS_REGION_KR, /* Korean */ - GUESS_REGION_CN, /* Chinese */ - 0 - }; - - bool convSuccess = true; - - /* Verify that the game title is UTF-8, and if not, - * try to determine the encoding and convert to UTF-8 */ - if (!validUtf8(game.title.c_str())) - { - const char *encoding = 0; - convSuccess = false; - - for (size_t i = 0; languages[i]; ++i) - { - encoding = libguess_determine_encoding(game.title.c_str(), - game.title.size(), - languages[i]); - if (encoding) - break; - } - - if (encoding) - { - iconv_t cd = iconv_open("UTF-8", encoding); - - size_t inLen = game.title.size(); - size_t outLen = inLen * 4; - std::string buf(outLen, '\0'); - char *inPtr = const_cast(game.title.c_str()); - char *outPtr = const_cast(buf.c_str()); - - errno = 0; - size_t result = iconv(cd, &inPtr, &inLen, &outPtr, &outLen); - - iconv_close(cd); - - if (result != (size_t) -1 && errno == 0) - { - buf.resize(buf.size()-outLen); - game.title = buf; - convSuccess = true; - } - } - } - - if (!convSuccess) - game.title.clear(); -#else - if (!validUtf8(game.title.c_str())) - game.title.clear(); -#endif - - if (game.title.empty()) - game.title = baseName(gameFolder); - - if (rgssVersion == 0) - { - /* Try to guess RGSS version based on Data/Scripts extension */ - rgssVersion = 1; - - if (!game.scripts.empty()) - { - const char *p = &game.scripts[game.scripts.size()]; - const char *head = &game.scripts[0]; - - while (--p != head) - if (*p == '.') - break; - - if (!strcmp(p, ".rvdata")) - rgssVersion = 2; - else if (!strcmp(p, ".rvdata2")) - rgssVersion = 3; - } - } - - setupScreenSize(*this); -} diff --git a/src/config.h b/src/config.h index fc9bbda..60a95e3 100644 --- a/src/config.h +++ b/src/config.h @@ -60,7 +60,6 @@ struct Config std::string iconPath; std::string execName; - std::string titleLanguage; struct { @@ -74,9 +73,6 @@ struct Config int sourceCount; } SE; - bool useScriptNames; - - std::string customScript; std::vector preloadScripts; std::vector rtps; @@ -97,7 +93,6 @@ struct Config Config(); void read(int argc, char *argv[]); - void readGameINI(); }; #endif // CONFIG_H diff --git a/src/font.cpp b/src/font.cpp index 4ac3346..dd11000 100644 --- a/src/font.cpp +++ b/src/font.cpp @@ -171,10 +171,7 @@ _TTF_Font *SharedFontState::getFont(std::string family, shState->fileSystem().openReadRaw(*ops, path, true); } - // FIXME 0.9 is guesswork at this point -// float gamma = (96.0/45.0)*(5.0/14.0)*(size-5); -// font = TTF_OpenFontRW(ops, 1, gamma /** .90*/); - font = TTF_OpenFontRW(ops, 1, size* 0.90f); + font = TTF_OpenFontRW(ops, 1, size); if (!font) throw Exception(Exception::SDLError, "%s", SDL_GetError()); diff --git a/src/graphics.cpp b/src/graphics.cpp index fe51f74..e8ef55e 100644 --- a/src/graphics.cpp +++ b/src/graphics.cpp @@ -753,6 +753,8 @@ void Graphics::transition(int duration, for (int i = 0; i < duration; ++i) { + shState->input().update(); + /* We need to clean up transMap properly before * a possible longjmp, so we manually test for * shutdown/reset here */ diff --git a/src/keybindings.cpp b/src/keybindings.cpp index 49d2a71..6d9307c 100644 --- a/src/keybindings.cpp +++ b/src/keybindings.cpp @@ -71,46 +71,28 @@ static const KbBindingData defaultKbBindings[] = { SDL_SCANCODE_RIGHT, Input::Right }, { SDL_SCANCODE_UP, Input::Up }, { SDL_SCANCODE_DOWN, Input::Down }, + { SDL_SCANCODE_H, Input::Left }, + { SDL_SCANCODE_L, Input::Right }, + { SDL_SCANCODE_K, Input::Up }, + { SDL_SCANCODE_J, Input::Down }, + { SDL_SCANCODE_Z, Input::C }, { SDL_SCANCODE_SPACE, Input::C }, { SDL_SCANCODE_RETURN, Input::C }, + { SDL_SCANCODE_X, Input::B }, { SDL_SCANCODE_ESCAPE, Input::B }, { SDL_SCANCODE_KP_0, Input::B }, { SDL_SCANCODE_LSHIFT, Input::A }, - { SDL_SCANCODE_X, Input::B }, - { SDL_SCANCODE_D, Input::Z }, - { SDL_SCANCODE_Q, Input::L }, - { SDL_SCANCODE_W, Input::R }, - { SDL_SCANCODE_A, Input::X }, - { SDL_SCANCODE_S, Input::Y } -}; - -/* RGSS1 */ -static const KbBindingData defaultKbBindings1[] = -{ - { SDL_SCANCODE_Z, Input::A }, - { SDL_SCANCODE_C, Input::C }, -}; - -/* RGSS2 and higher */ -static const KbBindingData defaultKbBindings2[] = -{ - { SDL_SCANCODE_Z, Input::C } + { SDL_SCANCODE_LCTRL, Input::X }, }; static elementsN(defaultKbBindings); -static elementsN(defaultKbBindings1); -static elementsN(defaultKbBindings2); static const JsBindingData defaultJsBindings[] = { - { 0, Input::A }, + { 0, Input::C }, { 1, Input::B }, - { 2, Input::C }, + { 2, Input::A }, { 3, Input::X }, - { 4, Input::Y }, - { 5, Input::Z }, - { 6, Input::L }, - { 7, Input::R } }; static elementsN(defaultJsBindings); @@ -143,20 +125,13 @@ static void addHatBinding(BDescVec &d, uint8_t hat, uint8_t pos, Input::ButtonCo d.push_back(desc); } -BDescVec genDefaultBindings(const Config &conf) +BDescVec genDefaultBindings() { BDescVec d; for (size_t i = 0; i < defaultKbBindingsN; ++i) defaultKbBindings[i].add(d); - if (conf.rgssVersion == 1) - for (size_t i = 0; i < defaultKbBindings1N; ++i) - defaultKbBindings1[i].add(d); - else - for (size_t i = 0; i < defaultKbBindings2N; ++i) - defaultKbBindings2[i].add(d); - for (size_t i = 0; i < defaultJsBindingsN; ++i) defaultJsBindings[i].add(d); @@ -164,7 +139,7 @@ BDescVec genDefaultBindings(const Config &conf) addAxisBinding(d, 0, Positive, Input::Right); addAxisBinding(d, 1, Negative, Input::Up ); addAxisBinding(d, 1, Positive, Input::Down ); - + addHatBinding(d, 0, SDL_HAT_LEFT, Input::Left ); addHatBinding(d, 0, SDL_HAT_RIGHT, Input::Right); addHatBinding(d, 0, SDL_HAT_UP, Input::Up ); @@ -178,24 +153,21 @@ BDescVec genDefaultBindings(const Config &conf) struct Header { uint32_t formVer; - uint32_t rgssVer; uint32_t count; }; -static void buildPath(const std::string &dir, uint32_t rgssVersion, - char *out, size_t outSize) +static void buildPath(const std::string &dir, char *out, size_t outSize) { - snprintf(out, outSize, "%skeybindings.mkxp%u", dir.c_str(), rgssVersion); + snprintf(out, outSize, "%skeybindings", dir.c_str()); } -static bool writeBindings(const BDescVec &d, const std::string &dir, - uint32_t rgssVersion) +static bool writeBindings(const BDescVec &d, const std::string &dir) { if (dir.empty()) return false; char path[1024]; - buildPath(dir, rgssVersion, path, sizeof(path)); + buildPath(dir, path, sizeof(path)); FILE *f = fopen(path, "wb"); @@ -204,7 +176,6 @@ static bool writeBindings(const BDescVec &d, const std::string &dir, Header hd; hd.formVer = FORMAT_VER; - hd.rgssVer = rgssVersion; hd.count = d.size(); if (fwrite(&hd, sizeof(hd), 1, f) < 1) @@ -225,10 +196,10 @@ static bool writeBindings(const BDescVec &d, const std::string &dir, void storeBindings(const BDescVec &d, const Config &conf) { - if (writeBindings(d, conf.customDataPath, conf.rgssVersion)) + if (writeBindings(d, conf.customDataPath)) return; - writeBindings(d, conf.commonDataPath, conf.rgssVersion); + writeBindings(d, conf.commonDataPath); } #define READ(ptr, size, n, f) if (fread(ptr, size, n, f) < n) return false @@ -277,14 +248,13 @@ static bool verifyDesc(const BindingDesc &desc) } } -static bool readBindings(BDescVec &out, const std::string &dir, - uint32_t rgssVersion) +static bool readBindings(BDescVec &out, const std::string &dir) { if (dir.empty()) return false; char path[1024]; - buildPath(dir, rgssVersion, path, sizeof(path)); + buildPath(dir, path, sizeof(path)); FILE *f = fopen(path, "rb"); @@ -300,8 +270,6 @@ static bool readBindings(BDescVec &out, const std::string &dir, if (hd.formVer != FORMAT_VER) return false; - if (hd.rgssVer != rgssVersion) - return false; /* Arbitrary max value */ if (hd.count > 1024) return false; @@ -324,11 +292,11 @@ BDescVec loadBindings(const Config &conf) { BDescVec d; - if (readBindings(d, conf.customDataPath, conf.rgssVersion)) + if (readBindings(d, conf.customDataPath)) return d; - if (readBindings(d, conf.commonDataPath, conf.rgssVersion)) + if (readBindings(d, conf.commonDataPath)) return d; - return genDefaultBindings(conf); + return genDefaultBindings(); } diff --git a/src/keybindings.h b/src/keybindings.h index 3d437c9..d0c2754 100644 --- a/src/keybindings.h +++ b/src/keybindings.h @@ -111,7 +111,7 @@ struct BindingDesc typedef std::vector BDescVec; struct Config; -BDescVec genDefaultBindings(const Config &conf); +BDescVec genDefaultBindings(); void storeBindings(const BDescVec &d, const Config &conf); BDescVec loadBindings(const Config &conf); diff --git a/src/main.cpp b/src/main.cpp index eb07970..92fe615 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -206,8 +206,6 @@ int main(int argc, char *argv[]) return 0; } - conf.readGameINI(); - assert(conf.rgssVersion >= 1 && conf.rgssVersion <= 3); printRgssVersion(conf.rgssVersion); diff --git a/src/oneshot.cpp b/src/oneshot.cpp new file mode 100644 index 0000000..ca8b116 --- /dev/null +++ b/src/oneshot.cpp @@ -0,0 +1,459 @@ +#include "oneshot.h" + +/****************** + * HERE BE DRAGONS + ******************/ + +#include "eventthread.h" +#include "debugwriter.h" + +#include + +//OS-Specific code +#if defined _WIN32 + #define OS_W32 + #define WIN32_LEAN_AND_MEAN + #define SECURITY_WIN32 + #include + #include + #include + #include +#elif defined __APPLE__ + #define OS_OSX +#elif defined __linux__ + #define OS_LINUX + #include + #include + #include + #include + + class GtkWidget; + + typedef enum + { + GTK_MESSAGE_INFO, + GTK_MESSAGE_WARNING, + GTK_MESSAGE_QUESTION, + GTK_MESSAGE_ERROR + } GtkMessageType; + + typedef enum + { + GTK_BUTTONS_NONE, + GTK_BUTTONS_OK, + GTK_BUTTONS_CLOSE, + GTK_BUTTONS_CANCEL, + GTK_BUTTONS_YES_NO, + GTK_BUTTONS_OK_CANCEL + } GtkButtonsType; + + typedef enum + { + GTK_RESPONSE_NONE = -1, + GTK_RESPONSE_REJECT = -2, + GTK_RESPONSE_ACCEPT = -3, + GTK_RESPONSE_DELETE_EVENT = -4, + GTK_RESPONSE_OK = -5, + GTK_RESPONSE_CANCEL = -6, + GTK_RESPONSE_CLOSE = -7, + GTK_RESPONSE_YES = -8, + GTK_RESPONSE_NO = -9, + GTK_RESPONSE_APPLY = -10, + GTK_RESPONSE_HELP = -11 + } GtkResponseType; +#else + #error "Operating system not detected." +#endif + +struct OneshotPrivate +{ + //Main SDL window + SDL_Window *window; + + //String data + std::string lang; + std::string userName; + std::string savePath; + + //Dialog text + std::string txtYes; + std::string txtNo; + +#if defined OS_LINUX + //GTK+ + void *libgtk; + void (*gtk_init)(int *argc, char ***argv); + GtkWidget *(*gtk_message_dialog_new)(void *parent, int flags, GtkMessageType type, GtkButtonsType buttons, const char *message_format, ...); + void (*gtk_window_set_title)(GtkWidget *window, const char *title); + GtkResponseType (*gtk_dialog_run)(GtkWidget *dialog); + void (*gtk_widget_destroy)(GtkWidget *widget); + void (*gtk_main_quit)(); + void (*gtk_main)(); + unsigned int (*gdk_threads_add_idle)(int (*function)(void *data), void *data); +#endif + + OneshotPrivate() + : window(0) +#if defined OS_LINUX + ,libgtk(0) +#endif + { + } + + ~OneshotPrivate() + { +#ifdef OS_LINUX + if (libgtk) + dlclose(libgtk); +#endif + } +}; + +//OS-SPECIFIC FUNCTIONS +#if defined OS_LINUX +struct linux_DialogData +{ + //Input + OneshotPrivate *p; + int type; + const char *body; + const char *title; + + //Output + bool result; +}; + +static int linux_dialog(void *rawData) +{ + linux_DialogData *data = reinterpret_cast(rawData); + OneshotPrivate *p = data->p; + + //Determine correct flags + GtkMessageType gtktype; + GtkButtonsType gtkbuttons = GTK_BUTTONS_OK; + switch (data->type) + { + case Oneshot::MSG_INFO: + gtktype = GTK_MESSAGE_INFO; + break; + case Oneshot::MSG_YESNO: + gtktype = GTK_MESSAGE_QUESTION; + gtkbuttons = GTK_BUTTONS_YES_NO; + break; + case Oneshot::MSG_WARN: + gtktype = GTK_MESSAGE_WARNING; + break; + case Oneshot::MSG_ERR: + gtktype = GTK_MESSAGE_ERROR; + break; + default: + p->gtk_main_quit(); + return 0; + } + + //Display dialog and get result + GtkWidget *dialog = p->gtk_message_dialog_new(0, 0, gtktype, gtkbuttons, data->body); + p->gtk_window_set_title(dialog, data->title); + int result = p->gtk_dialog_run(dialog); + p->gtk_widget_destroy(dialog); + + //Interpret result and return + data->result = (result == GTK_RESPONSE_OK || result == GTK_RESPONSE_YES); + p->gtk_main_quit(); + return 0; +} +#elif defined OS_W32 +/* Convert WCHAR pointer to std::string */ +static std::string w32_fromWide(const WCHAR *ustr) +{ + std::string result; + int size = WideCharToMultiByte(CP_UTF8, 0, ustr, -1, 0, 0, 0, 0); + if (size > 0) + { + CHAR *str = new CHAR[size]; + if (WideCharToMultiByte(CP_UTF8, 0, ustr, -1, str, size, 0, 0) == size) + result = str; + delete [] str; + } + return result; +} +/* Convert WCHAR pointer from const char* */ +static WCHAR *w32_toWide(const char *str) +{ + if (str) + { + int size = MultiByteToWideChar(CP_UTF8, 0, str, -1, 0, 0); + if (size > 0) + { + WCHAR *ustr = new WCHAR[size]; + if (MultiByteToWideChar(CP_UTF8, 0, str, -1, ustr, size) == size) + return ustr; + delete [] ustr; + } + } + + //Return empty string + WCHAR *ustr = new WCHAR[1]; + *ustr = 0; + return ustr; +} +#endif + +Oneshot::Oneshot(const RGSSThreadData &threadData) +{ + p = new OneshotPrivate(); + p->window = threadData.window; + p->savePath = threadData.config.commonDataPath.substr(0, threadData.config.commonDataPath.size() - 1); + + /******************** + * USERNAME/SAVE PATH + ********************/ +#if defined OS_W32 + //Get language code + WCHAR wlang[9]; + GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SISO639LANGNAME, wlang, sizeof(wlang) / sizeof(WCHAR)); + p->lang = w32_fromWide(wlang); + + //Get user's name + ULONG size = 0; + GetUserNameEx(NameDisplay, 0, &size); + if (GetLastError() == ERROR_MORE_DATA) + { + //Get their full (display) name + WCHAR *name = new WCHAR[size]; + GetUserNameEx(NameDisplay, name, &size); + p->userName = w32_fromWide(name); + delete [] name; + } + else + { + //Get their login name + DWORD size2 = 0; + GetUserName(0, &size2); + if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) + { + WCHAR *name = new WCHAR[size2]; + GetUserName(name, &size2); + p->userName = w32_fromWide(name); + delete [] name; + } + } +#else + //Get language code + const char *lc_all = getenv("LC_ALL"); + const char *lang = getenv("LANG"); + const char *code = (lc_all ? lc_all : lang); + if (code) + { + //find first non alphanumeric character, copy language code + int end = 0; + for (; code[end] && (code[end] >= 'a' && code[end] <= 'z'); ++end) {} + p->lang = std::string(code, end); + } + else + p->lang = "en"; + + //Get user's name + struct passwd *pwd = getpwuid(getuid()); + if (pwd) + { + if (pwd->pw_gecos && pwd->pw_gecos[0] != ',') + { + //Get the user's full name + int comma = 0; + for (; pwd->pw_gecos[comma] && pwd->pw_gecos[comma] != ','; ++comma) {} + p->userName = std::string(pwd->pw_gecos, comma); + } + else + p->userName = pwd->pw_name; + } +#endif + + /********** + * MSGBOX + **********/ +#ifdef OS_LINUX +#define LOAD_FUNC(name) *reinterpret_cast(&p->name) = dlsym(p->libgtk, #name) + //Attempt to link to gtk (prefer gtk2 over gtk3 until I can figure that message box icon out) + static const char *gtklibs[] = + { + "libgtk-x11-2.0.so", + "libgtk-3.0.so", + }; + + for (size_t i = 0; i < ARRAY_SIZE(gtklibs); ++i) + { + if (!(p->libgtk = dlopen("libgtk-x11-2.0.so", RTLD_NOW))) + p->libgtk = dlopen("libgtk-3.0.so", RTLD_NOW); + if (p->libgtk) + { + //Load functions + LOAD_FUNC(gtk_init); + LOAD_FUNC(gtk_message_dialog_new); + LOAD_FUNC(gtk_window_set_title); + LOAD_FUNC(gtk_dialog_run); + LOAD_FUNC(gtk_widget_destroy); + LOAD_FUNC(gtk_main_quit); + LOAD_FUNC(gtk_main); + LOAD_FUNC(gdk_threads_add_idle); + + if (p->gtk_init + && p->gtk_message_dialog_new + && p->gtk_window_set_title + && p->gtk_dialog_run + && p->gtk_widget_destroy + && p->gtk_main_quit + && p->gtk_main + && p->gdk_threads_add_idle) + { + p->gtk_init(0, 0); + } + else + { + dlclose(p->libgtk); + p->libgtk = 0; + } + } + if (p->libgtk) + break; + } +#undef LOAD_FUNC +#endif + /******** + * MISC + ********/ +#if defined OS_W32 + //Get windows version + OSVERSIONINFOW version; + ZeroMemory(&version, sizeof(version)); + version.dwOSVersionInfoSize = sizeof(version); + GetVersionEx(&version); +#endif +} + +Oneshot::~Oneshot() +{ + delete p; +} + +const std::string &Oneshot::lang() const +{ + return p->lang; +} + +const std::string &Oneshot::userName() const +{ + return p->userName; +} + +const std::string &Oneshot::savePath() const +{ + return p->savePath; +} + +void Oneshot::setYesNo(const char *yes, const char *no) +{ + p->txtYes = yes; + p->txtNo = no; +} + +bool Oneshot::msgbox(int type, const char *body, const char *title) +{ +#if defined OS_W32 + //Get native window handle + SDL_SysWMinfo wminfo; + SDL_version version; + SDL_VERSION(&version); + wminfo.version = version; + SDL_GetWindowWMInfo(p->window, &wminfo); + HWND hwnd = wminfo.info.win.window; + + //Construct flags + UINT flags = 0; + switch (type) + { + case MSG_INFO: + flags = MB_ICONINFORMATION; + break; + case MSG_YESNO: + flags = MB_ICONQUESTION | MB_YESNO; + break; + case MSG_WARN: + flags = MB_ICONWARNING; + break; + case MSG_ERR: + flags = MB_ICONERROR; + break; + } + + //Create message box + WCHAR *wbody = w32_toWide(body); + WCHAR *wtitle = w32_toWide(title); + int result = MessageBoxW(hwnd, wbody, wtitle, flags); + delete [] title; + delete [] body; + + //Interpret result + return (result == IDOK || result == IDYES); +#else +#if defined OS_LINUX + if (p->libgtk) + { + linux_DialogData data = {p, type, body, title, 0}; + p->gdk_threads_add_idle(linux_dialog, &data); + p->gtk_main(); + return data.result; + } +#endif + //SDL message box + + //Button data + static const SDL_MessageBoxButtonData buttonOk = {SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT, 1, "OK"}; + static const SDL_MessageBoxButtonData buttonsOk[] = {buttonOk}; + SDL_MessageBoxButtonData buttonYes = {SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT, 1, p->txtYes.c_str()}; + SDL_MessageBoxButtonData buttonNo = {SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT, 0, p->txtNo.c_str()}; + SDL_MessageBoxButtonData buttonsYesNo[] = {buttonNo, buttonYes}; + + //Messagebox data + SDL_MessageBoxData data; + data.window = p->window; + data.colorScheme = 0; + data.title = title; + data.message = body; + + //Set type + switch (type) + { + case MSG_INFO: + case MSG_YESNO: + data.flags = SDL_MESSAGEBOX_INFORMATION; + break; + case MSG_WARN: + data.flags = SDL_MESSAGEBOX_WARNING; + break; + case MSG_ERR: + data.flags = SDL_MESSAGEBOX_WARNING; + break; + } + + //Set buttons + switch (type) + { + case MSG_INFO: + case MSG_WARN: + case MSG_ERR: + data.numbuttons = 1; + data.buttons = buttonsOk; + break; + case MSG_YESNO: + data.numbuttons = 2; + data.buttons = buttonsYesNo; + break; + } + + //Show messagebox + int button; + SDL_ShowMessageBox(&data, &button); + return button ? true : false; +#endif +} diff --git a/src/oneshot.h b/src/oneshot.h new file mode 100644 index 0000000..8c10cbb --- /dev/null +++ b/src/oneshot.h @@ -0,0 +1,60 @@ +#ifndef ONESHOT_H +#define ONESHOT_H + +#include "etc-internal.h" +#include + +struct OneshotPrivate; +struct RGSSThreadData; + +class Oneshot +{ +public: + Oneshot(const RGSSThreadData &threadData); + ~Oneshot(); + + //msgbox type codes + enum + { + MSG_INFO, + MSG_YESNO, + MSG_WARN, + MSG_ERR, + }; + + //Wallpaper style + enum + { + STYLE_NONE, + STYLE_TILE, + STYLE_CENTER, + STYLE_STRETCH, + STYLE_FIT, + STYLE_FILL, + STYLE_SPAN, + }; + + //Wallpaper gradient + enum + { + GRADIENT_NONE, + GRADIENT_HORIZONTAL, + GRADIENT_VERTICAL, + }; + + //Accessors + const std::string &lang() const; + const std::string &userName() const; + const std::string &savePath() const; + + //Mutators + void setYesNo(const char *yes, const char *no); + + //Functions + bool msgbox(int type, const char *body, const char *title); + +private: + OneshotPrivate *p; +}; + +#endif // ONESHOT_H diff --git a/src/settingsmenu.cpp b/src/settingsmenu.cpp index 6518d7f..95cfe58 100644 --- a/src/settingsmenu.cpp +++ b/src/settingsmenu.cpp @@ -37,7 +37,7 @@ #include #include -const Vec2i winSize(540, 356); +const Vec2i winSize(700, 316); const uint8_t cBgNorm = 50; const uint8_t cBgDark = 20; @@ -63,16 +63,12 @@ struct VButton { BTN_STRING(Up), BTN_STRING(Down), - BTN_STRING(L), BTN_STRING(Left), BTN_STRING(Right), - BTN_STRING(R), - BTN_STRING(A), - BTN_STRING(B), - BTN_STRING(C), - BTN_STRING(X), - BTN_STRING(Y), - BTN_STRING(Z) + { Input::C, "Action" }, + { Input::B, "Menu" }, + { Input::A, "Run/Misc" }, + { Input::X, "Deactivate" }, }; static elementsN(vButtons); @@ -432,7 +428,7 @@ struct SettingsMenuPrivate else { dstRect.w = alignW; - dstRect.x = x; + dstRect.x = drawOff.x + x; SDL_BlitScaled(txtSurf, 0, surf, &dstRect); } } @@ -520,6 +516,7 @@ struct SettingsMenuPrivate } dupWarnLabel.setVisible(haveDup); + infoLabel.setVisible(!haveDup); } void redraw() @@ -705,7 +702,7 @@ struct SettingsMenuPrivate void onResetToDefault() { - setupBindingData(genDefaultBindings(rtData.config)); + setupBindingData(genDefaultBindings()); updateDuplicateStatus(); redraw(); } @@ -964,18 +961,18 @@ SettingsMenu::SettingsMenu(RGSSThreadData &rtData) p->rgb = p->winSurf->format; - const size_t layoutW = 4; - const size_t layoutH = 3; + const size_t layoutW = 2; + const size_t layoutH = 4; assert(layoutW*layoutH == vButtonsN); - const int bWidgetW = winSize.x / layoutH; + const int bWidgetW = winSize.x / layoutW; const int bWidgetH = 64; - const int bWidgetY = winSize.y - layoutW*bWidgetH - 48; + const int bWidgetY = winSize.y - layoutH*bWidgetH - 48; - for (int y = 0; y < 4; ++y) - for (int x = 0; x < 3; ++x) + for (int y = 0; y < layoutH; ++y) + for (int x = 0; x < layoutW; ++x) { - int i = y*3+x; + int i = x*layoutH+y; BindingWidget w(i, p, IntRect(x*bWidgetW, bWidgetY+y*bWidgetH, bWidgetW, bWidgetH)); p->bWidgets.push_back(w); @@ -1008,10 +1005,10 @@ SettingsMenu::SettingsMenu(RGSSThreadData &rtData) /* Labels */ const char *info = "Use left click to bind a slot, right click to clear its binding"; - p->infoLabel = Label(p, IntRect(16, 6, winSize.x, 16), info, cText, cText, cText); + p->infoLabel = Label(p, IntRect(112 + 32, buttonY + 8, winSize.x, 16), info, cText, cText, cText); const char *warn = "Warning: Same physical key bound to multiple slots"; - p->dupWarnLabel = Label(p, IntRect(16, 26, winSize.x, 16), warn, 255, 0, 0); + p->dupWarnLabel = Label(p, IntRect(112 + 32, buttonY + 8, winSize.x, 16), warn, 255, 0, 0); p->widgets.push_back(&p->infoLabel); p->widgets.push_back(&p->dupWarnLabel); diff --git a/src/sharedstate.cpp b/src/sharedstate.cpp index 023ff6b..1142598 100644 --- a/src/sharedstate.cpp +++ b/src/sharedstate.cpp @@ -26,6 +26,7 @@ #include "graphics.h" #include "input.h" #include "audio.h" +#include "oneshot.h" #include "glstate.h" #include "shader.h" #include "texpool.h" @@ -77,6 +78,8 @@ struct SharedStatePrivate Input input; Audio audio; + Oneshot oneshot; + GLState _glState; ShaderSet shaders; @@ -109,6 +112,7 @@ struct SharedStatePrivate graphics(threadData), input(*threadData), audio(*threadData), + oneshot(*threadData), fontState(threadData->config), stampCounter(0) { @@ -227,6 +231,7 @@ GSATT(Config&, config) GSATT(Graphics&, graphics) GSATT(Input&, input) GSATT(Audio&, audio) +GSATT(Oneshot&, oneshot) GSATT(GLState&, _glState) GSATT(ShaderSet&, shaders) GSATT(TexPool&, texPool) diff --git a/src/sharedstate.h b/src/sharedstate.h index d2d6f29..3aca9cc 100644 --- a/src/sharedstate.h +++ b/src/sharedstate.h @@ -42,6 +42,7 @@ class EventThread; class Graphics; class Input; class Audio; +class Oneshot; class GLState; class TexPool; class Font; @@ -71,6 +72,8 @@ struct SharedState Input &input() const; Audio &audio() const; + Oneshot &oneshot() const; + GLState &_glState() const; ShaderSet &shaders() const; diff --git a/src/tilemap.cpp b/src/tilemap.cpp index 8b61ea7..1964de5 100644 --- a/src/tilemap.cpp +++ b/src/tilemap.cpp @@ -158,7 +158,7 @@ static const size_t zlayersMax = viewpH + 5; static const uint8_t atAnimation[16*4] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 };