diff --git a/CMakeLists.txt b/CMakeLists.txt index 48dfb22..6a8a8c7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -284,6 +284,7 @@ set(BINDING_HEADERS binding-mri/sceneelement-binding.h binding-mri/viewportelement-binding.h binding-mri/flashable-binding.h + binding-mri/keybindings-binding.h ) set(BINDING_SOURCE binding-mri/binding-mri.cpp @@ -311,6 +312,7 @@ set(BINDING_SOURCE binding-mri/time-binding.cpp binding-mri/shader-binging.cpp binding-mri/modloader-binding.cpp + binding-mri/keybindings-binding.cpp ) source_group("Binding Source" FILES ${BINDING_SOURCE} ${BINDING_HEADERS}) diff --git a/binding-mri/binding-mri.cpp b/binding-mri/binding-mri.cpp index daa1207..8b15d40 100644 --- a/binding-mri/binding-mri.cpp +++ b/binding-mri/binding-mri.cpp @@ -138,6 +138,7 @@ void SunshineBindingInit(); void steamBindingInit(); void shaderBindingInit(); void ModLoaderBindingInit(); +void keybindingsBindingInit(); RB_METHOD(mriPrint); RB_METHOD(mriP); @@ -174,6 +175,7 @@ static void mriBindingInit(){ steamBindingInit(); shaderBindingInit(); ModLoaderBindingInit(); + keybindingsBindingInit(); _rb_define_module_function(rb_mKernel, "rgss_main", mriRgssMain); _rb_define_module_function(rb_mKernel, "rgss_stop", mriRgssStop); diff --git a/binding-mri/input-binding.cpp b/binding-mri/input-binding.cpp index 826d600..8c61fb3 100644 --- a/binding-mri/input-binding.cpp +++ b/binding-mri/input-binding.cpp @@ -24,6 +24,13 @@ #include "exception.h" #include "binding-util.h" #include "util.h" +#include "eventthread.h" + +#include "keybindings-binding.h" + +#include +#include +#include RB_METHOD(inputUpdate){ RB_UNUSED_PARAM; @@ -109,39 +116,198 @@ RB_METHOD(inputWheelFlipped) { return rb_bool_new(shState->input().wheelFlipped()); } -RB_METHOD(inputQuit){ +RB_METHOD(inputQuit) { RB_UNUSED_PARAM; return rb_bool_new(shState->input().hasQuit()); } +// keyboard +RB_METHOD(getKeyName) { + RB_UNUSED_PARAM; + + int key = 0; + rb_get_args(argc, argv, "i", &key RB_ARG_END); + + if (key >= 0 && key < SDL_Scancode::SDL_SCANCODE_COUNT) + return rb_utf8_str_new_cstr(SDL_GetKeyName(SDL_GetKeyFromScancode(static_cast(key), SDL_KMOD_NONE, false))); + + return rb_utf8_str_new_cstr(SDL_GetKeyName(SDLK_UNKNOWN)); +} + +RB_METHOD(keyPress) { + RB_UNUSED_PARAM; + + int key = 0; + rb_get_args(argc, argv, "i", &key RB_ARG_END); + + if (key >= 0 && key < SDL_Scancode::SDL_SCANCODE_COUNT) + return rb_bool_new(EventThread::keyStates[key]); + + return rb_bool_new(false); +} + +RB_METHOD(getPressedKey) { + RB_UNUSED_PARAM; + + short pressedKey = 0; + for(; pressedKey < SDL_Scancode::SDL_SCANCODE_COUNT && !EventThread::keyStates[pressedKey]; pressedKey++); + return pressedKey == SDL_Scancode::SDL_SCANCODE_COUNT ? Qnil : rb_fix_new(pressedKey); +} + +RB_METHOD(getKeyFromName) { + RB_UNUSED_PARAM; + + const char *name; + rb_get_args(argc, argv, "z", &name RB_ARG_END); + return rb_fix_new(SDL_GetScancodeFromName(name)); +} + +// gamepad buttons +RB_METHOD(getGamepadButtonName) { + RB_UNUSED_PARAM; + + int key = 0; + rb_get_args(argc, argv, "i", &key RB_ARG_END); + + if (key >= 0 && key < SDL_GamepadButton::SDL_GAMEPAD_BUTTON_COUNT) + return rb_utf8_str_new_cstr(SDL_GetGamepadStringForButton(static_cast(key))); + + return rb_utf8_str_new_cstr("Invalid"); +} + +RB_METHOD(gamepadButtonPress) { + RB_UNUSED_PARAM; + + int key = 0; + rb_get_args(argc, argv, "i", &key RB_ARG_END); + + if (key >= 0 && key < SDL_GamepadButton::SDL_GAMEPAD_BUTTON_COUNT) + return rb_bool_new(EventThread::gcState.buttons[key]); + + return rb_bool_new(false); +} + +RB_METHOD(getPressedGamepadButton) { + RB_UNUSED_PARAM; + + short pressedKey = 0; + for(; pressedKey < SDL_GamepadButton::SDL_GAMEPAD_BUTTON_COUNT && !EventThread::gcState.buttons[pressedKey]; pressedKey++); + return pressedKey == SDL_GamepadButton::SDL_GAMEPAD_BUTTON_COUNT ? Qnil : rb_fix_new(pressedKey); +} + +RB_METHOD(getGamepadButtonFromName) { + RB_UNUSED_PARAM; + + const char *name; + rb_get_args(argc, argv, "z", &name RB_ARG_END); + return rb_fix_new(SDL_GetGamepadButtonFromString(name)); +} + +// gamepad axes +RB_METHOD(getGamepadAxisName) { + RB_UNUSED_PARAM; + + int key = 0; + rb_get_args(argc, argv, "i", &key RB_ARG_END); + + if (key >= 0 && key < SDL_GamepadAxis::SDL_GAMEPAD_AXIS_COUNT) + return rb_utf8_str_new_cstr(SDL_GetGamepadStringForAxis(static_cast(key))); + + return rb_utf8_str_new_cstr("Invalid"); +} + +RB_METHOD(getGamepadAxisPressure) { + RB_UNUSED_PARAM; + + int key = 0; + rb_get_args(argc, argv, "i", &key RB_ARG_END); + + if (key >= 0 && key < SDL_GamepadAxis::SDL_GAMEPAD_AXIS_COUNT) + return rb_fix_new(EventThread::gcState.axes[key]); + + return rb_fix_new(0); +} + +RB_METHOD(getActiveGamepadAxis) { + RB_UNUSED_PARAM; + + int deadzone = 16000; + rb_get_args(argc, argv, "|i", &deadzone RB_ARG_END); + + short pressedKey = 0; + for(; pressedKey < SDL_GamepadAxis::SDL_GAMEPAD_AXIS_COUNT && (EventThread::gcState.axes[pressedKey] <= -32768 || std::abs(EventThread::gcState.axes[pressedKey]) < deadzone); pressedKey++); + return pressedKey == SDL_GamepadAxis::SDL_GAMEPAD_AXIS_COUNT ? Qnil : rb_fix_new(pressedKey); +} + +RB_METHOD(getGamepadAxisFromName) { + RB_UNUSED_PARAM; + + const char *name; + rb_get_args(argc, argv, "z", &name RB_ARG_END); + return rb_fix_new(SDL_GetGamepadAxisFromString(name)); +} + +static VALUE setBinding(VALUE self, VALUE rb_arr, VALUE rb_target){ + Check_Type(rb_arr, T_ARRAY); + + int target = FIX2INT(rb_target); + + long count = RARRAY_LEN(rb_arr); + + std::vector result; + result.reserve(count); + + for (size_t i = 0; i < count; ++i) + { + VALUE rb_binding = rb_ary_entry(rb_arr, i); + + //printf("bind\n"); + if (!rb_typeddata_is_kind_of(rb_binding, &sourceDesc_type)) + continue; + //printf("bind ok\n"); + + SourceDesc* src; + TypedData_Get_Struct(rb_binding, SourceDesc, &sourceDesc_type, src); + + result.push_back(*src); + } + + shState->input().setBinding(result, static_cast(target)); + + return Qnil; +} + + struct{ const char *str; Input::ButtonCode val; } static buttonCodes[] = { - { "DOWN", Input::Down }, - { "LEFT", Input::Left }, - { "RIGHT", Input::Right }, - { "UP", Input::Up }, + { "NONE", Input::None }, - { "ACTION", Input::Action }, - { "CANCEL", Input::Cancel }, - { "MENU", Input::Menu }, - { "ITEMS", Input::Items }, - { "RUN", Input::Run }, - { "DEACTIVATE", Input::Deactivate }, - - { "DEBUGACTION",Input::DebugAction}, + { "DOWN", Input::Down }, + { "LEFT", Input::Left }, + { "RIGHT", Input::Right }, + { "UP", Input::Up }, - { "L", Input::L }, - { "R", Input::R }, + { "ACTION", Input::Action }, + { "CANCEL", Input::Cancel }, + { "MENU", Input::Menu }, + { "ITEMS", Input::Items }, + { "RUN", Input::Run }, + { "DEACTIVATE", Input::Deactivate }, - { "F5", Input::F5 }, - { "F6", Input::F6 }, - { "F7", Input::F7 }, - { "F8", Input::F8 }, - { "F9", Input::F9 }, + { "DEBUGACTION", Input::DebugAction }, + + { "L", Input::L }, + { "R", Input::R }, + + { "F5", Input::F5 }, + { "F6", Input::F6 }, + { "F7", Input::F7 }, + { "F8", Input::F8 }, + { "F9", Input::F9 }, { "MOUSELEFT", Input::MouseLeft }, { "MOUSEMIDDLE", Input::MouseMiddle }, @@ -154,6 +320,7 @@ void inputBindingInit(){ printf("[inputBindingInit] Initializing Input binding\n"); VALUE module = rb_define_module("Input"); + // mkxp's input _rb_define_module_function(module, "update", inputUpdate); _rb_define_module_function(module, "press?", inputPress); _rb_define_module_function(module, "trigger?", inputTrigger); @@ -161,6 +328,30 @@ void inputBindingInit(){ _rb_define_module_function(module, "dir4", inputDir4); _rb_define_module_function(module, "dir8", inputDir8); + // keyboard keys + _rb_define_module_function(module, "key_name", getKeyName); + _rb_define_module_function(module, "key_press?", keyPress); + _rb_define_module_function(module, "pressed_key", getPressedKey); + _rb_define_module_function(module, "key_from_name", getKeyFromName); + rb_const_set(module, rb_intern("KEYS_COUNT"), SDL_Scancode::SDL_SCANCODE_COUNT - 1); + + // gamepad buttons + _rb_define_module_function(module, "c_button_name", getGamepadButtonName); + _rb_define_module_function(module, "c_button_press?", gamepadButtonPress); + _rb_define_module_function(module, "pressed_c_button", getPressedGamepadButton); + _rb_define_module_function(module, "c_button_from_name", getGamepadButtonFromName); + rb_const_set(module, rb_intern("GAMEPAD_BUTTONS_COUNT"), SDL_GamepadButton::SDL_GAMEPAD_BUTTON_COUNT - 1); + + // gamepad axes + _rb_define_module_function(module, "c_axis_name", getGamepadAxisName); + _rb_define_module_function(module, "c_axis_pressure", getGamepadAxisPressure); + _rb_define_module_function(module, "active_c_axis", getActiveGamepadAxis); + _rb_define_module_function(module, "c_axis_from_name", getGamepadAxisFromName); + rb_const_set(module, rb_intern("GAMEPAD_AXIS_COUNT"), SDL_GamepadAxis::SDL_GAMEPAD_AXIS_COUNT - 1); + + rb_define_module_function(module, "set_binding", RUBY_METHOD_FUNC(setBinding), 2); + + // mouse _rb_define_module_function(module, "mouse_x", inputMouseX); _rb_define_module_function(module, "mouse_y", inputMouseY); diff --git a/binding-mri/keybindings-binding.cpp b/binding-mri/keybindings-binding.cpp new file mode 100644 index 0000000..ffded2b --- /dev/null +++ b/binding-mri/keybindings-binding.cpp @@ -0,0 +1,258 @@ +#include "input.h" +#include "sharedstate.h" +#include "binding-util.h" + +#include "keybindings-binding.h" + +void sourceDesc_free(void* ptr) +{ + SourceDesc* kb = (SourceDesc*)ptr; + delete kb; +} + +const rb_data_type_t sourceDesc_type = { "SourceDesc", {0, sourceDesc_free, 0}, 0, 0, RUBY_TYPED_FREE_IMMEDIATELY }; + +static VALUE sourceDesc_alloc(VALUE klass) +{ + SourceDesc* ptr = ALLOC(SourceDesc); + + return TypedData_Wrap_Struct(klass, &sourceDesc_type, ptr); +} + +// fabrics +static VALUE rb_source_key(VALUE klass, VALUE scan) +{ + SourceDesc* s = new SourceDesc(); + + s->type = Key; + s->d.scan = static_cast(NUM2INT(scan)); + + return TypedData_Wrap_Struct(klass, &sourceDesc_type, s); +} + +static VALUE rb_source_caxis(VALUE klass, VALUE axis, VALUE dir) +{ + SourceDesc* s = new SourceDesc(); + + s->type = CAxis; + s->d.ja.axis = NUM2INT(axis); + s->d.ja.dir = static_cast(NUM2INT(dir)); + + return TypedData_Wrap_Struct(klass, &sourceDesc_type, s); +} + +static VALUE rb_source_cbutton(VALUE klass, VALUE button) +{ + SourceDesc* s = new SourceDesc(); + + s->type = CButton; + s->d.jb = NUM2INT(button); + + return TypedData_Wrap_Struct(klass, &sourceDesc_type, s); +} + +static VALUE rb_source_jaxis(VALUE klass, VALUE axis, VALUE dir) +{ + SourceDesc* s = new SourceDesc(); + + s->type = JAxis; + s->d.ja.axis = NUM2INT(axis); + s->d.ja.dir = static_cast(NUM2INT(dir)); + + return TypedData_Wrap_Struct(klass, &sourceDesc_type, s); +} + +static VALUE rb_source_jhat(VALUE klass, VALUE hat, VALUE pos) +{ + SourceDesc* s = new SourceDesc(); + + s->type = JHat; + s->d.jh.hat = NUM2INT(hat); + s->d.jh.pos = NUM2INT(pos); + + return TypedData_Wrap_Struct(klass, &sourceDesc_type, s); +} + +static VALUE rb_source_jbutton(VALUE klass, VALUE button) +{ + SourceDesc* s = new SourceDesc(); + + s->type = JButton; + s->d.jb = NUM2INT(button); + + return TypedData_Wrap_Struct(klass, &sourceDesc_type, s); +} + +// getters +#define SOURCE_DESC \ + SourceDesc* src; \ + TypedData_Get_Struct(self, SourceDesc, &sourceDesc_type, src); + +#define TYPE_IS src->type == SourceType + +static VALUE rb_source_type(VALUE self) +{ + SOURCE_DESC + return INT2NUM(src->type); +} + +static VALUE rb_source_scancode(VALUE self) +{ + SOURCE_DESC + if (TYPE_IS::Key) + return INT2NUM(src->d.scan); + return Qnil; +} + +static VALUE rb_source_button(VALUE self) +{ + SOURCE_DESC + if (TYPE_IS::CButton || TYPE_IS::JButton) + return INT2NUM(src->d.jb); + return Qnil; +} + +static VALUE rb_source_axis(VALUE self) +{ + SOURCE_DESC + if (TYPE_IS::CAxis || TYPE_IS::JAxis) + return INT2NUM(src->d.ja.axis); + return Qnil; +} + +static VALUE rb_source_dir(VALUE self) +{ + SOURCE_DESC + if (TYPE_IS::CAxis || TYPE_IS::JAxis) + return INT2NUM(src->d.ja.dir); + return Qnil; +} + +static VALUE rb_source_hat(VALUE self) +{ + SOURCE_DESC + if (TYPE_IS::JHat) + return INT2NUM(src->d.jh.hat); + return Qnil; +} + +static VALUE rb_source_pos(VALUE self) +{ + SOURCE_DESC + if (TYPE_IS::JHat) + return INT2NUM(src->d.jh.pos); + return Qnil; +} + +static VALUE rb_source_marshal_dump(VALUE self) +{ + SourceDesc* src; + TypedData_Get_Struct(self, SourceDesc, &sourceDesc_type, src); + + VALUE arr = rb_ary_new(); + + rb_ary_push(arr, INT2NUM(src->type)); + + switch (src->type) + { + case SourceType::Key: + rb_ary_push(arr, INT2NUM(src->d.scan)); + break; + + case SourceType::CButton: + case SourceType::JButton: + rb_ary_push(arr, INT2NUM(src->d.jb)); + break; + + case SourceType::CAxis: + case SourceType::JAxis: + rb_ary_push(arr, INT2NUM(src->d.ja.axis)); + rb_ary_push(arr, INT2NUM(src->d.ja.dir)); + break; + + case SourceType::JHat: + rb_ary_push(arr, INT2NUM(src->d.jh.hat)); + rb_ary_push(arr, INT2NUM(src->d.jh.pos)); + break; + + default: + break; + } + + return arr; +} + +static VALUE rb_source_marshal_load(VALUE self, VALUE data) +{ + SourceDesc* src; + TypedData_Get_Struct(self, SourceDesc, &sourceDesc_type, src); + + Check_Type(data, T_ARRAY); + + VALUE type = rb_ary_entry(data, 0); + src->type = static_cast(NUM2INT(type)); + + switch (src->type) + { + case SourceType::Key: + src->d.scan = static_cast(NUM2INT(rb_ary_entry(data, 1))); + break; + + case SourceType::CButton: + case SourceType::JButton: + src->d.jb = NUM2INT(rb_ary_entry(data, 1)); + break; + + case SourceType::CAxis: + case SourceType::JAxis: + src->d.ja.axis = NUM2INT(rb_ary_entry(data, 1)); + src->d.ja.dir = static_cast(NUM2INT(rb_ary_entry(data, 2))); + break; + + case SourceType::JHat: + src->d.jh.hat = NUM2INT(rb_ary_entry(data, 1)); + src->d.jh.pos = NUM2INT(rb_ary_entry(data, 2)); + break; + + default: + break; + } + + return self; +} + +void keybindingsBindingInit(){ + VALUE klass = rb_define_class("KeyBind", rb_cObject); + rb_define_alloc_func(klass, sourceDesc_alloc); + + rb_define_singleton_method(klass, "key", RUBY_METHOD_FUNC(rb_source_key), 1); + rb_define_singleton_method(klass, "caxis", RUBY_METHOD_FUNC(rb_source_caxis), 2); + rb_define_singleton_method(klass, "cbutton", RUBY_METHOD_FUNC(rb_source_cbutton), 1); + rb_define_singleton_method(klass, "jaxis", RUBY_METHOD_FUNC(rb_source_jaxis), 2); + rb_define_singleton_method(klass, "jhat", RUBY_METHOD_FUNC(rb_source_jhat), 2); + rb_define_singleton_method(klass, "jbutton", RUBY_METHOD_FUNC(rb_source_jbutton), 1); + + rb_define_method(klass, "type", RUBY_METHOD_FUNC(rb_source_type), 0); + rb_define_method(klass, "scancode", RUBY_METHOD_FUNC(rb_source_scancode), 0); + rb_define_method(klass, "button", RUBY_METHOD_FUNC(rb_source_button), 0); + rb_define_method(klass, "axis", RUBY_METHOD_FUNC(rb_source_axis), 0); + rb_define_method(klass, "dir", RUBY_METHOD_FUNC(rb_source_dir), 0); + rb_define_method(klass, "hat", RUBY_METHOD_FUNC(rb_source_hat), 0); + rb_define_method(klass, "pos", RUBY_METHOD_FUNC(rb_source_pos), 0); + + rb_define_method(klass, "marshal_dump", RUBY_METHOD_FUNC(rb_source_marshal_dump), 0); + rb_define_method(klass, "marshal_load", RUBY_METHOD_FUNC(rb_source_marshal_load), 1); + + rb_const_set(klass, rb_intern("Negative"), INT2FIX(0)); + rb_const_set(klass, rb_intern("Positive"), INT2FIX(1)); + + VALUE module = rb_define_module_under(klass, "Type"); + + rb_const_set(module, rb_intern("Invalid"), INT2FIX(SourceType::Invalid)); + rb_const_set(module, rb_intern("Key"), INT2FIX(SourceType::Key)); + rb_const_set(module, rb_intern("CButton"), INT2FIX(SourceType::CButton)); + rb_const_set(module, rb_intern("CAxis"), INT2FIX(SourceType::CAxis)); + rb_const_set(module, rb_intern("JButton"), INT2FIX(SourceType::JButton)); + rb_const_set(module, rb_intern("JAxis"), INT2FIX(SourceType::JAxis)); + rb_const_set(module, rb_intern("JHat"), INT2FIX(SourceType::JHat)); +} \ No newline at end of file diff --git a/binding-mri/keybindings-binding.h b/binding-mri/keybindings-binding.h new file mode 100644 index 0000000..6892969 --- /dev/null +++ b/binding-mri/keybindings-binding.h @@ -0,0 +1,8 @@ +#pragma once + +#include "keybindings.h" + +#include + +extern void sourceDesc_free(void* ptr); +extern const rb_data_type_t sourceDesc_type; \ No newline at end of file diff --git a/scripts/CMakeLists.txt b/scripts/CMakeLists.txt index 1042454..c6aae62 100644 --- a/scripts/CMakeLists.txt +++ b/scripts/CMakeLists.txt @@ -81,7 +81,8 @@ set(scripts i18n_Japanese.rb i18n_Language.rb Window_TPtL.rb - Settings.rb) + Settings.rb + Input.rb) find_program(RUBY_EXE ruby DOC "Location of the Ruby executable") diff --git a/scripts/Data_Settings.rb b/scripts/Data_Settings.rb index 929d456..9149fff 100644 --- a/scripts/Data_Settings.rb +++ b/scripts/Data_Settings.rb @@ -3,41 +3,105 @@ module Settings def reset! @data = { # Audio - :bgm_volume => 100, - :sfx_volume => 100, + :bgm_volume => 100, + :sfx_volume => 100, # Video - :fullscreen => false, - :colorblind => false, - :frameskip => true, - :twm_shader => true, + :fullscreen => false, + :colorblind => false, + :frameskip => true, + :twm_shader => true, # UI - :in_game_timer => false, - :language => 0, - :fasttravel_ui => 0, - :debug_text_scene_title => true, + :in_game_timer => false, + :language => 0, + :fasttravel_ui => 0, + :debug_text_scene_title => true, # Gameplay - :movement => 0, - :skip_text => false, - :en_purple_messagebox => true, - :enforce_april_fools => false, - :true_memory_mode => false, - :pre_solstice_update_content => false, - :dejavu_mode => false, - :demo => false, - :oneshot_mode => false, - + :movement => 0, + :skip_text => false, + :en_purple_messagebox => true, + :enforce_april_fools => false, + :true_memory_mode => false, + :pre_solstice_update_content => false, + :dejavu_mode => false, + :demo => false, + :oneshot_mode => false, + # Advanced - #controls - :gamepad_led => true, - + #controls + :gamepad_led => true, + :gamepad_deadzone => 5, + :controls_walk_down => [ + KeyBind.key(Input::key_from_name("Down")), + KeyBind.caxis(Input::c_axis_from_name("LeftY"), KeyBind::Positive), + KeyBind.cbutton(Input::c_button_from_name("DpDown")) + ], + :controls_walk_left => [ + KeyBind.key(Input::key_from_name("Left")), + KeyBind.caxis(Input::c_axis_from_name("LeftX"), KeyBind::Negative), + KeyBind.cbutton(Input::c_button_from_name("DpLeft")) + ], + :controls_walk_right => [ + KeyBind.key(Input::key_from_name("Right")), + KeyBind.caxis(Input::c_axis_from_name("LeftX"), KeyBind::Positive), + KeyBind.cbutton(Input::c_button_from_name("DpRight")) + ], + :controls_walk_up => [ + KeyBind.key(Input::key_from_name("Up")), + KeyBind.caxis(Input::c_axis_from_name("LeftY"), KeyBind::Negative), + KeyBind.cbutton(Input::c_button_from_name("DpUp")) + ], + :controls_run => [ + KeyBind.key(Input::key_from_name("Left Shift")), + KeyBind.caxis(Input::c_axis_from_name("righttrigger"), KeyBind::Positive), + KeyBind.cbutton(Input::c_button_from_name("x")) + ], + # ----------------------------------------------------------------------------------------------------------- + :controls_action => [ + KeyBind.key(Input::key_from_name("Z")), + KeyBind.key(Input::key_from_name("Space")), + KeyBind.cbutton(Input::c_button_from_name("a")), + ], + :controls_deactivate => [ + KeyBind.key(Input::key_from_name("Left Shift")), + KeyBind.cbutton(Input::c_button_from_name("back")), + KeyBind.caxis(Input::c_axis_from_name("lefttrigger"), KeyBind::Positive), + ], + :controls_cancel => [ + KeyBind.key(Input::key_from_name("X")), + KeyBind.key(Input::key_from_name("Escape")), + KeyBind.cbutton(Input::c_button_from_name("b")), + ], + :controls_menu => [ + KeyBind.key(Input::key_from_name("A")), + KeyBind.key(Input::key_from_name("Return")), + KeyBind.cbutton(Input::c_button_from_name("start")), + ], + :controls_items => [ + KeyBind.key(Input::key_from_name("S")), + KeyBind.cbutton(Input::c_button_from_name("y")), + ], + :controls_nav_left => [ + KeyBind.key(Input::key_from_name("Q")), + KeyBind.cbutton(Input::c_button_from_name("leftshoulder")), + ], + :controls_nav_right => [ + KeyBind.key(Input::key_from_name("W")), + KeyBind.cbutton(Input::c_button_from_name("rightshoulder")), + ], + # ----------------------------------------------------------------------------------------------------------- + :controls_debug => [ + KeyBind.key(Input::key_from_name("Left Ctrl")), + KeyBind.cbutton(Input::c_button_from_name("rightstick")), + ], + # Debug - :debug => false, - :debug_character => false, - :debug_text => false, + :debug => false, + :debug_character => false, + :debug_text => false, } end end @@ -48,14 +112,14 @@ class Window_Settings DATA = { tr("Audio") => [ { - :type => :int, + :type => :slider, :name => tr('BGM Volume'), :parameter => :bgm_volume, :min => 0, :max => 100 }, { - :type => :int, + :type => :slider, :name => tr('SFX Volume'), :parameter => :sfx_volume, :min => 0, @@ -109,12 +173,6 @@ class Window_Settings }, ], tr("Gameplay") => [ - { - :type => :enum, - :name => tr('Default movement'), - :parameter => :movement, - :values => [tr("Walk"), tr("Run")] - }, { :type => :bool, :name => tr('Skip Text (R)'), @@ -167,13 +225,101 @@ class Window_Settings :name => tr('Control LED lighting on gamepads'), :parameter => :gamepad_led }, + #{ + # :type => :slider, + # :name => tr("Gamepad deadzone"), + # :parameter => :gamepad_deadzone, + # :min => 0, + # :max => 10 + #}, + { :type => :sep, :name => tr("Walk") }, + { + :type => :key, + :name => tr("Walk Down"), + :parameter => :controls_walk_down, + :bind => Input::DOWN + }, + { + :type => :key, + :name => tr("Walk Left"), + :parameter => :controls_walk_left, + :bind => Input::LEFT + }, + { + :type => :key, + :name => tr("Walk Right"), + :parameter => :controls_walk_right, + :bind => Input::RIGHT + }, + { + :type => :key, + :name => tr("Walk Up"), + :parameter => :controls_walk_up, + :bind => Input::UP + }, + { + :type => :key, + :name => tr("Run"), + :parameter => :controls_run, + :bind => Input::RUN + }, + { :type => :sep, :name => tr("Actions") }, + { + :type => :key, + :name => tr("Action"), + :parameter => :controls_action, + :bind => Input::ACTION + }, + { + :type => :key, + :name => tr("Deactivate"), + :parameter => :controls_deactivate, + :bind => Input::DEACTIVATE + }, + { + :type => :key, + :name => tr("Cancel"), + :parameter => :controls_cancel, + :bind => Input::CANCEL + }, + { + :type => :key, + :name => tr("Menu"), + :parameter => :controls_menu, + :bind => Input::MENU + }, + { + :type => :key, + :name => tr("Items"), + :parameter => :controls_items, + :bind => Input::ITEMS + }, + { + :type => :key, + :name => tr("Nav Left"), + :parameter => :controls_nav_left, + :bind => Input::L + }, + { + :type => :key, + :name => tr("Nav Right"), + :parameter => :controls_nav_right, + :bind => Input::R + }, + { :type => :sep, :name => tr("Other") }, + { + :type => :key, + :name => tr("Debug"), + :parameter => :controls_debug, + :bind => Input::DEBUGACTION + }, ], tr("Advanced") => [ - { - :type => :bool, - :name => tr('useless option:3'), - :parameter => :erfsdgvfdgfgf - }, + { + :type => :bool, + :name => tr('useless option:3'), + :default => false + }, ], tr("Debug") => [ { diff --git a/scripts/Data_Settings_Classes.rb b/scripts/Data_Settings_Classes.rb index 07741c2..39f359c 100644 --- a/scripts/Data_Settings_Classes.rb +++ b/scripts/Data_Settings_Classes.rb @@ -1,8 +1,12 @@ +# Logic of settings UI class Window_Settings SCREENS_PANELS_MARGIN = 32 PARAMETER_WIDTH = (Graphics.width - 640) / 2 + 512 PARAMETER_HEIGHT = 32 - PARAMETER_VALUE_WIDTH = 200 + PARAMETER_VALUE_WIDTH = PARAMETER_WIDTH / 2 + PARAMETER_KEY_WIDTH = PARAMETER_WIDTH / 5 + + PARAMETER_CHANGE_AUDIO = "Audio/SE/text_robot.wav" class SettingsContent attr_reader :x @@ -17,6 +21,8 @@ class Window_Settings @index = 0 @opacity = 255 @offset = offset_y + @waiting_for_key = false + @wait_timer = 0 @visible_x = 0 @visible_y = offset_y @@ -38,6 +44,22 @@ class Window_Settings @screen_panel_selection_sprite.y = SCREENS_PANELS_MARGIN @screen_panel_selection_sprite.x = Graphics.width / 2 + @switch_panels_hint_left = Sprite.new(@viewport) + @switch_panels_hint_left.bitmap = Bitmap.new(PARAMETER_WIDTH / 2 - SCREENS_PANELS_MARGIN, @offset / 2) + @switch_panels_hint_left.bitmap.font.size = 20 + @switch_panels_hint_left.x = @x + SCREENS_PANELS_MARGIN + @switch_panels_hint_left.zoom_x = @switch_panels_hint_left.zoom_y = 2 + @switch_panels_hint_left.opacity = 127 + + @switch_panels_hint_right = Sprite.new(@viewport) + @switch_panels_hint_right.bitmap = Bitmap.new(PARAMETER_WIDTH / 2 - SCREENS_PANELS_MARGIN, @offset / 2) + @switch_panels_hint_right.bitmap.font.size = 20 + @switch_panels_hint_right.x = @x + SCREENS_PANELS_MARGIN + @switch_panels_hint_right.zoom_x = @switch_panels_hint_right.zoom_y = 2 + @switch_panels_hint_right.opacity = 127 + + redraw_panels_hints + @parameters = {} @screen_panels = [] @next_screen_panel_offset = 0 @@ -126,6 +148,13 @@ class Window_Settings @screen_panel_selection_sprite.zoom_x = @screen_panels[@screen].width * 0.3 + @screen_panel_selection_sprite.zoom_x * 0.7 @screen_panel_selection_sprite.x = (Graphics.width / 2 - @screen_panels[@screen].width * 0.5) * 0.3 + @screen_panel_selection_sprite.x * 0.7 + + @switch_panels_hint_left.x = @switch_panels_hint_left.x * 0.8 + (@x + SCREENS_PANELS_MARGIN) * 0.2 + @switch_panels_hint_right.x = @switch_panels_hint_right.x * 0.8 + (@x + SCREENS_PANELS_MARGIN) * 0.2 + + @waiting_for_key2 = @waiting_for_key + + @wait_timer = (@wait_timer + (@waiting_for_key ? 1 : -1)).clamp(0, 3) end def redraw_all @@ -136,6 +165,11 @@ class Window_Settings end end end + + def redraw_panels_hints + @switch_panels_hint_right.bitmap.draw_text(0, 0, @switch_panels_hint_right.bitmap.width, @switch_panels_hint_right.bitmap.height, "W→", 2) + @switch_panels_hint_left.bitmap.draw_text(0, 0, @switch_panels_hint_left.bitmap.width, @switch_panels_hint_left.bitmap.height, "←Q") + end def update_pos() center = Graphics.height / 2 - PARAMETER_HEIGHT * 0.5 @@ -144,35 +178,55 @@ class Window_Settings # Navigation def screen_left() + previous = @index + @parameters.values[@screen]&.[](@index)&.deselect @screen = (@screen - 1) % @parameters.length @index = @index.clamp(0, @parameters.values[@screen].length - 1) + @switch_panels_hint_left.x -= SCREENS_PANELS_MARGIN + @parameters.values[@screen]&.[](@index)&.select(previous) update_pos end def screen_right() + previous = @index + @parameters.values[@screen]&.[](@index)&.deselect @screen = (@screen + 1) % @parameters.length @index = @index.clamp(0, @parameters.values[@screen].length - 1) + @switch_panels_hint_right.x += SCREENS_PANELS_MARGIN + @parameters.values[@screen]&.[](@index)&.select(previous) update_pos end def parameter_up() + previous = @index + @parameters.values[@screen]&.[](@index)&.deselect offset = 1 if @parameters.values&.[](@screen)&.[](@index - 1)&.class&.const_get(:TYPE) == :sep offset += 1 end @index = (@index - offset) % @parameters.values[@screen].length + @parameters.values[@screen]&.[](@index)&.select(previous) update_pos end def parameter_down() + previous = @index + @parameters.values[@screen]&.[](@index)&.deselect offset = 1 if @parameters.values&.[](@screen)&.[](@index + 1)&.class&.const_get(:TYPE) == :sep offset += 1 end @index = (@index + offset) % @parameters.values[@screen].length + @parameters.values[@screen]&.[](@index)&.select(previous) update_pos end def parameter_select_offset(offset) + previous = @index + @parameters.values[@screen]&.[](@index)&.deselect @index = (@index + offset) % @parameters.values[@screen].length + if @parameters.values&.[](@screen)&.[](@index)&.class&.const_get(:TYPE) == :sep + @index += offset <=> 0 + end + @parameters.values[@screen]&.[](@index)&.select(previous) update_pos end @@ -211,8 +265,16 @@ class Window_Settings @opacity = value @selection_sprite.opacity = value @screen_panel_selection_sprite.opacity = value + @switch_panels_hint_right.opacity = @switch_panels_hint_left.opacity = (value * 127) / 255 redraw_all end + + def waiting_for_key=(value) + @waiting_for_key = value + end + def waiting_for_key + @wait_timer > 0 + end end # ---------------------------------------------------------------------------------------- @@ -281,7 +343,7 @@ class Window_Settings end def update() - @sprite.x = @screen_id * Graphics.width - @settings_content.visible_x + @settings_content.x + @sprite.x = @screen_id * Graphics.width - @settings_content.visible_x + @settings_content.x + 8 @sprite.y = @settings_content.visible_y + @position * PARAMETER_HEIGHT @sprite.opacity = ((1.0 + ((@sprite.y - @settings_content.offset).to_f / 64.0).clamp(-1.0, 0.0)) * @opacity * (@settings_content.opacity.to_f / 255.0) * 255.0).to_i end @@ -293,6 +355,8 @@ class Window_Settings def value_left() end def value_right() end def action() end + def select(previous) end + def deselect() end end # ---------------------------------------------------------------------------------------- @@ -321,6 +385,13 @@ class Window_Settings super(settings_content, screen_id, position, name, parameter, bool_value || false) end + def value=(value) + if (value != @value) + Audio.se_play(PARAMETER_CHANGE_AUDIO, 70, value ? 125 : 75) + end + super(value) + end + def get_display_value return @value ? tr("ON") : tr("OFF") end @@ -339,6 +410,26 @@ class Window_Settings end end + # ---------------------------------------------------------------------------------------- + class SwitchPatameter < BoolParameter + TYPE = :switch + + def initialize(settings_content, screen_id, position, name, parameter, bool_value, switch, invert) + @switch = switch + @invert = invert + + super(settings_content, screen_id, position, name, parameter, bool_value) + end + + def update_parameter + super() + + if @switch + $game_switches[@switch] = invert ? !@value : @value + end + end + end + # ---------------------------------------------------------------------------------------- class IntParameter < BaseParameter TYPE = :int @@ -347,10 +438,17 @@ class Window_Settings attr_reader :min_value def initialize(settings_content, screen_id, position, name, parameter, int_value, min_value, max_value) - super(settings_content, screen_id, position, name, parameter, int_value) - @min_value = min_value @max_value = max_value + + super(settings_content, screen_id, position, name, parameter, int_value) + end + + def value=(value) + if (value != @value) + Audio.se_play(PARAMETER_CHANGE_AUDIO, 70, ((value.to_f + @min_value.to_f) / (@max_value.to_f + @min_value.to_f) * 50.0).to_i + 75) + end + super(value) end def value_left() @@ -363,14 +461,86 @@ class Window_Settings end end + # ---------------------------------------------------------------------------------------- + class SliderParameter < IntParameter + TYPE = :slider + + def initialize(settings_content, screen_id, position, name, parameter, int_value, min_value, max_value) + super(settings_content, screen_id, position, name, parameter, int_value, min_value, max_value) + end + + def get_display_value() + percent = (@value.to_f - @min_value.to_f) / @max_value.to_f + (percent * 100.0).to_i.to_s + "%" + end + + def redraw() + @sprite.bitmap.clear + @sprite.bitmap.font.color = Color.new(255, 255, 255) + + @sprite.bitmap.draw_text(0, 0, @sprite.bitmap.width - PARAMETER_VALUE_WIDTH, @sprite.bitmap.height, @name) + + percent = (@value.to_f - @min_value.to_f) / @max_value.to_f + width = (PARAMETER_VALUE_WIDTH * percent).to_i + @sprite.bitmap.fill_rect(Rect.new(@sprite.bitmap.width - PARAMETER_VALUE_WIDTH, 4, PARAMETER_VALUE_WIDTH, @sprite.bitmap.height - 8), Color.new(255, 255, 255, 64)) + #@sprite.bitmap.fill_rect(Rect.new(@sprite.bitmap.width - PARAMETER_VALUE_WIDTH + 1, 5, PARAMETER_VALUE_WIDTH - 2, @sprite.bitmap.height - 10), Color.new(255, 255, 255, 0)) + @sprite.bitmap.fill_rect(Rect.new(@sprite.bitmap.width - PARAMETER_VALUE_WIDTH, 4, width, @sprite.bitmap.height - 8), Color.new(255, 255, 255, 255)) + + if percent >= 0.5 + @sprite.bitmap.font.color = Color.new(0, 0, 0) + @sprite.bitmap.draw_text(@sprite.bitmap.width - PARAMETER_VALUE_WIDTH, 4, width, @sprite.bitmap.height - 8, get_display_value, 1) + else + @sprite.bitmap.font.color = Color.new(255, 255, 255) + @sprite.bitmap.draw_text(@sprite.bitmap.width - PARAMETER_VALUE_WIDTH + width, 4, PARAMETER_VALUE_WIDTH - width, @sprite.bitmap.height - 8, get_display_value, 1) + end + + if (@settings_content.need_draw_line(@screen_id, @position)) + @sprite.bitmap.fill_rect(Rect.new(0, PARAMETER_HEIGHT - 1, PARAMETER_WIDTH, 2), Color.new(255, 255, 255, 24)) + end + end + end + + # ---------------------------------------------------------------------------------------- + class FloatParameter < BaseParameter + TYPE = :float + + attr_reader :max_value + attr_reader :min_value + attr_reader :step + + def initialize(settings_content, screen_id, position, name, parameter, float_value, step, min_value, max_value) + @step = step + @min_value = min_value + @max_value = max_value + + super(settings_content, screen_id, position, name, parameter, float_value) + end + + def value=(value) + if (value != @value) + Audio.se_play(PARAMETER_CHANGE_AUDIO, 70, ((value + @min_value) / (@max_value + @min_value) * 50.0).to_i + 75) + end + super(value) + end + + def value_left() + self.value = (@value - step).clamp(@min_value, @max_value) + redraw + end + def value_right() + self.value = (@value + step).clamp(@min_value, @max_value) + redraw + end + end + # ---------------------------------------------------------------------------------------- class EnumParameter < IntParameter TYPE = :enum def initialize(settings_content, screen_id, position, name, parameter, int_value, enum_texts) - super(settings_content, screen_id, position, name, parameter, int_value, 0, enum_texts.length - 1) - @texts = enum_texts + + super(settings_content, screen_id, position, name, parameter, int_value, 0, enum_texts.length - 1) end def get_display_value @@ -386,4 +556,159 @@ class Window_Settings redraw end end + + #---------------------------------------------------------------------------------------- + class KeyParameter < BaseParameter + TYPE = :key + + attr_reader :selection + + def initialize(settings_content, screen_id, position, name, parameter, key_binds, input_bind) + @selected = false + @selection = 0 + @key_binds = parameter ? Settings[parameter] : key_binds + @bind = input_bind + @waiting_for_key = false + @accept_action = false + + super(settings_content, screen_id, position, name, parameter, nil) + + apply + end + + def get_display_value(bind_id = 0) + key_bind = @key_binds[bind_id] + + if key_bind == nil + return tr("None") + end + + case key_bind.type + + when KeyBind::Type::Invalid + return tr("Invalid") + + when KeyBind::Type::Key + return tr(Input::key_name(key_bind.scancode)) + + when KeyBind::Type::CButton + return tr(Input::c_button_name(key_bind.button)) + + when KeyBind::Type::CAxis + axis_name = Input::c_axis_name(key_bind.axis) + dir_vert = axis_name.downcase.include?("y") ? true : false + dir_horiz = axis_name.downcase.include?("x") ? true : false + return tr(axis_name + (dir_horiz || dir_vert ? (" " + (dir_vert ? (key_bind.dir == 1 ? "Up" : "Down") : (key_bind.dir == 1 ? "Right" : "Left"))) : "")) + + when KeyBind::Type::JButton + return tr("Joystick Button") + " " + key_bind.button.to_s + + when KeyBind::Type::JAxis + return tr("Joystick Axis") + " " + key_bind.axis.to_s + " " + key_bind.dir == 1 ? "Positive" : "Negative" + + when KeyBind::Type::JHat + return tr("Joystick Hat") + " " + key_bind.hat.to_s + " " + key_bind.pos == 1 ? "Positive" : "Negative" + + end + end + + def redraw() + @sprite.bitmap.clear + + if @selected + @sprite.bitmap.fill_rect(Rect.new(@sprite.bitmap.width - PARAMETER_KEY_WIDTH * (4 - @selection), 0, PARAMETER_KEY_WIDTH, @sprite.bitmap.height), Color.new(255, 255, 255, 48)) + @sprite.bitmap.draw_text(@sprite.bitmap.width - PARAMETER_KEY_WIDTH * (4 - @selection) + 10, 0, 10, @sprite.bitmap.height, "→", 1) + @sprite.bitmap.draw_text(@sprite.bitmap.width - PARAMETER_KEY_WIDTH * (3 - @selection) - 20, 0, 10, @sprite.bitmap.height, "←", 1) + end + + @sprite.bitmap.draw_text(0, 0, @sprite.bitmap.width - PARAMETER_KEY_WIDTH * 4, @sprite.bitmap.height, @name) + for i in 0..3 + if @waiting_for_key && i == selection + @sprite.bitmap.draw_text(@sprite.bitmap.width - PARAMETER_KEY_WIDTH * (4 - i), 0, PARAMETER_KEY_WIDTH, @sprite.bitmap.height, tr("Press a key"), 1) + else + @sprite.bitmap.draw_text(@sprite.bitmap.width - PARAMETER_KEY_WIDTH * (4 - i), 0, PARAMETER_KEY_WIDTH, @sprite.bitmap.height, get_display_value(i), 1) + end + @sprite.bitmap.fill_rect(Rect.new(@sprite.bitmap.width - PARAMETER_KEY_WIDTH * (4 - i) - 1, 1, 2, @sprite.bitmap.height - 2), Color.new(255, 255, 255, 32)) + end + + if (@settings_content.need_draw_line(@screen_id, @position)) + @sprite.bitmap.fill_rect(Rect.new(0, PARAMETER_HEIGHT - 1, PARAMETER_WIDTH, 2), Color.new(255, 255, 255, 24)) + end + end + + def value_left() + if !@waiting_for_key + @selection = (@selection - 1) % 4 + $game_system.se_play($data_system.cursor_se) + redraw + end + end + def value_right() + if !@waiting_for_key + @selection = (@selection + 1) % 4 + $game_system.se_play($data_system.cursor_se) + redraw + end + end + + def action() + @accept_action = false + @waiting_for_key = true + @settings_content.waiting_for_key = true + redraw + end + + def apply() + if @bind + Input::set_binding(@key_binds, @bind) + end + end + + def update() + super() + + if @waiting_for_key && @settings_content.waiting_for_key + key = Input::pressed_key + c_button = Input::pressed_c_button + c_axis = Input::active_c_axis + + if !Input.press?(Input::ACTION) + @accept_action = true + end + + if key && (!Input.press?(Input::ACTION) || @accept_action) + if key != Input::key_from_name("Backspace") + Settings[@parameter][@selection] = KeyBind.key(key) + end + @waiting_for_key = @settings_content.waiting_for_key = false + apply + redraw + elsif c_button + Settings[@parameter][@selection] = KeyBind.cbutton(c_button) + @waiting_for_key = @settings_content.waiting_for_key = false + apply + redraw + elsif c_axis + Settings[@parameter][@selection] = KeyBind.caxis(c_axis, Input::c_axis_pressure(c_axis) > 0 ? KeyBind::Positive : KeyBind::Negative) + @waiting_for_key = @settings_content.waiting_for_key = false + apply + redraw + end + end + end + + def select(previous) + prev = @settings_content.get_parameter_by_sceen_id(@settings_content.screen, previous) + if prev&.respond_to?(:selection) + @selection = prev.selection + end + + @selected = true + redraw + end + def deselect + @selected = false + redraw + end + end end \ No newline at end of file diff --git a/scripts/Input.rb b/scripts/Input.rb new file mode 100644 index 0000000..5183933 --- /dev/null +++ b/scripts/Input.rb @@ -0,0 +1,11 @@ +# Modifications for input-binding.cpp +module Input + class << self + alias_method(:c_axis_pressure_int, :c_axis_pressure) + + def c_axis_pressure(axis) + normalized = c_axis_pressure_int(axis).to_f / 32767.0 + return normalized < Settings[:gamepad_deadzone] / 10.0 ? 0.0 : normalized + end + end +end \ No newline at end of file diff --git a/scripts/Window_Settings.rb b/scripts/Window_Settings.rb index a8effbf..f34aa20 100644 --- a/scripts/Window_Settings.rb +++ b/scripts/Window_Settings.rb @@ -11,7 +11,7 @@ class Window_Settings @viewport.z = 9998 @bg = Sprite.new(@viewport) @bg.bitmap = Bitmap.new(Graphics.width, Graphics.height) - @bg.bitmap.fill_rect(0, 0, Graphics.width, Graphics.height, Color.new(255, 255, 255, 128)) + @bg.bitmap.fill_rect(0, 0, Graphics.width, Graphics.height, Color.new(255, 255, 255, 196)) @bg.blend_type = 2 @title = Sprite.new(@viewport) @title.bitmap = Bitmap.new(320, TITLE_MARGIN) @@ -37,15 +37,27 @@ class Window_Settings when :bool @content.add_parameter(screen_title, BoolParameter.new(@content, screen_index, parameter_index, parameter_info[:name], parameter_info[:parameter], parameter_info[:default])) + when :switch + @content.add_parameter(screen_title, BoolParameter.new(@content, screen_index, parameter_index, + parameter_info[:name], parameter_info[:parameter], parameter_info[:default], parameter_info[:switch], parameter_info[:invert])) when :int @content.add_parameter(screen_title, IntParameter.new(@content, screen_index, parameter_index, parameter_info[:name], parameter_info[:parameter], parameter_info[:default], parameter_info[:min], parameter_info[:max])) + when :slider + @content.add_parameter(screen_title, SliderParameter.new(@content, screen_index, parameter_index, + parameter_info[:name], parameter_info[:parameter], parameter_info[:default], parameter_info[:min], parameter_info[:max])) + when :float + @content.add_parameter(screen_title, FloatParameter.new(@content, screen_index, parameter_index, + parameter_info[:name], parameter_info[:parameter], parameter_info[:default], parameter_info[:step], parameter_info[:min], parameter_info[:max])) when :enum @content.add_parameter(screen_title, EnumParameter.new(@content, screen_index, parameter_index, parameter_info[:name], parameter_info[:parameter], 0, parameter_info[:values])) when :sep @content.add_parameter(screen_title, Separator.new(@content, screen_index, parameter_index, parameter_info[:name])) + when :key + @content.add_parameter(screen_title, KeyParameter.new(@content, screen_index, parameter_index, + parameter_info[:name], parameter_info[:parameter], parameter_info[:key_binds], parameter_info[:bind])) end end end @@ -109,11 +121,18 @@ class Window_Settings end return if !self.visible + return if @content.waiting_for_key # navigation if Input.wheel_y != 0 - @content.parameter_select_offset(-Input.wheel_y.round) - $game_system.se_play($data_system.cursor_se) + if (Input::key_press?(Input::key_from_name("Left Shift"))) + for i in 0...Input.wheel_y.round.abs + Input.wheel_y.round > 0 ? @content.parameter_right : @content.parameter_left + end + else + @content.parameter_select_offset(-Input.wheel_y.round) + $game_system.se_play($data_system.cursor_se) + end end if (Input.trigger?(Input::L)) @@ -174,15 +193,6 @@ class Window_Settings if (Input.trigger?(Input::ACTION)) current_parameter&.action end - current_val = current_parameter&.value - if current_val != old_val - current_type = current_parameter&.class&.const_get(:TYPE) - if current_type == :int || current_type == :enum - Audio.se_play("Audio/SE/text_robot.wav", 70, ((current_val.to_f + current_parameter.min_value.to_f) / (current_parameter.max_value.to_f + current_parameter.min_value.to_f) * 50.0).to_i + 75) - elsif current_type == :bool - Audio.se_play("Audio/SE/text_robot.wav", 70, current_val ? 125 : 75) - end - end # menu closing if Input.trigger?(Input::CANCEL) diff --git a/scripts/_scripts.txt b/scripts/_scripts.txt index d09352a..6285ef8 100644 --- a/scripts/_scripts.txt +++ b/scripts/_scripts.txt @@ -28,6 +28,7 @@ Game_FastTravel # yes. Settings +Input Sprite_Character Sprite_Picture diff --git a/src/input.cpp b/src/input.cpp index 7f5cab2..0a01349 100644 --- a/src/input.cpp +++ b/src/input.cpp @@ -29,7 +29,6 @@ #include #include -#include #include #include @@ -384,6 +383,148 @@ struct InputPrivate { bindings.push_back(&bind[i]); } + void setBindingDescs(const std::vector &descs, const Input::ButtonCode &target){ + // cleaning + kbBindings.erase( + std::remove_if( + kbBindings.begin(), + kbBindings.end(), + [target](const KbBinding& b) + { return b.target == target; } + ), + kbBindings.end() + ); + gcABindings.erase( + std::remove_if( + gcABindings.begin(), + gcABindings.end(), + [target](const GcAxisBinding& b) + { return b.target == target; } + ), + gcABindings.end() + ); + gcBBindings.erase( + std::remove_if( + gcBBindings.begin(), + gcBBindings.end(), + [target](const GcButtonBinding& b) + { return b.target == target; } + ), + gcBBindings.end() + ); + jsABindings.erase( + std::remove_if( + jsABindings.begin(), + jsABindings.end(), + [target](const JsAxisBinding& b) + { return b.target == target; } + ), + jsABindings.end() + ); + jsHBindings.erase( + std::remove_if( + jsHBindings.begin(), + jsHBindings.end(), + [target](const JsHatBinding& b) + { return b.target == target; } + ), + jsHBindings.end() + ); + jsBBindings.erase( + std::remove_if( + jsBBindings.begin(), + jsBBindings.end(), + [target](const JsButtonBinding& b) + { return b.target == target; } + ), + jsBBindings.end() + ); + + + for (size_t i = 0; i < descs.size(); ++i){ + const SourceDesc &src = descs[i]; + + if (target == Input::None) + continue; + + switch (src.type){ + case Invalid : + break; + case Key : + { + KbBinding bind; + bind.source = src.d.scan; + bind.target = target; + kbBindings.push_back(bind); + + break; + } + case CAxis : + { + GcAxisBinding bind; + bind.source = src.d.ja.axis; + bind.dir = src.d.ja.dir; + bind.target = target; + gcABindings.push_back(bind); + + break; + } + case CButton : + { + GcButtonBinding bind; + bind.source = src.d.jb; + bind.target = target; + gcBBindings.push_back(bind); + + break; + } + case JAxis : + { + JsAxisBinding bind; + bind.source = src.d.ja.axis; + bind.dir = src.d.ja.dir; + bind.target = target; + jsABindings.push_back(bind); + + break; + } + case JHat : + { + JsHatBinding bind; + bind.source = src.d.jh.hat; + bind.pos = src.d.jh.pos; + bind.target = target; + jsHBindings.push_back(bind); + + break; + } + case JButton : + { + JsButtonBinding bind; + bind.source = src.d.jb; + bind.target = target; + jsBBindings.push_back(bind); + + break; + } + default : + assert(!"unreachable"); + } + } + + bindings.clear(); + + appendBindings(kbStatBindings); + appendBindings(msBindings); + + appendBindings(kbBindings); + appendBindings(gcABindings); + appendBindings(gcBBindings); + appendBindings(jsABindings); + appendBindings(jsHBindings); + appendBindings(jsBBindings); + } + void applyBindingDesc(const BDescVec &d){ kbBindings.clear(); gcABindings.clear(); @@ -692,6 +833,10 @@ int Input::mouseY(){ return (EventThread::mouseState.y - rtData.screenOffset.y) * rtData.sizeResoRatio.y; } +void Input::setBinding(std::vector descs, Input::ButtonCode target){ + p->setBindingDescs(descs, target); +} + // wheel support :3 float Input::wheelX() { return p->mouseWheelState.wheelX; } float Input::wheelY() { return p->mouseWheelState.wheelY; } diff --git a/src/input.h b/src/input.h index c2984ef..ad3a675 100644 --- a/src/input.h +++ b/src/input.h @@ -19,11 +19,14 @@ ** along with mkxp. If not, see . */ +#include + #ifndef INPUT_H #define INPUT_H struct InputPrivate; struct RGSSThreadData; +struct SourceDesc; class Input{ public: @@ -62,6 +65,8 @@ public: int mouseX(); int mouseY(); + void setBinding(std::vector descs, Input::ButtonCode target); + // more non-standard extensions float wheelX(); float wheelY(); diff --git a/src/keybindings.cpp b/src/keybindings.cpp index d9a0559..a220f1f 100644 --- a/src/keybindings.cpp +++ b/src/keybindings.cpp @@ -100,16 +100,16 @@ static const KbBindingData defaultKbBindings[] ={ static elementsN(defaultKbBindings); static const GcBindingData defaultGcBindings[] ={ - { SDL_GAMEPAD_BUTTON_DPAD_LEFT, Input::Left }, - { SDL_GAMEPAD_BUTTON_DPAD_RIGHT, Input::Right }, - { SDL_GAMEPAD_BUTTON_DPAD_UP, Input::Up }, - { SDL_GAMEPAD_BUTTON_DPAD_DOWN, Input::Down }, - { SDL_GAMEPAD_BUTTON_SOUTH, Input::Action }, - { SDL_GAMEPAD_BUTTON_EAST, Input::Cancel }, - { SDL_GAMEPAD_BUTTON_WEST, Input::Run }, - { SDL_GAMEPAD_BUTTON_NORTH, Input::Items }, - { SDL_GAMEPAD_BUTTON_START, Input::Menu }, - { SDL_GAMEPAD_BUTTON_BACK, Input::Deactivate }, + { SDL_GAMEPAD_BUTTON_DPAD_LEFT, Input::Left }, + { SDL_GAMEPAD_BUTTON_DPAD_RIGHT, Input::Right }, + { SDL_GAMEPAD_BUTTON_DPAD_UP, Input::Up }, + { SDL_GAMEPAD_BUTTON_DPAD_DOWN, Input::Down }, + { SDL_GAMEPAD_BUTTON_SOUTH, Input::Action }, + { SDL_GAMEPAD_BUTTON_EAST, Input::Cancel }, + { SDL_GAMEPAD_BUTTON_WEST, Input::Run }, + { SDL_GAMEPAD_BUTTON_NORTH, Input::Items }, + { SDL_GAMEPAD_BUTTON_START, Input::Menu }, + { SDL_GAMEPAD_BUTTON_BACK, Input::Deactivate }, { SDL_GAMEPAD_BUTTON_LEFT_SHOULDER, Input::L }, { SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER, Input::R }, };