diff --git a/.DS_Store b/.DS_Store deleted file mode 100644 index 5008ddf..0000000 Binary files a/.DS_Store and /dev/null differ diff --git a/README.md b/README.md index 2f4e69b..b4142fc 100644 --- a/README.md +++ b/README.md @@ -43,3 +43,6 @@ Mattel Intellivision games were often meant to be played with game-specific card | Start | Pause Game | | Select | Controller Swap | +## Todo + +- Some games won't work well with modern game controllers without a keypad. These games have been remapped to facebuttons to be functional like Night Stalker, however these fixes are currently achieved with #IFDEF's. Need to replace these IFDEFS with some form of decent game detection so it automatically sets these new mappings. \ No newline at end of file diff --git a/src/cart.c b/src/cart.c index fa8b4e3..e6a8023 100644 --- a/src/cart.c +++ b/src/cart.c @@ -17,6 +17,7 @@ #include #include "memory.h" +#include "cp1610.h" #include "cart.h" #include "osd.h" diff --git a/src/controller.c b/src/controller.c index d25b10e..1e74bfc 100644 --- a/src/controller.c +++ b/src/controller.c @@ -16,6 +16,8 @@ */ #include #include "controller.h" + +#include "cp1610.h" #include "memory.h" const double PI = 3.14159265358979323846; @@ -70,11 +72,16 @@ int getQuickKeypadState(int player); void controllerInit() { - controllerSwap = 0; // by default input 0 maps to Right Controller (0x1FE) // and input 1 maps to Left Controller (0x1FF) // pressing select (freeintv_libretro.c) will // swap the left and right controllers +#if defined(SHARKSHARK) || defined(REVCONTROLLERS) + //These titles require controller swap from boot + controllerSwap = 1; +#else + controllerSwap = 0; +#endif } void setControllerInput(int player, int state) @@ -84,31 +91,111 @@ void setControllerInput(int player, int state) int getControllerState(int joypad[], int player) { - // converts joypad input for use by system + // converts joypad input for use by system int Lx = 0; // left analog X int Ly = 0; // left analog Y int Rx = 0; // right analog X int Ry = 0; // right analog Y double theta; // analog joy angle - int norm; // theta, normalized + int norm; // theta, normalized int state = 0; //0xFF; - +#ifdef VECTRON if(joypad[0]!=0) { state |= D_N; } // 0xFB - Up if(joypad[1]!=0) { state |= D_S; } // 0xFE - Down - if(joypad[2]!=0) { state |= D_W; } // 0xF7 - Left - if(joypad[3]!=0) { state |= D_E; } // 0xFD - Right - - if(joypad[0]!=0 && joypad[2]!=0) { state |= D_NW; } // 0xE3 - Up+Left - if(joypad[0]!=0 && joypad[3]!=0) { state |= D_NE; } // 0xE9 - Up+Right - if(joypad[1]!=0 && joypad[2]!=0) { state |= D_SW; } // 0x36 - Down+Left - if(joypad[1]!=0 && joypad[3]!=0) { state |= D_SE; } // 0x3C - Down+Right - + if(joypad[2]!=0) { state |= D_SW; } // 0xF7 - Left + if(joypad[3]!=0) { state |= D_SE; } // 0xFD - Right + if(joypad[0]!=0 && joypad[2]!=0) { state = D_WSW; } // 0xE3 - Up+Left + if(joypad[0]!=0 && joypad[3]!=0) { state = D_ESE; } // 0xE9 - Up+Right + if(joypad[1]!=0 && joypad[2]!=0) { state = D_SSW; } // 0x36 - Down+Left + if(joypad[1]!=0 && joypad[3]!=0) { state = D_SSE; } // 0x3C - Down+Right +#else + if(joypad[0]!=0) { state |= D_N; } // 0xFB - Up + if(joypad[1]!=0) { state |= D_S; } // 0xFE - Down + if(joypad[2]!=0) { state |= D_W; } // 0xF7 - Left + if(joypad[3]!=0) { state |= D_E; } // 0xFD - Right + + if(joypad[0]!=0 && joypad[2]!=0) { state = D_NW; } // 0xE3 - Up+Left + if(joypad[0]!=0 && joypad[3]!=0) { state = D_NE; } // 0xE9 - Up+Right + if(joypad[1]!=0 && joypad[2]!=0) { state = D_SW; } // 0x36 - Down+Left + if(joypad[1]!=0 && joypad[3]!=0) { state = D_SE; } // 0x3C - Down+Right +#endif + +#if defined(NIGHTSTALKER) + //Nightstalker requires keypad to play so map keypad to face buttons + if(joypad[7]!=0) { state |= K_4; } + if(joypad[4]!=0) { state |= K_6; } + if(joypad[5]!=0) { state |= K_8; } + if(joypad[6]!=0) { state |= K_2; } +#elif defined(SHARKSHARK) + //Add Dart moves to shark shark + if(joypad[7]!=0) { state |= K_1; } // 0x5F - Button Top + if(joypad[4]!=0) { state |= K_3; } // 0x9F - Button Left + if(joypad[5]!=0) { state |= B_RIGHT; } // 0x3F - Button Right + if(joypad[6]!=0) { state |= K_6; } +#elif defined(ASTROSMASH) + //Astrosmash requires keypad to play so map Button Top to K3 (Hyper space) + if(joypad[7]!=0) { state |= K_3; } // 0x5F - Button Top + if(joypad[4]!=0) { state |= K_2; } // 0x3F - Button Right + if(joypad[5]!=0) { state |= B_LEFT; } // 0x9F - Button Left + if(joypad[6]!=0) { state |= K_1; } +#elif defined(PINBALL) + //Pinball needs the LEFT/RIGHT button flipping + if(joypad[7]!=0) { state |= B_TOP; } // 0x5F - Button Top + if(joypad[4]!=0) { state |= B_RIGHT; } // 0x3F - Button Right + if(joypad[5]!=0) { state |= B_LEFT; } // 0x9F - Button Left + if(joypad[6]!=0) { state |= getQuickKeypadState(player); } +#elif defined(SLAPSHOT) + //Slapshot needs choose player + if(joypad[7]!=0) { state |= B_TOP; } // 0x5F - Button Top + if(joypad[4]!=0) { state |= B_RIGHT; } // 0x3F - Button Right + if(joypad[5]!=0) { state |= B_LEFT; } // 0x9F - Button Left + if(joypad[6]!=0) { state |= K_0; } +#elif defined(HOVERFORCE) + if(joypad[7]!=0) { state |= B_TOP; } // 0x5F - Button Top + if(joypad[4]!=0) { state |= K_C; } + if(joypad[5]!=0) { state |= B_LEFT; } // 0x9F - Button Left + if(joypad[6]!=0) { state |= K_E; } + if(joypad[8]!=0) { state |= K_0; } // Map START to K0 instead of pause +#elif defined(MOUNTAINSKI) + if(joypad[7]!=0) { state |= B_TOP; } // 0x5F - Button Top + if(joypad[4]!=0) { state |= K_C; } + if(joypad[5]!=0) { state |= B_LEFT; } // 0x9F - Button Left + if(joypad[6]!=0) { state |= K_E; } + if(joypad[8]!=0) { state |= K_0; } // Map START to K0 instead of pause +#elif defined(DECATHLON) + if(joypad[7]!=0) { state |= B_TOP; } // 0x5F - Button Top + if(joypad[4]!=0) { state |= K_C; } // 0x3F - Button Right + if(joypad[5]!=0) { state |= K_E; } // 0x9F - Button Left + if(joypad[6]!=0) { state |= getQuickKeypadState(player); } +#elif defined(TOWERDOOM) + if(joypad[7]!=0) { state |= B_TOP; } // 0x5F - Button Top + if(joypad[4]!=0) { state |= K_C; } // 0x3F - Button Right + if(joypad[5]!=0) { state |= K_E; } // 0x9F - Button Left + if(joypad[6]!=0) { state |= getQuickKeypadState(player); } +#elif defined(VECTRON) + if(joypad[7]!=0) { state |= B_TOP; } // 0x5F - Button Top + if(joypad[4]!=0) { state |= B_RIGHT; } // 0x9F - Button Left + if(joypad[5]!=0) { state |= B_LEFT; } // 0x3F - Button Right + if(joypad[6]!=0) { state |= getQuickKeypadState(player); } +#elif defined(CLOUDY) + if(joypad[7]!=0) { state |= K_4; } + if(joypad[4]!=0) { state |= K_6; } + if(joypad[5]!=0) { state |= K_8; } + if(joypad[6]!=0) { state |= K_2; } + if(joypad[6]!=0 && joypad[7]!=0) { state = K_1; } // Up+Left facebuttons + if(joypad[6]!=0 && joypad[4]!=0) { state = K_3; } // Up+Right facebuttons + if(joypad[5]!=0 && joypad[7]!=0) { state = K_7; } // Down+Left facebuttons + if(joypad[5]!=0 && joypad[4]!=0) { state = K_9; } // Down+Right facebuttons + if(joypad[8]!=0) { state |= K_E; } + if(joypad[9]!=0) { state |= K_C; } + if(joypad[11]!=0) { state |= B_TOP; } +#else if(joypad[7]!=0) { state |= B_TOP; } // 0x5F - Button Top if(joypad[4]!=0) { state |= B_LEFT; } // 0x9F - Button Left if(joypad[5]!=0) { state |= B_RIGHT; } // 0x3F - Button Right - if(joypad[6]!=0) { state |= getQuickKeypadState(player); } +#endif /* Analog Controls for 16-way disc control */ @@ -116,12 +203,12 @@ int getControllerState(int joypad[], int player) Ly = joypad[15] / 8192; if(Lx != 0 || Ly != 0) { - // find angle + // find angle theta = atan2((double)Ly, (double)Lx) + PI; // normalize if(theta<0.0) { theta = 0.0; } norm = floor((theta/(2*PI))*15.0); - norm -= 3; + norm -= 3; if(norm<0) { norm += 16; } state |= discDirections[norm & 0x0F]; } @@ -131,12 +218,12 @@ int getControllerState(int joypad[], int player) Ry = joypad[17] / 8192; if(Rx != 0 || Ry != 0) { - // find angle + // find angle theta = atan2((double)Ry, (double)Rx) + PI; // normalize if(theta<0.0) { theta = 0.0; } norm = floor((theta/(2*PI))*7.0); - norm -= 1; + norm -= 1; if(norm<0) { norm += 8; } state |= keypadDirections[norm & 0x07]; } @@ -145,11 +232,16 @@ int getControllerState(int joypad[], int player) if(joypad[18]!=0) { state |= K_0; } // 0x48 - Keypad 0 if(joypad[19]!=0) { state |= K_5; } // 0x42 - Keypad 5 +#ifdef CLOUDY + // L trigger used for in game gameplay (QOL - check arrows) + if(joypad[13]!=0) { state |= K_0; } + return state; +#else // L/R triggers for Keypad Enter/Clear if(joypad[12]!=0) { state |= K_C; } // 0x88 - Keypad Clear if(joypad[13]!=0) { state |= K_E; } // 0x28 - Keypad Enter - return state; +#endif } // Mini keypads, displayed in the corner using a shoulder button, diff --git a/src/libretro.c b/src/libretro.c index e33330a..2ba0f81 100644 --- a/src/libretro.c +++ b/src/libretro.c @@ -53,10 +53,10 @@ void retro_set_input_state(retro_input_state_t fn) { InputState = fn; } struct retro_game_geometry Geometry; -int joypad0[18]; // joypad 0 state -int joypad1[18]; // joypad 1 state -int joypre0[18]; // joypad 0 previous state -int joypre1[18]; // joypad 1 previous state +int joypad0[20]; // joypad 0 state +int joypad1[20]; // joypad 1 state +int joypre0[20]; // joypad 0 previous state +int joypre1[20]; // joypad 1 previous state bool paused = false; @@ -263,8 +263,9 @@ void retro_run(void) joypad1[16] = InputState(1, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_X); joypad1[17] = InputState(1, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_Y); joypad1[18] = InputState(1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L3); - joypad1[18] = InputState(1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R3); + joypad1[19] = InputState(1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R3); +#if !defined(HOVERFORCE) && !defined(MOUNTAINSKI) && !defined(CLOUDY) // Pause if((joypad0[8]==1 && joypre0[8]==0) || (joypad1[8]==1 && joypre1[8]==0)) { @@ -272,12 +273,63 @@ void retro_run(void) if(paused) { OSD_drawPaused(); +#ifdef XBOXPADSTYLEHELP + OSD_drawTextCenterBG(21, "HELP - PRESS B"); +#else OSD_drawTextCenterBG(21, "HELP - PRESS A"); +#endif } } +#endif if(paused) { +#ifdef XBOXPADSTYLE + // If core is being built for a device which uses XBOX style + // facebuttons instead of retropad. Reverse the mapping help + // help menu // + if(joypad0[4]==1 || joypad1[4]==1) + { + OSD_drawTextBG(3, 4, " "); + OSD_drawTextBG(3, 5, " - HELP - "); + OSD_drawTextBG(3, 6, " "); + OSD_drawTextBG(3, 7, " B - RIGHT ACTION BUTTON "); + OSD_drawTextBG(3, 8, " A - LEFT ACTION BUTTON "); + OSD_drawTextBG(3, 9, " X - TOP ACTION BUTTON "); + OSD_drawTextBG(3, 10, " Y - LAST SELECTED KEYPAD BUTTON "); + OSD_drawTextBG(3, 11, " L/R - SHOW KEYPAD "); + OSD_drawTextBG(3, 12, " LT/RT - KEYPAD CLEAR/ENTER "); + OSD_drawTextBG(3, 13, " "); + OSD_drawTextBG(3, 14, " START - PAUSE GAME "); + OSD_drawTextBG(3, 15, " SELECT - SWAP LEFT/RIGHT CONTROLLERS "); + OSD_drawTextBG(3, 16, " "); + OSD_drawTextBG(3, 17, " FREEINTV 1.3 LICENSE GPL V2 "); + OSD_drawTextBG(3, 18, " "); + } +#elif defined(NIGHTSTALKER) || defined(ASTROSMASH) || defined(PINBALL) || defined(SHARKSHARK) || defined(SLAPSHOT) || \ + defined(HOVERFORCE) || defined(DECATHLON) || defined (TOWERDOOM) || defined (VECTRON) || defined(CLOUDY) + // These games have special mappings so the mapping details + // are offputting so just tell them to refer to manual or overlay. + // help menu // + if(joypad0[4]==1 || joypad1[4]==1) + { + OSD_drawTextBG(3, 4, " "); + OSD_drawTextBG(3, 5, " - HELP - "); + OSD_drawTextBG(3, 6, " "); + OSD_drawTextBG(3, 7, " "); + OSD_drawTextBG(3, 8, " PLEASE CHECK MANUAL "); + OSD_drawTextBG(3, 9, " OR OVERLAY "); + OSD_drawTextBG(3, 10, " "); + OSD_drawTextBG(3, 11, " L/R - SHOW KEYPAD "); + OSD_drawTextBG(3, 12, " LT/RT - KEYPAD CLEAR/ENTER "); + OSD_drawTextBG(3, 13, " "); + OSD_drawTextBG(3, 14, " START - PAUSE GAME "); + OSD_drawTextBG(3, 15, " SELECT - SWAP LEFT/RIGHT CONTROLLERS "); + OSD_drawTextBG(3, 16, " "); + OSD_drawTextBG(3, 17, " FREEINTV 1.3 LICENSE GPL V2 "); + OSD_drawTextBG(3, 18, " "); + } +#else // help menu // if(joypad0[4]==1 || joypad1[4]==1) { @@ -294,12 +346,25 @@ void retro_run(void) OSD_drawTextBG(3, 14, " START - PAUSE GAME "); OSD_drawTextBG(3, 15, " SELECT - SWAP LEFT/RIGHT CONTROLLERS "); OSD_drawTextBG(3, 16, " "); - OSD_drawTextBG(3, 17, " FREEINTV 1.2 LICENSE GPL V3 "); + OSD_drawTextBG(3, 17, " FREEINTV 1.3 LICENSE GPL V2 "); OSD_drawTextBG(3, 18, " "); } +#endif } else { +#ifdef CLOUDY + if(joypad0[10]) // left shoulder down (Right shoulder required for gameplay in A D&D Cloudy Mountain) + { + showKeypad0 = true; + setControllerInput(0, getKeypadState(0, joypad0, joypre0)); + } + else + { + showKeypad0 = false; + setControllerInput(0, getControllerState(joypad0, 0)); + } +#else if(joypad0[10] | joypad0[11]) // left/right shoulder down { showKeypad0 = true; @@ -310,8 +375,20 @@ void retro_run(void) showKeypad0 = false; setControllerInput(0, getControllerState(joypad0, 0)); } - - if(joypad1[10] | joypad1[11]) // left shoulder down +#endif +#ifdef CLOUDY + if(joypad1[10]) // left shoulder down (Right shoulder required for gameplay in A D&D Cloudy Mountain) + { + showKeypad1 = true; + setControllerInput(1, getKeypadState(1, joypad1, joypre1)); + } + else + { + showKeypad1 = false; + setControllerInput(1, getControllerState(joypad1, 1)); + } +#else + if(joypad1[10] | joypad1[11]) // left/right shoulder down { showKeypad1 = true; setControllerInput(1, getKeypadState(1, joypad1, joypre1)); @@ -321,7 +398,7 @@ void retro_run(void) showKeypad1 = false; setControllerInput(1, getControllerState(joypad1, 1)); } - +#endif if(keyboardDown || keyboardChange) { setControllerInput(0, keyboardState); @@ -373,7 +450,7 @@ void retro_run(void) ivoiceBufferPos = 0.0; ivoice_frame(); } - +#ifndef CLOUDY // Swap Left/Right Controller if(joypad0[9]==1 || joypad1[9]==1) { @@ -390,7 +467,7 @@ void retro_run(void) OSD_drawRightLeft(); } } - +#endif if (intv_halt) OSD_drawTextBG(3, 5, "INTELLIVISION HALTED"); // send frame to libretro