From 79dbb9856d0c865abfe31c6ddc54e2238d37e35d Mon Sep 17 00:00:00 2001 From: Roza Date: Mon, 22 Feb 2021 18:36:53 -0500 Subject: [PATCH] Input.count, Input.repeatcount, System.user_name --- binding/binding-mri.cpp | 1218 +++++++++++++++++++------------------ binding/input-binding.cpp | 29 + src/input/input.cpp | 23 + src/input/input.h | 2 + 4 files changed, 667 insertions(+), 605 deletions(-) diff --git a/binding/binding-mri.cpp b/binding/binding-mri.cpp index 180fa727..4b162ac0 100644 --- a/binding/binding-mri.cpp +++ b/binding/binding-mri.cpp @@ -1,23 +1,23 @@ /* -** binding-mri.cpp -** -** This file is part of mkxp. -** -** Copyright (C) 2013 Jonas Kulla -** -** mkxp is free software: you can redistribute it and/or modify -** it under the terms of the GNU General Public License as published by -** the Free Software Foundation, either version 2 of the License, or -** (at your option) any later version. -** -** mkxp is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -** -** You should have received a copy of the GNU General Public License -** along with mkxp. If not, see . -*/ + ** binding-mri.cpp + ** + ** This file is part of mkxp. + ** + ** Copyright (C) 2013 Jonas Kulla + ** + ** mkxp is free software: you can redistribute it and/or modify + ** it under the terms of the GNU General Public License as published by + ** the Free Software Foundation, either version 2 of the License, or + ** (at your option) any later version. + ** + ** mkxp is distributed in the hope that it will be useful, + ** but WITHOUT ANY WARRANTY; without even the implied warranty of + ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + ** GNU General Public License for more details. + ** + ** You should have received a copy of the GNU General Public License + ** along with mkxp. If not, see . + */ #include "audio/audio.h" #include "filesystem/filesystem.h" @@ -80,7 +80,7 @@ static void mriBindingTerminate(); static void mriBindingReset(); ScriptBinding scriptBindingImpl = {mriBindingExecute, mriBindingTerminate, - mriBindingReset}; + mriBindingReset}; ScriptBinding *scriptBinding = &scriptBindingImpl; @@ -122,6 +122,7 @@ RB_METHOD(mkxpRawKeyStates); RB_METHOD(mkxpMouseInWindow); RB_METHOD(mkxpPlatform); RB_METHOD(mkxpUserLanguage); +RB_METHOD(mkxpUserName); RB_METHOD(mkxpGameTitle); RB_METHOD(mkxpPowerState); RB_METHOD(mkxpSettingsMenu); @@ -136,253 +137,260 @@ RB_METHOD(mriRgssStop); RB_METHOD(_kernelCaller); static void mriBindingInit() { - tableBindingInit(); - etcBindingInit(); - fontBindingInit(); - bitmapBindingInit(); - spriteBindingInit(); - viewportBindingInit(); - planeBindingInit(); - - if (rgssVer == 1) { - windowBindingInit(); - tilemapBindingInit(); - } else { - windowVXBindingInit(); - tilemapVXBindingInit(); - } - - inputBindingInit(); - audioBindingInit(); - graphicsBindingInit(); - - fileIntBindingInit(); - + tableBindingInit(); + etcBindingInit(); + fontBindingInit(); + bitmapBindingInit(); + spriteBindingInit(); + viewportBindingInit(); + planeBindingInit(); + + if (rgssVer == 1) { + windowBindingInit(); + tilemapBindingInit(); + } else { + windowVXBindingInit(); + tilemapVXBindingInit(); + } + + inputBindingInit(); + audioBindingInit(); + graphicsBindingInit(); + + fileIntBindingInit(); + #ifdef MKXPZ_MINIFFI - MiniFFIBindingInit(); -#endif - -#ifdef MKXPZ_STEAM - CUSLBindingInit(); + MiniFFIBindingInit(); #endif - httpBindingInit(); - - if (rgssVer >= 3) { - _rb_define_module_function(rb_mKernel, "rgss_main", mriRgssMain); - _rb_define_module_function(rb_mKernel, "rgss_stop", mriRgssStop); - - _rb_define_module_function(rb_mKernel, "msgbox", mriPrint); - _rb_define_module_function(rb_mKernel, "msgbox_p", mriP); - - rb_define_global_const("RGSS_VERSION", rb_str_new_cstr("3.0.1")); - } else { - _rb_define_module_function(rb_mKernel, "print", mriPrint); - _rb_define_module_function(rb_mKernel, "p", mriP); - - rb_define_alias(rb_singleton_class(rb_mKernel), "_mkxp_kernel_caller_alias", - "caller"); - _rb_define_module_function(rb_mKernel, "caller", _kernelCaller); - } - - if (rgssVer == 1) - rb_eval_string(module_rpg1); - else if (rgssVer == 2) - rb_eval_string(module_rpg2); - else if (rgssVer == 3) - rb_eval_string(module_rpg3); - else - assert(!"unreachable"); - - VALUE mod = rb_define_module("System"); - _rb_define_module_function(mod, "data_directory", mkxpDataDirectory); - _rb_define_module_function(mod, "set_window_title", mkxpSetTitle); - _rb_define_module_function(mod, "show_settings", mkxpSettingsMenu); - _rb_define_module_function(mod, "puts", mkxpPuts); - _rb_define_module_function(mod, "desensitize", mkxpDesensitize); - _rb_define_module_function(mod, "raw_key_states", mkxpRawKeyStates); - _rb_define_module_function(mod, "mouse_in_window", mkxpMouseInWindow); - _rb_define_module_function(mod, "platform", mkxpPlatform); - _rb_define_module_function(mod, "user_language", mkxpUserLanguage); - _rb_define_module_function(mod, "game_title", mkxpGameTitle); - _rb_define_module_function(mod, "power_state", mkxpPowerState); - _rb_define_module_function(mod, "nproc", mkxpCpuCount); - _rb_define_module_function(mod, "memory", mkxpSystemMemory); +#ifdef MKXPZ_STEAM + CUSLBindingInit(); +#endif + + httpBindingInit(); + + if (rgssVer >= 3) { + _rb_define_module_function(rb_mKernel, "rgss_main", mriRgssMain); + _rb_define_module_function(rb_mKernel, "rgss_stop", mriRgssStop); + + _rb_define_module_function(rb_mKernel, "msgbox", mriPrint); + _rb_define_module_function(rb_mKernel, "msgbox_p", mriP); + + rb_define_global_const("RGSS_VERSION", rb_str_new_cstr("3.0.1")); + } else { + _rb_define_module_function(rb_mKernel, "print", mriPrint); + _rb_define_module_function(rb_mKernel, "p", mriP); + + rb_define_alias(rb_singleton_class(rb_mKernel), "_mkxp_kernel_caller_alias", + "caller"); + _rb_define_module_function(rb_mKernel, "caller", _kernelCaller); + } + + if (rgssVer == 1) + rb_eval_string(module_rpg1); + else if (rgssVer == 2) + rb_eval_string(module_rpg2); + else if (rgssVer == 3) + rb_eval_string(module_rpg3); + else + assert(!"unreachable"); + + VALUE mod = rb_define_module("System"); + _rb_define_module_function(mod, "data_directory", mkxpDataDirectory); + _rb_define_module_function(mod, "set_window_title", mkxpSetTitle); + _rb_define_module_function(mod, "show_settings", mkxpSettingsMenu); + _rb_define_module_function(mod, "puts", mkxpPuts); + _rb_define_module_function(mod, "desensitize", mkxpDesensitize); + _rb_define_module_function(mod, "raw_key_states", mkxpRawKeyStates); + _rb_define_module_function(mod, "mouse_in_window", mkxpMouseInWindow); + _rb_define_module_function(mod, "platform", mkxpPlatform); + _rb_define_module_function(mod, "user_language", mkxpUserLanguage); + _rb_define_module_function(mod, "user_name", mkxpUserName); + _rb_define_module_function(mod, "game_title", mkxpGameTitle); + _rb_define_module_function(mod, "power_state", mkxpPowerState); + _rb_define_module_function(mod, "nproc", mkxpCpuCount); + _rb_define_module_function(mod, "memory", mkxpSystemMemory); _rb_define_module_function(mod, "reload_cache", mkxpReloadPathCache); _rb_define_module_function(mod, "mount", mkxpAddPath); _rb_define_module_function(mod, "unmount", mkxpRemovePath); - - /* Load global constants */ - rb_gv_set("MKXP", Qtrue); - rb_const_set(mod, rb_intern("VERSION"), rb_str_new_cstr(MACRO_STRINGIFY(MKXPZ_VERSION))); - - VALUE debug = rb_bool_new(shState->config().editor.debug); - if (rgssVer == 1) - rb_gv_set("DEBUG", debug); - else if (rgssVer >= 2) - rb_gv_set("TEST", debug); - - rb_gv_set("BTEST", rb_bool_new(shState->config().editor.battleTest)); - // Load zlib, if it's present. Requires --with-static-linked-ext or zlib.so. - // It's okay if it fails, normally it wouldn't be defined anyway. - // It's included with normal RGSS though, so I'd prefer if it's loaded at the start. - rb_eval_string("begin;require 'zlib';rescue;nil;end"); + /* Load global constants */ + rb_gv_set("MKXP", Qtrue); + rb_const_set(mod, rb_intern("VERSION"), rb_str_new_cstr(MACRO_STRINGIFY(MKXPZ_VERSION))); + + VALUE debug = rb_bool_new(shState->config().editor.debug); + if (rgssVer == 1) + rb_gv_set("DEBUG", debug); + else if (rgssVer >= 2) + rb_gv_set("TEST", debug); + + rb_gv_set("BTEST", rb_bool_new(shState->config().editor.battleTest)); + + // Load zlib, if it's present. Requires --with-static-linked-ext or zlib.so. + // It's okay if it fails, normally it wouldn't be defined anyway. + // It's included with normal RGSS though, so I'd prefer if it's loaded at the start. + rb_eval_string("begin;require 'zlib';rescue;nil;end"); } static void showMsg(const std::string &msg) { - shState->eThread().showMessageBox(msg.c_str()); + shState->eThread().showMessageBox(msg.c_str()); } static void printP(int argc, VALUE *argv, const char *convMethod, const char *sep) { - VALUE dispString = rb_str_buf_new(128); - ID conv = rb_intern(convMethod); - - for (int i = 0; i < argc; ++i) { - VALUE str = rb_funcall2(argv[i], conv, 0, NULL); - rb_str_buf_append(dispString, str); - - if (i < argc) - rb_str_buf_cat2(dispString, sep); - } - - showMsg(RSTRING_PTR(dispString)); + VALUE dispString = rb_str_buf_new(128); + ID conv = rb_intern(convMethod); + + for (int i = 0; i < argc; ++i) { + VALUE str = rb_funcall2(argv[i], conv, 0, NULL); + rb_str_buf_append(dispString, str); + + if (i < argc) + rb_str_buf_cat2(dispString, sep); + } + + showMsg(RSTRING_PTR(dispString)); } RB_METHOD(mriPrint) { - RB_UNUSED_PARAM; - - printP(argc, argv, "to_s", ""); - - return Qnil; + RB_UNUSED_PARAM; + + printP(argc, argv, "to_s", ""); + + return Qnil; } RB_METHOD(mriP) { - RB_UNUSED_PARAM; - - printP(argc, argv, "inspect", "\n"); - - return Qnil; + RB_UNUSED_PARAM; + + printP(argc, argv, "inspect", "\n"); + + return Qnil; } RB_METHOD(mkxpDataDirectory) { - RB_UNUSED_PARAM; - - const std::string &path = shState->config().customDataPath; - const char *s = path.empty() ? "." : path.c_str(); - - std::string s_nml = shState->fileSystem().normalize(s, 1, 1); - VALUE ret = rb_str_new_cstr(s_nml.c_str()); - - return ret; + RB_UNUSED_PARAM; + + const std::string &path = shState->config().customDataPath; + const char *s = path.empty() ? "." : path.c_str(); + + std::string s_nml = shState->fileSystem().normalize(s, 1, 1); + VALUE ret = rb_str_new_cstr(s_nml.c_str()); + + return ret; } RB_METHOD(mkxpSetTitle) { - RB_UNUSED_PARAM; - - VALUE s; - rb_scan_args(argc, argv, "1", &s); - SafeStringValue(s); - - shState->eThread().requestWindowRename(RSTRING_PTR(s)); - return s; + RB_UNUSED_PARAM; + + VALUE s; + rb_scan_args(argc, argv, "1", &s); + SafeStringValue(s); + + shState->eThread().requestWindowRename(RSTRING_PTR(s)); + return s; } RB_METHOD(mkxpDesensitize) { - RB_UNUSED_PARAM; - - VALUE filename; - rb_scan_args(argc, argv, "1", &filename); - SafeStringValue(filename); - - return rb_str_new_cstr( - shState->fileSystem().desensitize(RSTRING_PTR(filename))); + RB_UNUSED_PARAM; + + VALUE filename; + rb_scan_args(argc, argv, "1", &filename); + SafeStringValue(filename); + + return rb_str_new_cstr( + shState->fileSystem().desensitize(RSTRING_PTR(filename))); } RB_METHOD(mkxpPuts) { - RB_UNUSED_PARAM; - - const char *str; - rb_get_args(argc, argv, "z", &str RB_ARG_END); - - Debug() << str; - - return Qnil; + RB_UNUSED_PARAM; + + const char *str; + rb_get_args(argc, argv, "z", &str RB_ARG_END); + + Debug() << str; + + return Qnil; } RB_METHOD(mkxpRawKeyStates) { - RB_UNUSED_PARAM; - - VALUE str = rb_str_new(0, sizeof(EventThread::keyStates)); - memcpy(RSTRING_PTR(str), EventThread::keyStates, - sizeof(EventThread::keyStates)); - - return str; + RB_UNUSED_PARAM; + + VALUE str = rb_str_new(0, sizeof(EventThread::keyStates)); + memcpy(RSTRING_PTR(str), EventThread::keyStates, + sizeof(EventThread::keyStates)); + + return str; } RB_METHOD(mkxpMouseInWindow) { - RB_UNUSED_PARAM; - - return rb_bool_new(EventThread::mouseState.inWindow); + RB_UNUSED_PARAM; + + return rb_bool_new(EventThread::mouseState.inWindow); } RB_METHOD(mkxpPlatform) { - RB_UNUSED_PARAM; - - return rb_str_new_cstr(SDL_GetPlatform()); + RB_UNUSED_PARAM; + + return rb_str_new_cstr(SDL_GetPlatform()); } RB_METHOD(mkxpUserLanguage) { - RB_UNUSED_PARAM; + RB_UNUSED_PARAM; + + return rb_str_new_cstr(mkxp_sys::getSystemLanguage().c_str()); +} - return rb_str_new_cstr(mkxp_sys::getSystemLanguage().c_str()); +RB_METHOD(mkxpUserName) { + RB_UNUSED_PARAM; + + return rb_str_new_cstr(mkxp_sys::getUserName().c_str()); } RB_METHOD(mkxpGameTitle) { - RB_UNUSED_PARAM; - - return rb_str_new_cstr(shState->config().game.title.c_str()); + RB_UNUSED_PARAM; + + return rb_str_new_cstr(shState->config().game.title.c_str()); } RB_METHOD(mkxpPowerState) { - RB_UNUSED_PARAM; - - int secs, pct; - SDL_PowerState ps = SDL_GetPowerInfo(&secs, &pct); - - VALUE hash = rb_hash_new(); - - rb_hash_aset(hash, ID2SYM(rb_intern("seconds")), - (secs > -1) ? INT2NUM(secs) : RUBY_Qnil); - - rb_hash_aset(hash, ID2SYM(rb_intern("percent")), - (pct > -1) ? INT2NUM(pct) : RUBY_Qnil); - - rb_hash_aset(hash, ID2SYM(rb_intern("discharging")), - rb_bool_new(ps == SDL_POWERSTATE_ON_BATTERY)); - - return hash; + RB_UNUSED_PARAM; + + int secs, pct; + SDL_PowerState ps = SDL_GetPowerInfo(&secs, &pct); + + VALUE hash = rb_hash_new(); + + rb_hash_aset(hash, ID2SYM(rb_intern("seconds")), + (secs > -1) ? INT2NUM(secs) : RUBY_Qnil); + + rb_hash_aset(hash, ID2SYM(rb_intern("percent")), + (pct > -1) ? INT2NUM(pct) : RUBY_Qnil); + + rb_hash_aset(hash, ID2SYM(rb_intern("discharging")), + rb_bool_new(ps == SDL_POWERSTATE_ON_BATTERY)); + + return hash; } RB_METHOD(mkxpSettingsMenu) { - RB_UNUSED_PARAM; - - shState->eThread().requestSettingsMenu(); - - return Qnil; + RB_UNUSED_PARAM; + + shState->eThread().requestSettingsMenu(); + + return Qnil; } RB_METHOD(mkxpCpuCount) { - RB_UNUSED_PARAM; - - return INT2NUM(SDL_GetCPUCount()); + RB_UNUSED_PARAM; + + return INT2NUM(SDL_GetCPUCount()); } RB_METHOD(mkxpSystemMemory) { - RB_UNUSED_PARAM; - - return INT2NUM(SDL_GetSystemRAM()); + RB_UNUSED_PARAM; + + return INT2NUM(SDL_GetSystemRAM()); } RB_METHOD(mkxpReloadPathCache) { @@ -426,420 +434,420 @@ RB_METHOD(mkxpRemovePath) { } static VALUE rgssMainCb(VALUE block) { - rb_funcall2(block, rb_intern("call"), 0, 0); - return Qnil; + rb_funcall2(block, rb_intern("call"), 0, 0); + return Qnil; } static VALUE rgssMainRescue(VALUE arg, VALUE exc) { - VALUE *excRet = (VALUE *)arg; - - *excRet = exc; - - return Qnil; + VALUE *excRet = (VALUE *)arg; + + *excRet = exc; + + return Qnil; } static void processReset() { - shState->graphics().reset(); - shState->audio().reset(); - - shState->rtData().rqReset.clear(); - shState->graphics().repaintWait(shState->rtData().rqResetFinish, false); + shState->graphics().reset(); + shState->audio().reset(); + + shState->rtData().rqReset.clear(); + shState->graphics().repaintWait(shState->rtData().rqResetFinish, false); } RB_METHOD(mriRgssMain) { - RB_UNUSED_PARAM; - - while (true) { - VALUE exc = Qnil; + RB_UNUSED_PARAM; + + while (true) { + VALUE exc = Qnil; #if RAPI_FULL < 270 - rb_rescue2((VALUE(*)(ANYARGS))rgssMainCb, rb_block_proc(), - (VALUE(*)(ANYARGS))rgssMainRescue, (VALUE)&exc, rb_eException, - (VALUE)0); + rb_rescue2((VALUE(*)(ANYARGS))rgssMainCb, rb_block_proc(), + (VALUE(*)(ANYARGS))rgssMainRescue, (VALUE)&exc, rb_eException, + (VALUE)0); #else - rb_rescue2(rgssMainCb, rb_block_proc(), rgssMainRescue, (VALUE)&exc, - rb_eException, (VALUE)0); + rb_rescue2(rgssMainCb, rb_block_proc(), rgssMainRescue, (VALUE)&exc, + rb_eException, (VALUE)0); #endif - - if (NIL_P(exc)) - break; - - if (rb_obj_class(exc) == getRbData()->exc[Reset]) - processReset(); - else - rb_exc_raise(exc); - } - - return Qnil; + + if (NIL_P(exc)) + break; + + if (rb_obj_class(exc) == getRbData()->exc[Reset]) + processReset(); + else + rb_exc_raise(exc); + } + + return Qnil; } RB_METHOD(mriRgssStop) { - RB_UNUSED_PARAM; - - while (true) - shState->graphics().update(); - - return Qnil; + RB_UNUSED_PARAM; + + while (true) + shState->graphics().update(); + + return Qnil; } RB_METHOD(_kernelCaller) { - RB_UNUSED_PARAM; - - VALUE trace = - rb_funcall2(rb_mKernel, rb_intern("_mkxp_kernel_caller_alias"), 0, 0); - - if (!RB_TYPE_P(trace, RUBY_T_ARRAY)) + RB_UNUSED_PARAM; + + VALUE trace = + rb_funcall2(rb_mKernel, rb_intern("_mkxp_kernel_caller_alias"), 0, 0); + + if (!RB_TYPE_P(trace, RUBY_T_ARRAY)) + return trace; + + long len = RARRAY_LEN(trace); + + if (len < 2) + return trace; + + /* Remove useless "ruby:1:in 'eval'" */ + rb_ary_pop(trace); + + /* Also remove trace of this helper function */ + rb_ary_shift(trace); + + len -= 2; + + if (len == 0) + return trace; + + /* RMXP does this, not sure if specific or 1.8 related */ + VALUE args[] = {rb_str_new_cstr(":in `
'"), rb_str_new_cstr("")}; + rb_funcall2(rb_ary_entry(trace, len - 1), rb_intern("gsub!"), 2, args); + return trace; - - long len = RARRAY_LEN(trace); - - if (len < 2) - return trace; - - /* Remove useless "ruby:1:in 'eval'" */ - rb_ary_pop(trace); - - /* Also remove trace of this helper function */ - rb_ary_shift(trace); - - len -= 2; - - if (len == 0) - return trace; - - /* RMXP does this, not sure if specific or 1.8 related */ - VALUE args[] = {rb_str_new_cstr(":in `
'"), rb_str_new_cstr("")}; - rb_funcall2(rb_ary_entry(trace, len - 1), rb_intern("gsub!"), 2, args); - - return trace; } #if RAPI_FULL > 187 static VALUE newStringUTF8(const char *string, long length) { - return rb_enc_str_new(string, length, rb_utf8_encoding()); + return rb_enc_str_new(string, length, rb_utf8_encoding()); } #else #define newStringUTF8 rb_str_new #endif struct evalArg { - VALUE string; - VALUE filename; + VALUE string; + VALUE filename; }; static VALUE evalHelper(evalArg *arg) { - VALUE argv[] = {arg->string, Qnil, arg->filename}; - return rb_funcall2(Qnil, rb_intern("eval"), ARRAY_SIZE(argv), argv); + VALUE argv[] = {arg->string, Qnil, arg->filename}; + return rb_funcall2(Qnil, rb_intern("eval"), ARRAY_SIZE(argv), argv); } static VALUE evalString(VALUE string, VALUE filename, int *state) { - evalArg arg = {string, filename}; - return rb_protect((VALUE(*)(VALUE))evalHelper, (VALUE)&arg, state); + evalArg arg = {string, filename}; + return rb_protect((VALUE(*)(VALUE))evalHelper, (VALUE)&arg, state); } static void runCustomScript(const std::string &filename) { - std::string scriptData; - - if (!readFileSDL(filename.c_str(), scriptData)) { - showMsg(std::string("Unable to open '") + filename + "'"); - return; - } - - evalString(newStringUTF8(scriptData.c_str(), scriptData.size()), - newStringUTF8(filename.c_str(), filename.size()), NULL); + std::string scriptData; + + if (!readFileSDL(filename.c_str(), scriptData)) { + showMsg(std::string("Unable to open '") + filename + "'"); + return; + } + + evalString(newStringUTF8(scriptData.c_str(), scriptData.size()), + newStringUTF8(filename.c_str(), filename.size()), NULL); } VALUE kernelLoadDataInt(const char *filename, bool rubyExc, bool raw); struct BacktraceData { - /* Maps: Ruby visible filename, To: Actual script name */ - BoostHash scriptNames; + /* Maps: Ruby visible filename, To: Actual script name */ + BoostHash scriptNames; }; bool evalScript(VALUE string, const char *filename) { - int state; - evalString(string, rb_str_new_cstr(filename), &state); - if (state) return false; - return true; + int state; + evalString(string, rb_str_new_cstr(filename), &state); + if (state) return false; + return true; } #define SCRIPT_SECTION_FMT (rgssVer >= 3 ? "{%04ld}" : "Section%03ld") static void runRMXPScripts(BacktraceData &btData) { - const Config &conf = shState->rtData().config; - const std::string &scriptPack = conf.game.scripts; - const char *platform = SDL_GetPlatform(); - - if (scriptPack.empty()) { - showMsg("No game scripts specified (missing Game.ini?)"); - return; - } - - if (!shState->fileSystem().exists(scriptPack.c_str())) { - showMsg("Unable to open '" + scriptPack + "'"); - return; - } - - VALUE scriptArray; - - /* We checked if Scripts.rxdata exists, but something might - * still go wrong */ - try { - scriptArray = kernelLoadDataInt(scriptPack.c_str(), false, false); - } catch (const Exception &e) { - showMsg(std::string("Failed to read script data: ") + e.msg); - return; - } - - if (!RB_TYPE_P(scriptArray, RUBY_T_ARRAY)) { - showMsg("Failed to read script data"); - return; - } - - rb_gv_set("$RGSS_SCRIPTS", scriptArray); - - long scriptCount = RARRAY_LEN(scriptArray); - - std::string decodeBuffer; - decodeBuffer.resize(0x1000); - - for (long i = 0; i < scriptCount; ++i) { - VALUE script = rb_ary_entry(scriptArray, i); - - if (!RB_TYPE_P(script, RUBY_T_ARRAY)) - continue; - - VALUE scriptName = rb_ary_entry(script, 1); - VALUE scriptString = rb_ary_entry(script, 2); - - int result = Z_OK; - unsigned long bufferLen; - - while (true) { - unsigned char *bufferPtr = reinterpret_cast( - const_cast(decodeBuffer.c_str())); - const unsigned char *sourcePtr = - reinterpret_cast(RSTRING_PTR(scriptString)); - - bufferLen = decodeBuffer.length(); - - result = uncompress(bufferPtr, &bufferLen, sourcePtr, - RSTRING_LEN(scriptString)); - - bufferPtr[bufferLen] = '\0'; - - if (result != Z_BUF_ERROR) - break; - - decodeBuffer.resize(decodeBuffer.size() * 2); + const Config &conf = shState->rtData().config; + const std::string &scriptPack = conf.game.scripts; + const char *platform = SDL_GetPlatform(); + + if (scriptPack.empty()) { + showMsg("No game scripts specified (missing Game.ini?)"); + return; } - - if (result != Z_OK) { - static char buffer[256]; - snprintf(buffer, sizeof(buffer), "Error decoding script %ld: '%s'", i, - RSTRING_PTR(scriptName)); - - showMsg(buffer); - - break; + + if (!shState->fileSystem().exists(scriptPack.c_str())) { + showMsg("Unable to open '" + scriptPack + "'"); + return; } - - rb_ary_store(script, 3, rb_str_new_cstr(decodeBuffer.c_str())); - } - - // Can be force-disabled similarly to framerate options -#ifndef MKXPZ_NO_PRELOADSCRIPTS - /* Execute preloaded scripts */ - for (std::vector::const_iterator i = conf.preloadScripts.begin(); - i != conf.preloadScripts.end(); ++i) - runCustomScript(*i); - - VALUE exc = rb_gv_get("$!"); - if (exc != Qnil) - return; - -#ifdef MKXPZ_ESSENTIALS_DEBUG - // Used to try and fix Essentials garbage later if it's detected - int minimonsters = 0; -#endif - - while (true) { -#if RAPI_FULL < 200 && defined(MKXPZ_DISABLE_CONSOLE) - VALUE iostr = rb_str_new2(NULL_IO); - // Sysinit isn't a thing yet, so send io to /dev/null instead - rb_funcall(rb_gv_get("$stderr"), rb_intern("reopen"), 1, iostr); - rb_funcall(rb_gv_get("$stdout"), rb_intern("reopen"), 1, iostr); -#endif + + VALUE scriptArray; + + /* We checked if Scripts.rxdata exists, but something might + * still go wrong */ + try { + scriptArray = kernelLoadDataInt(scriptPack.c_str(), false, false); + } catch (const Exception &e) { + showMsg(std::string("Failed to read script data: ") + e.msg); + return; + } + + if (!RB_TYPE_P(scriptArray, RUBY_T_ARRAY)) { + showMsg("Failed to read script data"); + return; + } + + rb_gv_set("$RGSS_SCRIPTS", scriptArray); + + long scriptCount = RARRAY_LEN(scriptArray); + + std::string decodeBuffer; + decodeBuffer.resize(0x1000); + for (long i = 0; i < scriptCount; ++i) { - VALUE script = rb_ary_entry(scriptArray, i); - VALUE scriptDecoded = rb_ary_entry(script, 3); - VALUE string = - newStringUTF8(RSTRING_PTR(scriptDecoded), RSTRING_LEN(scriptDecoded)); - - VALUE fname; - const char *scriptName = RSTRING_PTR(rb_ary_entry(script, 1)); - 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); - - fname = newStringUTF8(buf, len); - btData.scriptNames.insert(buf, scriptName); - -#ifdef MKXPZ_ESSENTIALS_DEBUG - // There is 0 reason for anything other than Essentials to have this class - if (minimonsters == 0 && rb_const_defined(rb_cObject, rb_intern("PokemonMapMetadata"))) - minimonsters = 1; -#endif - - // Before checking to see if the next script should be skipped, - // make sure to check whether it's the last one or not and run - // any extra stuff before the end (primarily stupid Essentials fixes) - // Will be placed within a build option later if I decide to add more -#ifndef MKXPZ_BUILD_XCODE - #define SCRIPT(name) rb_str_new((const char*)&___scripts_##name##_rb, ___scripts_##name##_rb_len), #name " (Internal)" - #define EVALFILE(name) if (!evalScript(SCRIPT(name))) break; -#else - #define EVALFILE(name) { \ - std::string s = mkxp_fs::contentsOfAssetAsString("BindingScripts/" #name, "rb"); \ - if (!evalScript(rb_str_new_cstr(s.c_str()), #name)) break; \ - } -#endif - if (i + 2 == scriptCount){ -#ifdef MKXPZ_ESSENTIALS_DEBUG - if (minimonsters > 0 && !RTEST(rb_gv_get("Z_NOPOKEFIX"))){ - EVALFILE(EssentialsCompatibility); - minimonsters = -1; - } -#endif - } - - // if the script name starts with |s|, only execute - // it if "s" is the same first letter as the platform - // we're running on - - // |W| - Windows, |M| - Mac OS X, |L| - Linux - - // Adding a 'not' symbol means it WON'T run on that - // platform (i.e. |!W| won't run on Windows) - - if (scriptName[0] == '|') { - int len = strlen(scriptName); - if (len > 2) { - if (scriptName[1] == '!' && len > 3 && - scriptName[3] == scriptName[0]) { - if (toupper(scriptName[2]) == platform[0]) - continue; - } - if (scriptName[2] == scriptName[0] && - toupper(scriptName[1]) != platform[0]) + VALUE script = rb_ary_entry(scriptArray, i); + + if (!RB_TYPE_P(script, RUBY_T_ARRAY)) continue; + + VALUE scriptName = rb_ary_entry(script, 1); + VALUE scriptString = rb_ary_entry(script, 2); + + int result = Z_OK; + unsigned long bufferLen; + + while (true) { + unsigned char *bufferPtr = reinterpret_cast( + const_cast(decodeBuffer.c_str())); + const unsigned char *sourcePtr = + reinterpret_cast(RSTRING_PTR(scriptString)); + + bufferLen = decodeBuffer.length(); + + result = uncompress(bufferPtr, &bufferLen, sourcePtr, + RSTRING_LEN(scriptString)); + + bufferPtr[bufferLen] = '\0'; + + if (result != Z_BUF_ERROR) + break; + + decodeBuffer.resize(decodeBuffer.size() * 2); } - } - - int state; - - evalString(string, fname, &state); - if (state) - break; + + if (result != Z_OK) { + static char buffer[256]; + snprintf(buffer, sizeof(buffer), "Error decoding script %ld: '%s'", i, + RSTRING_PTR(scriptName)); + + showMsg(buffer); + + break; + } + + rb_ary_store(script, 3, rb_str_new_cstr(decodeBuffer.c_str())); } - + + // Can be force-disabled similarly to framerate options +#ifndef MKXPZ_NO_PRELOADSCRIPTS + /* Execute preloaded scripts */ + for (std::vector::const_iterator i = conf.preloadScripts.begin(); + i != conf.preloadScripts.end(); ++i) + runCustomScript(*i); + VALUE exc = rb_gv_get("$!"); - if (rb_obj_class(exc) != getRbData()->exc[Reset]) - break; - - processReset(); - } + if (exc != Qnil) + return; + +#ifdef MKXPZ_ESSENTIALS_DEBUG + // Used to try and fix Essentials garbage later if it's detected + int minimonsters = 0; +#endif + + while (true) { +#if RAPI_FULL < 200 && defined(MKXPZ_DISABLE_CONSOLE) + VALUE iostr = rb_str_new2(NULL_IO); + // Sysinit isn't a thing yet, so send io to /dev/null instead + rb_funcall(rb_gv_get("$stderr"), rb_intern("reopen"), 1, iostr); + rb_funcall(rb_gv_get("$stdout"), rb_intern("reopen"), 1, iostr); +#endif + for (long i = 0; i < scriptCount; ++i) { + VALUE script = rb_ary_entry(scriptArray, i); + VALUE scriptDecoded = rb_ary_entry(script, 3); + VALUE string = + newStringUTF8(RSTRING_PTR(scriptDecoded), RSTRING_LEN(scriptDecoded)); + + VALUE fname; + const char *scriptName = RSTRING_PTR(rb_ary_entry(script, 1)); + 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); + + fname = newStringUTF8(buf, len); + btData.scriptNames.insert(buf, scriptName); + +#ifdef MKXPZ_ESSENTIALS_DEBUG + // There is 0 reason for anything other than Essentials to have this class + if (minimonsters == 0 && rb_const_defined(rb_cObject, rb_intern("PokemonMapMetadata"))) + minimonsters = 1; +#endif + + // Before checking to see if the next script should be skipped, + // make sure to check whether it's the last one or not and run + // any extra stuff before the end (primarily stupid Essentials fixes) + // Will be placed within a build option later if I decide to add more +#ifndef MKXPZ_BUILD_XCODE +#define SCRIPT(name) rb_str_new((const char*)&___scripts_##name##_rb, ___scripts_##name##_rb_len), #name " (Internal)" +#define EVALFILE(name) if (!evalScript(SCRIPT(name))) break; +#else +#define EVALFILE(name) { \ +std::string s = mkxp_fs::contentsOfAssetAsString("BindingScripts/" #name, "rb"); \ +if (!evalScript(rb_str_new_cstr(s.c_str()), #name)) break; \ +} +#endif + if (i + 2 == scriptCount){ +#ifdef MKXPZ_ESSENTIALS_DEBUG + if (minimonsters > 0 && !RTEST(rb_gv_get("Z_NOPOKEFIX"))){ + EVALFILE(EssentialsCompatibility); + minimonsters = -1; + } +#endif + } + + // if the script name starts with |s|, only execute + // it if "s" is the same first letter as the platform + // we're running on + + // |W| - Windows, |M| - Mac OS X, |L| - Linux + + // Adding a 'not' symbol means it WON'T run on that + // platform (i.e. |!W| won't run on Windows) + + if (scriptName[0] == '|') { + int len = strlen(scriptName); + if (len > 2) { + if (scriptName[1] == '!' && len > 3 && + scriptName[3] == scriptName[0]) { + if (toupper(scriptName[2]) == platform[0]) + continue; + } + if (scriptName[2] == scriptName[0] && + toupper(scriptName[1]) != platform[0]) + continue; + } + } + + int state; + + evalString(string, fname, &state); + if (state) + break; + } + + VALUE exc = rb_gv_get("$!"); + if (rb_obj_class(exc) != getRbData()->exc[Reset]) + break; + + processReset(); + } } #endif static void showExc(VALUE exc, const BacktraceData &btData) { - VALUE bt = rb_funcall2(exc, rb_intern("backtrace"), 0, NULL); - VALUE msg = rb_funcall2(exc, rb_intern("message"), 0, NULL); - VALUE bt0 = rb_ary_entry(bt, 0); - VALUE name = rb_class_path(rb_obj_class(exc)); - - VALUE ds = rb_sprintf("%" PRIsVALUE ": %" PRIsVALUE " (%" PRIsVALUE ")", + VALUE bt = rb_funcall2(exc, rb_intern("backtrace"), 0, NULL); + VALUE msg = rb_funcall2(exc, rb_intern("message"), 0, NULL); + VALUE bt0 = rb_ary_entry(bt, 0); + VALUE name = rb_class_path(rb_obj_class(exc)); + + VALUE ds = rb_sprintf("%" PRIsVALUE ": %" PRIsVALUE " (%" PRIsVALUE ")", #if RAPI_MAJOR >= 2 - bt0, exc, name); + bt0, exc, name); #else - // Ruby 1.9's version of this function needs char* - RSTRING_PTR(bt0), RSTRING_PTR(exc), RSTRING_PTR(name)); + // Ruby 1.9's version of this function needs char* + RSTRING_PTR(bt0), RSTRING_PTR(exc), RSTRING_PTR(name)); #endif - /* omit "useless" last entry (from ruby:1:in `eval') */ - for (long i = 1, btlen = RARRAY_LEN(bt) - 1; i < btlen; ++i) + /* omit "useless" last entry (from ruby:1:in `eval') */ + for (long i = 1, btlen = RARRAY_LEN(bt) - 1; i < btlen; ++i) rb_str_catf(ds, "\n\tfrom %" PRIsVALUE, #if RAPI_MAJOR >= 2 - rb_ary_entry(bt, i)); + rb_ary_entry(bt, i)); #else RSTRING_PTR(rb_ary_entry(bt, i))); #endif - Debug() << StringValueCStr(ds); - - char *s = RSTRING_PTR(bt0); - - char line[16]; - std::string file(512, '\0'); - - char *p = s + strlen(s); - char *e; - - while (p != s) - if (*--p == ':') - break; - - e = p; - - while (p != s) - if (*--p == ':') - break; - - /* s p e - * SectionXXX:YY: in 'blabla' */ - - *e = '\0'; - strncpy(line, *p ? p + 1 : p, sizeof(line)); - line[sizeof(line) - 1] = '\0'; - *e = ':'; - e = p; - - /* s e - * SectionXXX:YY: in 'blabla' */ - - *e = '\0'; - strncpy(&file[0], s, file.size()); - *e = ':'; - - /* Shrink to fit */ - file.resize(strlen(file.c_str())); - file = btData.scriptNames.value(file, file); - - std::string ms(640, '\0'); - snprintf(&ms[0], ms.size(), "Script '%s' line %s: %s occured.\n\n%s", - file.c_str(), line, RSTRING_PTR(name), RSTRING_PTR(msg)); - - showMsg(ms); + Debug() << StringValueCStr(ds); + + char *s = RSTRING_PTR(bt0); + + char line[16]; + std::string file(512, '\0'); + + char *p = s + strlen(s); + char *e; + + while (p != s) + if (*--p == ':') + break; + + e = p; + + while (p != s) + if (*--p == ':') + break; + + /* s p e + * SectionXXX:YY: in 'blabla' */ + + *e = '\0'; + strncpy(line, *p ? p + 1 : p, sizeof(line)); + line[sizeof(line) - 1] = '\0'; + *e = ':'; + e = p; + + /* s e + * SectionXXX:YY: in 'blabla' */ + + *e = '\0'; + strncpy(&file[0], s, file.size()); + *e = ':'; + + /* Shrink to fit */ + file.resize(strlen(file.c_str())); + file = btData.scriptNames.value(file, file); + + std::string ms(640, '\0'); + snprintf(&ms[0], ms.size(), "Script '%s' line %s: %s occured.\n\n%s", + file.c_str(), line, RSTRING_PTR(name), RSTRING_PTR(msg)); + + showMsg(ms); } static void mriBindingExecute() { - Config &conf = shState->rtData().config; - + Config &conf = shState->rtData().config; + #if RAPI_MAJOR >= 2 - /* Normally only a ruby executable would do a sysinit, - * but not doing it will lead to crashes due to closed - * stdio streams on some platforms (eg. Windows) */ - int argc = 0; - char **argv = 0; - ruby_sysinit(&argc, &argv); - - RUBY_INIT_STACK; - ruby_init(); - - std::vector rubyArgsC{"mkxp-z"}; + /* Normally only a ruby executable would do a sysinit, + * but not doing it will lead to crashes due to closed + * stdio streams on some platforms (eg. Windows) */ + int argc = 0; + char **argv = 0; + ruby_sysinit(&argc, &argv); + + RUBY_INIT_STACK; + ruby_init(); + + std::vector rubyArgsC{"mkxp-z"}; rubyArgsC.push_back("-e "); void *node; if (conf.jit.enabled) { @@ -855,78 +863,78 @@ static void mriBindingExecute() { node = ruby_options(rubyArgsC.size(), const_cast(rubyArgsC.data())); } - int state; - bool valid = ruby_executable_node(node, &state); - if (valid) - state = ruby_exec_node(node); - if (state || !valid) { - // The message is formatted for and automatically spits - // out to the terminal, so let's leave it that way for now -/* - VALUE exc = rb_errinfo(); - #if RAPI_FULL >= 250 - VALUE msg = rb_funcall(exc, rb_intern("full_message"), 0); - #else - VALUE msg = rb_funcall(exc, rb_intern("message"), 0); - #endif -*/ - showMsg("An error occurred while initializing Ruby. (Invalid JIT settings?)"); - ruby_cleanup(state); - shState->rtData().rqTermAck.set(); - return; - } + int state; + bool valid = ruby_executable_node(node, &state); + if (valid) + state = ruby_exec_node(node); + if (state || !valid) { + // The message is formatted for and automatically spits + // out to the terminal, so let's leave it that way for now + /* + VALUE exc = rb_errinfo(); + #if RAPI_FULL >= 250 + VALUE msg = rb_funcall(exc, rb_intern("full_message"), 0); + #else + VALUE msg = rb_funcall(exc, rb_intern("message"), 0); + #endif + */ + showMsg("An error occurred while initializing Ruby. (Invalid JIT settings?)"); + ruby_cleanup(state); + shState->rtData().rqTermAck.set(); + return; + } rb_enc_set_default_internal(rb_enc_from_encoding(rb_utf8_encoding())); rb_enc_set_default_external(rb_enc_from_encoding(rb_utf8_encoding())); #else - ruby_init(); - rb_eval_string("$KCODE='U'"); + ruby_init(); + rb_eval_string("$KCODE='U'"); #endif - + #if defined(MKXPZ_ESSENTIALS_DEBUG) && !defined(__WIN32__) - char *tmpdir = getenv("TMPDIR"); - if (tmpdir) - setenv("TEMP", tmpdir, false); + char *tmpdir = getenv("TMPDIR"); + if (tmpdir) + setenv("TEMP", tmpdir, false); #endif - - VALUE lpaths = rb_gv_get(":"); - if (!conf.rubyLoadpaths.empty()) { - /* Setup custom load paths */ - for (size_t i = 0; i < conf.rubyLoadpaths.size(); ++i) { - std::string &path = conf.rubyLoadpaths[i]; - - VALUE pathv = rb_str_new(path.c_str(), path.size()); - rb_ary_push(lpaths, pathv); + + VALUE lpaths = rb_gv_get(":"); + if (!conf.rubyLoadpaths.empty()) { + /* Setup custom load paths */ + for (size_t i = 0; i < conf.rubyLoadpaths.size(); ++i) { + std::string &path = conf.rubyLoadpaths[i]; + + VALUE pathv = rb_str_new(path.c_str(), path.size()); + rb_ary_push(lpaths, pathv); + } } - } #ifndef WORKDIR_CURRENT - else { - rb_ary_push(lpaths, rb_str_new_cstr(mkxp_fs::getCurrentDirectory().c_str())); - } + else { + rb_ary_push(lpaths, rb_str_new_cstr(mkxp_fs::getCurrentDirectory().c_str())); + } #endif - - RbData rbData; - shState->setBindingData(&rbData); - BacktraceData btData; - - mriBindingInit(); - - std::string &customScript = conf.customScript; - if (!customScript.empty()) - runCustomScript(customScript); - else - runRMXPScripts(btData); - + + RbData rbData; + shState->setBindingData(&rbData); + BacktraceData btData; + + mriBindingInit(); + + std::string &customScript = conf.customScript; + if (!customScript.empty()) + runCustomScript(customScript); + else + runRMXPScripts(btData); + #if RAPI_FULL > 187 - VALUE exc = rb_errinfo(); + VALUE exc = rb_errinfo(); #else - VALUE exc = rb_gv_get("$!"); + VALUE exc = rb_gv_get("$!"); #endif - if (!NIL_P(exc) && !rb_obj_is_kind_of(exc, rb_eSystemExit)) - showExc(exc, btData); - - ruby_cleanup(0); - - shState->rtData().rqTermAck.set(); + if (!NIL_P(exc) && !rb_obj_is_kind_of(exc, rb_eSystemExit)) + showExc(exc, btData); + + ruby_cleanup(0); + + shState->rtData().rqTermAck.set(); } static void mriBindingTerminate() { rb_raise(rb_eSystemExit, " "); } diff --git a/binding/input-binding.cpp b/binding/input-binding.cpp index bb4fbd3e..6d801e9b 100644 --- a/binding/input-binding.cpp +++ b/binding/input-binding.cpp @@ -125,6 +125,19 @@ RB_METHOD(inputRelease) { return rb_bool_new(shState->input().isReleased(num)); } +RB_METHOD(inputCount) { + RB_UNUSED_PARAM; + + rb_check_argc(argc, 1); + + VALUE button; + rb_scan_args(argc, argv, "1", &button); + + int num = getButtonArg(&button); + + return UINT2NUM(shState->input().count(num)); +} + RB_METHOD(inputPressEx) { RB_UNUSED_PARAM; @@ -181,6 +194,20 @@ RB_METHOD(inputReleaseEx) { return rb_bool_new(shState->input().isReleasedEx(NUM2INT(button), 1)); } +RB_METHOD(inputCountEx) { + RB_UNUSED_PARAM; + + VALUE button; + rb_scan_args(argc, argv, "1", &button); + + if (SYMBOL_P(button)) { + int num = getScancodeArg(&button); + return UINT2NUM(shState->input().repeatcount(num, 0)); + } + + return UINT2NUM(shState->input().repeatcount(NUM2INT(button), 1)); +} + RB_METHOD(inputDir4) { RB_UNUSED_PARAM; @@ -350,10 +377,12 @@ void inputBindingInit() { _rb_define_module_function(module, "trigger?", inputTrigger); _rb_define_module_function(module, "repeat?", inputRepeat); _rb_define_module_function(module, "release?", inputRelease); + _rb_define_module_function(module, "count", inputCount); _rb_define_module_function(module, "pressex?", inputPressEx); _rb_define_module_function(module, "triggerex?", inputTriggerEx); _rb_define_module_function(module, "repeatex?", inputRepeatEx); _rb_define_module_function(module, "releaseex?", inputReleaseEx); + _rb_define_module_function(module, "repeatcount", inputCountEx); _rb_define_module_function(module, "dir4", inputDir4); _rb_define_module_function(module, "dir8", inputDir8); diff --git a/src/input/input.cpp b/src/input/input.cpp index 3c2a6f69..20303393 100644 --- a/src/input/input.cpp +++ b/src/input/input.cpp @@ -1180,6 +1180,13 @@ bool Input::isReleased(int button) { return p->getStateCheck(button).released; } +unsigned int Input::count(int button) { + if (button != p->repeating) + return 0; + + return p->repeatCount; +} + bool Input::isPressedEx(int code, bool isVKey) { return p->getStateRaw(code, isVKey).pressed; @@ -1200,6 +1207,22 @@ bool Input::isReleasedEx(int code, bool isVKey) return p->getStateRaw(code, isVKey).released; } +unsigned int Input::repeatcount(int code, bool isVKey) { + unsigned int c = code; + if (isVKey) { + try { + c = vKeyToScancode[code]; + } + catch (...) { + return 0; + } + } + if (c != p->rawRepeating) + return 0; + + return p->rawRepeatCount; +} + int Input::dir4Value() { return p->dir4Data.active; diff --git a/src/input/input.h b/src/input/input.h index da644d75..778c0fc2 100644 --- a/src/input/input.h +++ b/src/input/input.h @@ -61,10 +61,12 @@ public: bool isTriggered(int button); bool isRepeated(int button); bool isReleased(int button); + unsigned int count(int button); bool isPressedEx(int code, bool isVKey); bool isTriggeredEx(int code, bool isVKey); bool isRepeatedEx(int code, bool isVKey); bool isReleasedEx(int code, bool isVKey); + unsigned int repeatcount(int code, bool isVKey); int dir4Value(); int dir8Value();