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
};