Manually rebased over latest mkxp commit. Some features, such as lighting, are not reimplemented yet.

This commit is contained in:
Mathew Velasquez 2015-09-02 22:41:25 -04:00
parent 5a7480a406
commit 3b64e7871b
24 changed files with 722 additions and 320 deletions

15
.gitignore vendored
View File

@ -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

BIN
assets/icon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 616 B

11
assets/manifest.xml Normal file
View File

@ -0,0 +1,11 @@
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<dependency>
<dependentAssembly>
<assemblyIdentity type="win32"
name="System"
version="1.0.0.0"
language="*"
processorArchitecture="x86" />
</dependentAssembly>
</dependency>
</assembly>

3
assets/resources.rc Normal file
View File

@ -0,0 +1,3 @@
#include <winuser.h>
1 RT_MANIFEST "assets/manifest.xml"
MAINICON ICON "assets/icon.ico"

View File

@ -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))

View File

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

View File

@ -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

View File

@ -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

View File

@ -24,6 +24,10 @@
#include "al-util.h"
#ifdef _WIN32
#include <cstring>
#endif
struct ALDataSource
{
enum Status

View File

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

View File

@ -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<std::string>())
("Game.Scripts", po::value<std::string>())
;
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<std::string>(); );
GUARD_ALL( game.scripts = vm["Game.Scripts"].as<std::string>(); );
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<char*>(game.title.c_str());
char *outPtr = const_cast<char*>(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);
}

View File

@ -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<std::string> preloadScripts;
std::vector<std::string> rtps;
@ -97,7 +93,6 @@ struct Config
Config();
void read(int argc, char *argv[]);
void readGameINI();
};
#endif // CONFIG_H

View File

@ -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());

View File

@ -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 */

View File

@ -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();
}

View File

@ -111,7 +111,7 @@ struct BindingDesc
typedef std::vector<BindingDesc> BDescVec;
struct Config;
BDescVec genDefaultBindings(const Config &conf);
BDescVec genDefaultBindings();
void storeBindings(const BDescVec &d, const Config &conf);
BDescVec loadBindings(const Config &conf);

View File

@ -206,8 +206,6 @@ int main(int argc, char *argv[])
return 0;
}
conf.readGameINI();
assert(conf.rgssVersion >= 1 && conf.rgssVersion <= 3);
printRgssVersion(conf.rgssVersion);

459
src/oneshot.cpp Normal file
View File

@ -0,0 +1,459 @@
#include "oneshot.h"
/******************
* HERE BE DRAGONS
******************/
#include "eventthread.h"
#include "debugwriter.h"
#include <SDL2/SDL.h>
//OS-Specific code
#if defined _WIN32
#define OS_W32
#define WIN32_LEAN_AND_MEAN
#define SECURITY_WIN32
#include <windows.h>
#include <security.h>
#include <shlobj.h>
#include <SDL2/SDL_syswm.h>
#elif defined __APPLE__
#define OS_OSX
#elif defined __linux__
#define OS_LINUX
#include <stdlib.h>
#include <unistd.h>
#include <pwd.h>
#include <dlfcn.h>
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<linux_DialogData*>(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<void**>(&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
}

60
src/oneshot.h Normal file
View File

@ -0,0 +1,60 @@
#ifndef ONESHOT_H
#define ONESHOT_H
#include "etc-internal.h"
#include <string>
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

View File

@ -37,7 +37,7 @@
#include <algorithm>
#include <assert.h>
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);

View File

@ -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)

View File

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

View File

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