diff --git a/lua-engine.cpp b/lua-engine.cpp index f089e1ef..ca59a485 100644 --- a/lua-engine.cpp +++ b/lua-engine.cpp @@ -9,6 +9,7 @@ #include "snapshot.h" #include "pixform.h" #include "screenshot.h" +#include "controls.h" #include "lua-engine.h" #include #include @@ -2263,6 +2264,163 @@ s_buttonDescs [] = {8, 15, "B"}, }; +// string joypad.gettype(int port = 1) +// +// Returns the type of controller at the given physical port index 1 or 2 +// (port is the same as "which" for other input functions, unless there's a multitap) +// possible return values are "joypad", "mouse", "superscope", "justifier", "justifiers", "multitap", "none" +DEFINE_LUA_FUNCTION(joy_gettype, "[port=1]") +{ + int port = 0; + if (lua_type(L, 1) == LUA_TNUMBER) + { + port = luaL_checkinteger(L, 1) - 1; + } + + controllers controller; + int8 ids[4]; + S9xGetController(port, &controller, &ids[0], &ids[1], &ids[2], &ids[3]); + + switch(controller) + { + default: + case CTL_NONE: lua_pushliteral(L, "none"); break; + case CTL_JOYPAD: lua_pushliteral(L, "joypad"); break; + case CTL_MOUSE: lua_pushliteral(L, "mouse"); break; + case CTL_SUPERSCOPE: lua_pushliteral(L, "superscope"); break; + case CTL_JUSTIFIER: lua_pushstring(L, ids[0] ? "justifiers" : "justifier"); break; + case CTL_MP5: lua_pushliteral(L, "multitap"); break; + } + return 1; +} + +// joypad.settype(int port = 1, string typename) +// +// Sets the type of controller at the given physical port index 1 or 2 +// (port is the same as "which" for other input functions, unless there's a multitap) +// The SNES sees a new controller type get plugged in instantly. +// note that it's an error to call this command while a movie is active. +// note that a superscope must be plugged into port 2 for it to work, and other peripherals might have similar sorts of requirements +// valid types are "joypad", "mouse", "superscope", "justifier", "justifiers", "multitap", "none" +DEFINE_LUA_FUNCTION(joy_settype, "[port=1,]typename") +{ + if (S9xMovieActive()) + luaL_error(L, "joypad.settype() cannot be called while a movie is active."); + + int port = 0; + int index = 1; + if (lua_type(L, index) == LUA_TNUMBER) + { + port = luaL_checkinteger(L, index) - 1; + index++; + } + const char* type = luaL_checkstring(L, index); + + controllers controller; + int8 ids[4]; + S9xGetController(port, &controller, &ids[0], &ids[1], &ids[2], &ids[3]); + + if(!strcmp(type, "joypad")) + { + controller = CTL_JOYPAD; + ids[0] = port; + } + else if(!strcmp(type, "mouse")) + { + controller = CTL_MOUSE; + ids[0] = port; + } + else if(!strcmp(type, "superscope")) + { + controller = CTL_SUPERSCOPE; + ids[0] = 0; + } + else if(!strcmp(type, "justifier")) + { + controller = CTL_JUSTIFIER; + ids[0] = 0; + } + else if(!strcmp(type, "justifiers")) + { + controller = CTL_JUSTIFIER; + ids[0] = 1; + } + else if(!strcmp(type, "multitap")) + { + controller = CTL_MP5; + if(port == 0) + { + ids[0] = 0; + ids[1] = 1; + ids[2] = 2; + ids[3] = 3; + } + } + else + controller = CTL_NONE; + + Settings.MouseMaster = true; + Settings.JustifierMaster = true; + Settings.SuperScopeMaster = true; + Settings.MultiPlayer5Master = true; + + S9xSetController(port, controller, ids[0],ids[1],ids[2],ids[3]); + + Settings.MultiPlayer5Master = false; + Settings.SuperScopeMaster = false; + Settings.JustifierMaster = false; + Settings.MouseMaster = false; + + // now fix emulation settings and controller ids for multitap + S9xGetController(0, &controller, &ids[0],&ids[1],&ids[2],&ids[3]); + int max0id = std::max((signed char)0, std::max(ids[0], std::max(ids[1], std::max(ids[2], ids[3])))); + if(controller == CTL_MOUSE) Settings.MouseMaster = true; + if(controller == CTL_JUSTIFIER) Settings.JustifierMaster = true; + if(controller == CTL_SUPERSCOPE) Settings.SuperScopeMaster = true; + if(controller == CTL_MP5) Settings.MultiPlayer5Master = true; + controllers controller2; + S9xGetController(1, &controller2, &ids[0],&ids[1],&ids[2],&ids[3]); + if(controller2 == CTL_MOUSE) Settings.MouseMaster = true; + if(controller2 == CTL_JUSTIFIER) Settings.JustifierMaster = true; + if(controller2 == CTL_SUPERSCOPE) Settings.SuperScopeMaster = true; + if(controller2 == CTL_MP5) Settings.MultiPlayer5Master = true; + if((controller2 == CTL_JOYPAD && controller == CTL_MP5) || controller2 == CTL_MP5) + { + ids[0] = max0id + 1; + if(controller2 == CTL_MP5) + { + ids[1] = max0id + 2; + ids[2] = max0id + 3; + ids[3] = max0id + 4; + } + S9xSetController(port, controller2, ids[0],ids[1],ids[2],ids[3]); + } + +#ifdef __WIN32__ + // support only limited combination of peripherals + extern void ChangeInputDevice(void); + if(!strcmp(type, "mouse") && port == 0) + GUI.ControllerOption = SNES_MOUSE; + else if(!strcmp(type, "mouse") && port == 1) + GUI.ControllerOption = SNES_MOUSE_SWAPPED; + else if(!strcmp(type, "superscope")) + GUI.ControllerOption = SNES_SUPERSCOPE; + else if(!strcmp(type, "justifier")) + GUI.ControllerOption = SNES_JUSTIFIER; + else if(!strcmp(type, "justifiers")) + GUI.ControllerOption = SNES_JUSTIFIER_2; + else if(!strcmp(type, "multitap") && port == 0) + GUI.ControllerOption = SNES_MULTIPLAYER8; + else if(!strcmp(type, "multitap") && port == 1) + GUI.ControllerOption = SNES_MULTIPLAYER5; + else + GUI.ControllerOption = SNES_JOYPAD; + ChangeInputDevice(); +#endif + + return 0; +} + int joy_getArgControllerNum(lua_State* L, int& index) { int controllerNumber; @@ -2285,6 +2443,32 @@ int joy_getArgControllerNum(lua_State* L, int& index) } +// PERIPHERAL_SUPPORT +#define SNESMOUSE_LEFT 0x40 +#define SNESMOUSE_RIGHT 0x80 +#define SUPERSCOPE_FIRE 0x80 +#define SUPERSCOPE_CURSOR 0x40 +#define SUPERSCOPE_TURBO 0x20 +#define SUPERSCOPE_PAUSE 0x10 +#define SUPERSCOPE_OFFSCREEN 0x02 +#define JUSTIFIER_TRIGGER 0x80 +#define JUSTIFIER_START 0x20 +#define JUSTIFIER_SELECT 0x08 +#define JUSTIFIER_OFFSCREEN 0x02 +#define JUSTIFIER2_TRIGGER 0x40 +#define JUSTIFIER2_START 0x10 +#define JUSTIFIER2_SELECT 0x04 +#define JUSTIFIER2_OFFSCREEN 0x01 +#define MOUSE_DATA_SIZE 5 +#define SCOPE_DATA_SIZE 6 +#define JUSTIFIER_DATA_SIZE 11 +bool MovieGetMouse(int i, uint8 out [MOUSE_DATA_SIZE]); +bool MovieGetScope(int i, uint8 out [SCOPE_DATA_SIZE]); +bool MovieGetJustifier(int i, uint8 out [JUSTIFIER_DATA_SIZE]); +void AddCommandTransformAxis(controllers type, int idx, int16 val, bool8 axis); +void AddCommandTransformButton(controllers type, int idx, bool8 on, uint8 mask); +void ClearCommandTransforms(); + // joypad.set(controllerNum = 1, inputTable) // controllerNum can be within the range 1 to 8 DEFINE_LUA_FUNCTION(joy_set, "[controller=1,]inputtable") @@ -2292,7 +2476,9 @@ DEFINE_LUA_FUNCTION(joy_set, "[controller=1,]inputtable") int index = 1; int controllerNumber = joy_getArgControllerNum(L, index); - luaL_checktype(L, index, LUA_TTABLE); + // And the table of buttons. + int tableIndex = lua_istable(L, 1) ? 1 : 2; + luaL_checktype(L, tableIndex, LUA_TTABLE); if (S9xMoviePlaying()) // don't allow tampering with a playing movie's input return 0; // (although it might be useful sometimes...) @@ -2304,29 +2490,57 @@ DEFINE_LUA_FUNCTION(joy_set, "[controller=1,]inputtable") return 0; } - uint32 input = 0; - uint32 mask = 0; + controllers con = CTL_JOYPAD; + int8 ids[4]; + if(controllerNumber <= 2) // could be a peripheral in ports 1 or 2, let's check + S9xGetController(controllerNumber - 1, &con, &ids[0], &ids[1], &ids[2], &ids[3]); - for(int i = 0; i < sizeof(s_buttonDescs)/sizeof(*s_buttonDescs); i++) + switch(con) { - const ButtonDesc& bd = s_buttonDescs[i]; - if(bd.controllerNum == controllerNumber) + default: // joypad { - lua_getfield(L, index, bd.name); - if (!lua_isnil(L,-1)) + uint32 input = 0; + uint32 mask = 0; + + for(int i = 0; i < sizeof(s_buttonDescs)/sizeof(*s_buttonDescs); i++) { - bool pressed = lua_toboolean(L,-1) != 0; - uint32 bitmask = ((uint32)1 << bd.bit); - if(pressed) - input |= bitmask; - else - input &= ~bitmask; - mask |= bitmask; + const ButtonDesc& bd = s_buttonDescs[i]; + if(bd.controllerNum == controllerNumber) + { + lua_getfield(L, index, bd.name); + if (!lua_isnil(L,-1)) + { + bool pressed = lua_toboolean(L,-1) != 0; + uint32 bitmask = ((uint32)1 << bd.bit); + if(pressed) + input |= bitmask; + else + input &= ~bitmask; + mask |= bitmask; + } + lua_pop(L,1); + } } - lua_pop(L,1); + MovieSetJoypad(controllerNumber - 1, input, mask); } + break; + case CTL_MOUSE: + { + // TODO NYI + } + break; + case CTL_SUPERSCOPE: + { + // TODO NYI + } + break; + case CTL_JUSTIFIER: + { + // TODO NYI + } + break; } - MovieSetJoypad(controllerNumber - 1, input, mask); + return 0; } @@ -2339,20 +2553,189 @@ int joy_get_internal(lua_State* L, bool reportUp, bool reportDown) lua_newtable(L); - uint32 input = MovieGetJoypad(controllerNumber - 1); + controllers controller = CTL_JOYPAD; + int8 ids[4]; + if(controllerNumber <= 2) // could be a peripheral in ports 1 or 2, let's check + S9xGetController(controllerNumber - 1, &controller, &ids[0], &ids[1], &ids[2], &ids[3]); - for(int i = 0; i < sizeof(s_buttonDescs)/sizeof(*s_buttonDescs); i++) + bool pressed; + switch(controller) { - const ButtonDesc& bd = s_buttonDescs[i]; - if(bd.controllerNum == controllerNumber) + default: // joypad { - bool pressed = (input & ((uint32)1<