Compare commits

...
Sign in to create a new pull request.

1 commit

Author SHA1 Message Date
Ilari Liusvaara
891a878c50 WIP on dynamic multitap enable/disable
Switch in/out of multitap mode while inside poll is not properly
emulated yet.
2015-11-17 07:59:58 +02:00
2 changed files with 77 additions and 11 deletions

View file

@ -540,6 +540,7 @@ namespace
{"ygamepad16", "Y-cabled gamepad (16-button)", 9},
{"multitap", "Multitap", 3},
{"multitap16", "Multitap (16-button)", 4},
{"multitapd", "Multitap (dynamic enable)", 10},
{"mouse", "Mouse", 5}
}},
{"port2", "Port 2 Type", "none", {
@ -549,6 +550,7 @@ namespace
{"ygamepad16", "Y-cabled gamepad (16-button)", 9},
{"multitap", "Multitap", 3},
{"multitap16", "Multitap (16-button)", 4},
{"multitapd", "Multitap (dynamic enable)", 10},
{"mouse", "Mouse", 5},
{"superscope", "Super Scope", 8},
{"justifier", "Justifier", 6},
@ -569,15 +571,22 @@ namespace
////////////////// PORTS COMMON ///////////////////
portctrl::type* index_to_ptype[] = {
&none, &gamepad, &gamepad16, &multitap, &multitap16, &mouse, &justifier, &justifiers, &superscope,
&ygamepad16
&ygamepad16, &multitapd
};
//The dynamic enable multitap is marked multitap here because initially it is one.
unsigned index_to_bsnes_type[] = {
SNES_DEVICE_NONE, SNES_DEVICE_JOYPAD, SNES_DEVICE_JOYPAD, SNES_DEVICE_MULTITAP, SNES_DEVICE_MULTITAP,
SNES_DEVICE_MOUSE, SNES_DEVICE_JUSTIFIER, SNES_DEVICE_JUSTIFIERS, SNES_DEVICE_SUPER_SCOPE,
SNES_DEVICE_JOYPAD
SNES_DEVICE_JOYPAD, SNES_DEVICE_MULTITAP
};
bool port_is_ycable[2];
struct port_flags_struct
{
bool is_ycable; //Y-cable is connected to port?
bool dynamic_multitap; //Port has dynamic multitap enable/disable?
bool multitap_enable; //Multitap enabled on port (only meaningful if dynamic_multitap)?
bool multitap_toggle; //Multitap is being toggled next frame.
} port_flags[2];
void snesdbg_on_break();
void snesdbg_on_trace();
@ -625,6 +634,14 @@ namespace
img[2].markup, img[2].data, img[2].size);
}
void setup_state_vars_on_load()
{
do_reset_flag = -1;
port_flags[0].multitap_toggle = false;
port_flags[1].multitap_toggle = false;
port_flags[0].multitap_enable = (dynamic_cast<SNES::Multitap*>(SNES::input.port1) != NULL);
port_flags[1].multitap_enable = (dynamic_cast<SNES::Multitap*>(SNES::input.port2) != NULL);
}
int load_rom(core_type* ctype, core_romimage* img, std::map<std::string, std::string>& settings,
uint64_t secs, uint64_t subsecs, bool(*fun)(core_romimage*))
@ -663,10 +680,12 @@ namespace
internal_rom = ctype;
snes_set_controller_port_device(false, index_to_bsnes_type[type1]);
snes_set_controller_port_device(true, index_to_bsnes_type[type2]);
port_is_ycable[0] = (type1 == 9);
port_is_ycable[1] = (type2 == 9);
port_flags[0].is_ycable = (type1 == 9);
port_flags[1].is_ycable = (type2 == 9);
port_flags[0].dynamic_multitap = (type1 == 10);
port_flags[1].dynamic_multitap = (type2 == 10);
have_saved_this_frame = false;
do_reset_flag = -1;
setup_state_vars_on_load();
if(ecore_callbacks)
ecore_callbacks->action_state_updated();
//Save initial state, so we can restore it later.
@ -696,6 +715,8 @@ namespace
r.ports.push_back(index_to_ptype[type2]);
unsigned p1controllers = r.ports[1]->controller_info->controllers.size();
unsigned p2controllers = r.ports[2]->controller_info->controllers.size();
if(p1controllers == 5) p1controllers = 4; //Skip 5th controller, it is control only.
if(p2controllers == 5) p2controllers = 4; //Skip 5th controller, it is control only.
r.logical_map.resize(p1controllers + p2controllers);
if(p1controllers == 4) {
r.logical_map[0] = std::make_pair(1, 0);
@ -773,7 +794,7 @@ namespace
int16_t inputPoll(bool port, SNES::Input::Device device, unsigned index, unsigned id)
{
if(port_is_ycable[port ? 1 : 0]) {
if(port_flags[port ? 1 : 0].is_ycable) {
int16_t bit0 = ecore_callbacks->get_input(port ? 2 : 1, 0, id);
int16_t bit1 = ecore_callbacks->get_input(port ? 2 : 1, 1, id);
return bit0 + 2 * bit1;
@ -1103,12 +1124,22 @@ namespace
ecore_callbacks->memory_write(_addr, val);
}
bool switch_multitap_state(unsigned port, bool do_it)
{
if(port > 1 || !do_it) return false;
//FIXME: This does not handle the switch correctly if in mid-poll.
port_flags[port].multitap_enable = !port_flags[port].multitap_enable;
snes_set_controller_port_device(port == 1, port_flags[port].multitap_enable ? SNES_DEVICE_MULTITAP :
SNES_DEVICE_JOYPAD);
return true;
}
void redraw_cover_fbinfo();
struct _bsnes_core : public core_core
{
_bsnes_core() : core_core({&gamepad, &gamepad16, &justifier, &justifiers, &mouse, &multitap,
&multitap16, &none, &superscope, &psystem, &psystem_hreset, &psystem_compact}, {
&multitap16, &none, &superscope, &psystem, &psystem_hreset, &psystem_compact, &multitapd}, {
{0, "Soft reset", "reset", {}},
{1, "Hard reset", "hardreset", {}},
#ifdef BSNES_HAS_DEBUGGER
@ -1133,6 +1164,8 @@ namespace
{22, "Layers‣Sprite Priority 2", "oampri2", {{"", "toggle"}}},
{23, "Layers‣Sprite Priority 3", "oampri3", {{"", "toggle"}}},
#endif
{24, "Port 1 multitap enable", "multitap1", {{"", "toggle"}}},
{25, "Port 2 multitap enable", "multitap2", {{"", "toggle"}}},
}) {}
std::string c_core_identifier() const {
@ -1224,7 +1257,7 @@ namespace
if(!SNES::system.unserialize(s))
throw std::runtime_error("SNES core rejected savestate");
have_saved_this_frame = true;
do_reset_flag = -1;
setup_state_vars_on_load();
}
core_region& c_get_region() {
return (SNES::system.region() == SNES::System::Region::PAL) ? region_pal : region_ntsc;
@ -1265,6 +1298,13 @@ namespace
if(!internal_rom)
return;
bool was_delay_reset = false;
bool a_updated = false;
for(unsigned i = 0; i < 2; i++)
a_updated |= switch_multitap_state(i, port_flags[i].dynamic_multitap &&
ecore_callbacks->get_input(i + 1, 4, 0));
if(a_updated) ecore_callbacks->action_state_updated();
int16_t reset = ecore_callbacks->get_input(0, 0, 1);
int16_t hreset = 0;
if(support_hreset)
@ -1372,6 +1412,12 @@ again2:
}
void c_pre_emulate_frame(portctrl::frame& cf)
{
for(unsigned i = 0; i < 2; i++) {
if(port_flags[i].dynamic_multitap)
cf.axis3(i + 1, 4, 0, port_flags[i].multitap_toggle ? 1 : 0);
port_flags[i].multitap_toggle = false;
}
cf.axis3(0, 0, 1, (do_reset_flag >= 0) ? 1 : 0);
if(support_hreset)
cf.axis3(0, 0, 4, do_hreset_flag ? 1 : 0);
@ -1410,6 +1456,11 @@ again2:
ecore_callbacks->action_state_updated();
}
#endif
if(id == 24 || id == 25) {
if(!port_flags[id-24].dynamic_multitap) return;
port_flags[id - 24].multitap_toggle = !port_flags[id - 24].multitap_toggle;
ecore_callbacks->action_state_updated();
}
}
const interface_device_reg* c_get_registers() { return snes_registers; }
unsigned c_action_flags(unsigned id)
@ -1426,6 +1477,13 @@ again2:
return SNES::ppu.layer_enabled[y][id % 4] ? 3 : 1;
}
#endif
if(id == 24 || id == 25) {
//Controller 1/2 multitap enable.
unsigned flags = 0;
if(port_flags[id-24].multitap_enable ^ port_flags[id-24].multitap_toggle) flags |= 2;
if(port_flags[id-24].dynamic_multitap) flags |= 1;
return flags;
}
return 0; //WTF?
}
int c_reset_action(bool hard)
@ -1552,7 +1610,7 @@ again2:
if(!SNES::system.unserialize(s))
throw std::runtime_error("SNES core rejected initial state?");
have_saved_this_frame = false;
do_reset_flag = -1;
setup_state_vars_on_load();
if(ecore_callbacks)
ecore_callbacks->action_state_updated();
}

View file

@ -29,6 +29,7 @@
"hard":{"type":"button", "name":"hard", "symbol":"H", "shadow":true},
"rhigh":{"type":"axis", "name":"rhigh", "shadow":true},
"rlow":{"type":"axis", "name":"rlow", "shadow":true},
"menable":{"type":"button", "name":"menable", "symbol":"M", "shadow":true},
"shadownull":{"type":"null", "shadow":true}
},"controllers":{
"gamepad":{"type":"gamepad", "class":"gamepad", "buttons":[
@ -40,6 +41,9 @@
"buttons/left", "buttons/right", "buttons/A", "buttons/X", "buttons/L", "buttons/R",
"buttons/ext0", "buttons/ext1", "buttons/ext2", "buttons/ext3"
]},
"mtoggle":{"type":"mtoggle", "class":"mtoggle", "buttons":[
"buttons/menable"
]},
"justifier":{"type":"justifier", "class":"justifier", "buttons":[
"buttons/xaxis", "buttons/yaxis", "buttons/trigger", "buttons/start"
]},
@ -98,6 +102,10 @@
],"legal":[0]},
{"symbol":"psystem_compact", "name":"system", "hname":"system", "controllers":[
"controllers/system_compact"
],"legal":[0]}
],"legal":[0]},
{"symbol":"multitapd", "name":"multitapd", "hname":"Multitap (dynamic enable)", "controllers":[
"controllers/gamepad", "controllers/gamepad", "controllers/gamepad", "controllers/gamepad",
"controllers/mtoggle"
],"legal":[1, 2]}
]
}