Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file removed .DS_Store
Binary file not shown.
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
1 change: 1 addition & 0 deletions src/cart.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

#include <stdio.h>
#include "memory.h"
#include "cp1610.h"
#include "cart.h"
#include "osd.h"

Expand Down
128 changes: 110 additions & 18 deletions src/controller.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
*/
#include <math.h>
#include "controller.h"

#include "cp1610.h"
#include "memory.h"

const double PI = 3.14159265358979323846;
Expand Down Expand Up @@ -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)
Expand All @@ -84,44 +91,124 @@ 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 */

Lx = joypad[14] / 8192;
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];
}
Expand All @@ -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];
}
Expand All @@ -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,
Expand Down
99 changes: 88 additions & 11 deletions src/libretro.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -263,21 +263,73 @@ 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))
{
paused = !paused;
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)
{
Expand All @@ -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;
Expand All @@ -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));
Expand All @@ -321,7 +398,7 @@ void retro_run(void)
showKeypad1 = false;
setControllerInput(1, getControllerState(joypad1, 1));
}

#endif
if(keyboardDown || keyboardChange)
{
setControllerInput(0, keyboardState);
Expand Down Expand Up @@ -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)
{
Expand All @@ -390,7 +467,7 @@ void retro_run(void)
OSD_drawRightLeft();
}
}

#endif
if (intv_halt)
OSD_drawTextBG(3, 5, "INTELLIVISION HALTED");
// send frame to libretro
Expand Down