snes, add justifier support for lethal enforcers
This commit is contained in:
parent
b3291e88fa
commit
f78d51fb61
|
@ -773,6 +773,7 @@ int BurnComputeSHA1(const UINT8 *buffer, int buffer_size, char *hash_str);
|
|||
#define HARDWARE_FDS (HARDWARE_PREFIX_FDS)
|
||||
#define HARDWARE_SNES (HARDWARE_PREFIX_SNES)
|
||||
#define HARDWARE_SNES_ZAPPER (HARDWARE_PREFIX_SNES | 0x0000001)
|
||||
#define HARDWARE_SNES_JUSTIFIER (HARDWARE_PREFIX_SNES | 0x0000002)
|
||||
|
||||
#define HARDWARE_CHANNELF (HARDWARE_PREFIX_CHANNELF)
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ static UINT8 DrvRecalc = 1;
|
|||
static UINT8 LastControllerDip = 0;
|
||||
static UINT8 LastControllerTimer = 0;
|
||||
|
||||
static INT32 has_gun = 0;
|
||||
static INT32 has_gun = 0; // 1 Zapper (SuperScope), 2 Justifier
|
||||
static ButtonToggle scope_turbo;
|
||||
static ButtonToggle scope_pause;
|
||||
|
||||
|
@ -139,6 +139,38 @@ static struct BurnInputInfo SNESZapperInputList[] = {
|
|||
|
||||
STDINPUTINFO(SNESZapper)
|
||||
|
||||
static struct BurnInputInfo SNESJustifierInputList[] = {
|
||||
{"P1 Up", BIT_DIGITAL, snesInputPort0 + 4, "p1 up" },
|
||||
{"P1 Down", BIT_DIGITAL, snesInputPort0 + 5, "p1 down" },
|
||||
{"P1 Left", BIT_DIGITAL, snesInputPort0 + 6, "p1 left" },
|
||||
{"P1 Right", BIT_DIGITAL, snesInputPort0 + 7, "p1 right" },
|
||||
{"P1 Button Y", BIT_DIGITAL, snesInputPort0 + 1, "p1 fire 1" },
|
||||
{"P1 Button X", BIT_DIGITAL, snesInputPort0 + 9, "p1 fire 2" },
|
||||
{"P1 Button B", BIT_DIGITAL, snesInputPort0 + 0, "p1 fire 3" },
|
||||
{"P1 Button A", BIT_DIGITAL, snesInputPort0 + 8, "p1 fire 4" },
|
||||
{"P1 Button L", BIT_DIGITAL, snesInputPort0 + 10, "p1 fire 5" },
|
||||
{"P1 Button R", BIT_DIGITAL, snesInputPort0 + 11, "p1 fire 6" },
|
||||
{"P1 Select", BIT_DIGITAL, snesInputPort0 + 2, "p1 select" },
|
||||
{"P1 Start", BIT_DIGITAL, snesInputPort0 + 3, "p1 start" },
|
||||
|
||||
A("P2 Gun X", BIT_ANALOG_REL, &Analog[0], "p2 x-axis" ),
|
||||
A("P2 Gun Y", BIT_ANALOG_REL, &Analog[1], "p2 y-axis" ),
|
||||
{"P2 Fire", BIT_DIGITAL, snesInputPort1 + 7, "p2 fire 1" },
|
||||
{"P2 Start", BIT_DIGITAL, snesInputPort1 + 5, "p2 fire 2" },
|
||||
|
||||
A("P3 Gun X", BIT_ANALOG_REL, &Analog[2], "p3 x-axis" ),
|
||||
A("P3 Gun Y", BIT_ANALOG_REL, &Analog[3], "p3 y-axis" ),
|
||||
{"P3 Fire", BIT_DIGITAL, snesInputPort1 + 6, "p3 fire 1" },
|
||||
{"P3 Start", BIT_DIGITAL, snesInputPort1 + 4, "p3 fire 2" },
|
||||
|
||||
{"Reset", BIT_DIGITAL, &DrvReset, "reset" },
|
||||
|
||||
{"Dip A", BIT_DIPSWITCH, DrvDips + 0, "dip" },
|
||||
{"Dip B", BIT_DIPSWITCH, DrvDips + 1, "dip" },
|
||||
};
|
||||
|
||||
STDINPUTINFO(SNESJustifier)
|
||||
|
||||
static struct BurnDIPInfo SNESDIPList[] =
|
||||
{
|
||||
DIP_OFFSET(0x19)
|
||||
|
@ -157,6 +189,15 @@ static struct BurnDIPInfo SNESZapperDIPList[] =
|
|||
|
||||
STDDIPINFO(SNESZapper)
|
||||
|
||||
static struct BurnDIPInfo SNESJustifierDIPList[] =
|
||||
{
|
||||
DIP_OFFSET(0x15)
|
||||
{0x00, 0xff, 0xff, 0x00, NULL },
|
||||
{0x01, 0xff, 0xff, 0x00, NULL },
|
||||
};
|
||||
|
||||
STDDIPINFO(SNESJustifier)
|
||||
|
||||
static struct BurnDIPInfo SNESMouseBaseDIPList[] =
|
||||
{
|
||||
DIP_OFFSET(0x21)
|
||||
|
@ -287,6 +328,12 @@ static INT32 DrvInit()
|
|||
BurnGunInit(1, true);
|
||||
}
|
||||
|
||||
if (BurnDrvGetHardwareCode() == HARDWARE_SNES_JUSTIFIER) {
|
||||
bprintf(0, _T("*** SNES: With Justifier\n"));
|
||||
has_gun = 2;
|
||||
BurnGunInit(2, true);
|
||||
}
|
||||
|
||||
DrvDoReset();
|
||||
|
||||
return 0;
|
||||
|
@ -358,8 +405,10 @@ static INT32 DrvScan(INT32 nAction, INT32* pnMin)
|
|||
|
||||
if (has_gun) {
|
||||
BurnGunScan();
|
||||
scope_turbo.Scan();
|
||||
scope_pause.Scan();
|
||||
if (has_gun == 1) {
|
||||
scope_turbo.Scan();
|
||||
scope_pause.Scan();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -386,20 +435,36 @@ static INT32 DrvFrame()
|
|||
if (has_gun) {
|
||||
BurnGunMakeInputs(0, Analog[0], Analog[1]);
|
||||
|
||||
snesInputPort1[8] = BurnGunReturnX(0);
|
||||
snesInputPort1[9] = BurnGunReturnY(0);
|
||||
scope_turbo.Toggle(snesInputPort1[2]);
|
||||
if (has_gun == 2) { // justifier - 2 guns
|
||||
BurnGunMakeInputs(1, Analog[2], Analog[3]); // 2nd gun
|
||||
}
|
||||
|
||||
if (has_gun == 1) { // superscope
|
||||
scope_turbo.Toggle(snesInputPort1[2]);
|
||||
}
|
||||
}
|
||||
|
||||
if (CheckControllerPlug() == 0) {
|
||||
INT32 p2_type = 0;
|
||||
switch (has_gun) {
|
||||
case 0: p2_type = DEVICE_GAMEPAD; break;
|
||||
case 1: p2_type = DEVICE_SUPERSCOPE; break;
|
||||
case 2: p2_type = DEVICE_JUSTIFIER; break;
|
||||
}
|
||||
|
||||
for (INT32 i = 0; i < 12; i++) {
|
||||
if ((DrvDips[1] & 0x01) == 0) {
|
||||
snes_setButtonState(snes, 1, i, snesInputPort0[i], DEVICE_GAMEPAD);
|
||||
}
|
||||
if ((DrvDips[1] & 0x02) == 0) { // p2 controller or lightgun
|
||||
snes_setButtonState(snes, 2, i, snesInputPort1[i], has_gun ? DEVICE_SUPERSCOPE : DEVICE_GAMEPAD);
|
||||
if ((DrvDips[1] & 0x02) == 0) { // p2 controller or lightgun (SuperScope, Justifier)
|
||||
snes_setButtonState(snes, 2, i, snesInputPort1[i], p2_type);
|
||||
}
|
||||
}
|
||||
|
||||
if (has_gun) {
|
||||
snes_setGunState(snes, BurnGunReturnX(0), BurnGunReturnY(0), (p2_type == DEVICE_JUSTIFIER) ? BurnGunReturnX(1) : 0, (p2_type == DEVICE_JUSTIFIER) ? BurnGunReturnY(1) : 0);
|
||||
}
|
||||
|
||||
if (DrvDips[1] & 0x01) {
|
||||
snes_setMouseState(snes, 1, Analog[0], Analog[1], snesMouseButtons[0], snesMouseButtons[1]);
|
||||
}
|
||||
|
@ -14393,8 +14458,8 @@ struct BurnDriver BurnDrvsnes_Lethalenf = {
|
|||
"snes_lethalenf", NULL, NULL, NULL, "1993",
|
||||
"Lethal Enforcers (USA)\0", NULL, "Konami", "Nintendo",
|
||||
NULL, NULL, NULL, NULL,
|
||||
BDF_GAME_WORKING, 2, HARDWARE_SNES, GBF_SHOOT, 0,
|
||||
SNESGetZipName, snes_LethalenfRomInfo, snes_LethalenfRomName, NULL, NULL, NULL, NULL, SNESInputInfo, SNESDIPInfo,
|
||||
BDF_GAME_WORKING, 2, HARDWARE_SNES_JUSTIFIER, GBF_SHOOT, 0,
|
||||
SNESGetZipName, snes_LethalenfRomInfo, snes_LethalenfRomName, NULL, NULL, NULL, NULL, SNESJustifierInputInfo, SNESJustifierDIPInfo,
|
||||
DrvInit, DrvExit, DrvFrame, DrvDraw, DrvScan, &DrvRecalc, 0x8000,
|
||||
512, 448, 4, 3
|
||||
};
|
||||
|
|
|
@ -16,7 +16,6 @@ Input* input_init(Snes* snes, int8_t tag) {
|
|||
input->portTag = tag; // 1, 2, ...
|
||||
input->type = DEVICE_GAMEPAD;
|
||||
input->currentState = 0;
|
||||
// TODO: handle I/O line (and latching of PPU)
|
||||
return input;
|
||||
}
|
||||
|
||||
|
@ -30,11 +29,11 @@ void input_reset(Input* input) {
|
|||
input->currentState = 0;
|
||||
input->lastX = 0;
|
||||
input->lastY = 0;
|
||||
input->mouseSens = 0;
|
||||
input->devParam = 0;
|
||||
}
|
||||
|
||||
void input_handleState(Input* input, StateHandler* sh) {
|
||||
sh_handleBytes(sh, &input->type, &input->lastX, &input->lastY, &input->mouseSens, NULL);
|
||||
sh_handleBytes(sh, &input->type, &input->lastX, &input->lastY, &input->devParam, NULL);
|
||||
sh_handleBools(sh, &input->latchLine, NULL);
|
||||
sh_handleInts(sh, &input->currentState, &input->latchedState, NULL);
|
||||
}
|
||||
|
@ -54,22 +53,27 @@ void input_setMouse(Input* input, int16_t x, int16_t y, uint8_t buttonA, uint8_t
|
|||
x = d_min(d_abs(x), 0x7f);
|
||||
y = d_min(d_abs(y), 0x7f);
|
||||
input->currentState = 0;
|
||||
input->currentState |= (0x01 | (input->mouseSens % 3) << 4 | (buttonA) << 6 | (buttonB) << 7) << 16;
|
||||
input->currentState |= (0x01 | (input->devParam % 3) << 4 | (buttonA) << 6 | (buttonB) << 7) << 16;
|
||||
input->currentState |= (y | input->lastY) << 8;
|
||||
input->currentState |= (x | input->lastX) << 0;
|
||||
}
|
||||
|
||||
static void update_mouse_sensitivity(Input* input) {
|
||||
input->currentState = (input->currentState & ~0x300000) | ((input->mouseSens % 3) << (4 + 16));
|
||||
input->currentState = (input->currentState & ~0x300000) | ((input->devParam % 3) << (4 + 16));
|
||||
}
|
||||
|
||||
void input_latch(Input* input, bool value) {
|
||||
// if(input->latchLine && !value) {
|
||||
if(value) {
|
||||
input->latchedState = input->currentState;
|
||||
if (input->type == DEVICE_MOUSE) {
|
||||
if (input->type == DEVICE_MOUSE) {
|
||||
update_mouse_sensitivity(input);
|
||||
}
|
||||
} else
|
||||
if (input->type == DEVICE_JUSTIFIER) {
|
||||
// every other read selects between p1/p2's gun. they're daisy-chained,
|
||||
// and plugged into port 2 on the snes/sfc
|
||||
input->devParam ^= 1;
|
||||
input->latchedState |= (input->devParam & 1) << 3;
|
||||
}
|
||||
}
|
||||
input->latchLine = value;
|
||||
}
|
||||
|
@ -88,9 +92,10 @@ uint8_t input_read(Input* input) {
|
|||
if (input->latchLine) {
|
||||
// fun feature: reading the mouse while latched changes the sensitivty
|
||||
// setting
|
||||
update_mouse_sensitivity(input);
|
||||
input->mouseSens++;
|
||||
}
|
||||
update_mouse_sensitivity(input);
|
||||
input->devParam++;
|
||||
} // fallthrough!
|
||||
case DEVICE_JUSTIFIER: // below is shared w/DEVICE_MOUSE
|
||||
ret = (input->latchedState >> 31) & 1;
|
||||
input->latchedState <<= 1;
|
||||
input->latchedState |= 1;
|
||||
|
|
|
@ -10,8 +10,9 @@ typedef struct Input Input;
|
|||
#include "snes.h"
|
||||
#include "statehandler.h"
|
||||
|
||||
enum { DEVICE_NONE = 0, DEVICE_GAMEPAD = 1, DEVICE_SUPERSCOPE = 2, DEVICE_MOUSE = 3 };
|
||||
enum { DEVICE_NONE = 0, DEVICE_GAMEPAD = 1, DEVICE_SUPERSCOPE = 2, DEVICE_MOUSE = 3, DEVICE_JUSTIFIER = 4 };
|
||||
enum { SCOPE_FIRE = 1 << 0, SCOPE_CURSOR = 1 << 1, SCOPE_TURBO = 1 << 2, SCOPE_PAUSE = 1 << 3, SCOPE_RELOAD = 1 << 6 };
|
||||
enum { JUSTI_FIRE1 = 1 << 7, JUSTI_FIRE2 = 1 << 6 };
|
||||
|
||||
struct Input {
|
||||
Snes* snes;
|
||||
|
@ -24,7 +25,7 @@ struct Input {
|
|||
uint32_t latchedState;
|
||||
// for mouse
|
||||
uint8_t lastX, lastY;
|
||||
uint8_t mouseSens;
|
||||
uint8_t devParam; // mouse: sensitivity setting, gun: Justifier ID
|
||||
};
|
||||
|
||||
Input* input_init(Snes* snes, int8_t tag);
|
||||
|
|
|
@ -91,6 +91,7 @@ void snes_runSpcCycle(Snes* snes);
|
|||
bool snes_loadRom(Snes* snes, const uint8_t* data, int length, uint8_t* biosdata, int bioslength);
|
||||
void snes_setButtonState(Snes* snes, int player, int button, int pressed, int device);
|
||||
void snes_setMouseState(Snes* snes, int player, int16_t x, int16_t y, uint8_t buttonA, uint8_t buttonB);
|
||||
void snes_setGunState(Snes* snes, int x1, int y1, int x2, int y2);
|
||||
void snes_setPixels(Snes* snes, uint8_t* pixelData, int height);
|
||||
void snes_setSamples(Snes* snes, int16_t* sampleData, int samplesPerFrame);
|
||||
int snes_saveBattery(Snes* snes, uint8_t* data);
|
||||
|
|
|
@ -73,7 +73,7 @@ bool snes_loadRom(Snes* snes, const uint8_t* data, int length, uint8_t* biosdata
|
|||
max = headers[i].score;
|
||||
used = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
bprintf(0, _T("header used %d\n"), used);
|
||||
if(used & 1) {
|
||||
// odd-numbered ones are for headered roms
|
||||
|
@ -197,34 +197,50 @@ bool snes_isPal(Snes* snes) {
|
|||
}
|
||||
|
||||
void snes_setButtonState(Snes* snes, int player, int button, int pressed, int device) {
|
||||
// set key in controller
|
||||
Input* input = (player == 1) ? snes->input1 : snes->input2;
|
||||
uint32_t *c_state = &input->currentState;
|
||||
// set key in controller
|
||||
Input* input = (player == 1) ? snes->input1 : snes->input2;
|
||||
uint32_t *c_state = &input->currentState;
|
||||
|
||||
input_setType(input, device);
|
||||
input_setType(input, device);
|
||||
|
||||
if(pressed) {
|
||||
*c_state |= 1 << button;
|
||||
} else {
|
||||
*c_state &= ~(1 << button);
|
||||
if(pressed) {
|
||||
*c_state |= 1 << button;
|
||||
} else {
|
||||
*c_state &= ~(1 << button);
|
||||
}
|
||||
}
|
||||
|
||||
#define is_gun_offscreen(x,y) (!(x == 0 || x == 255 || y == 0 || y == 255) )
|
||||
|
||||
void snes_setGunState(Snes* snes, int x1, int y1, int x2, int y2) {
|
||||
// set gun coords
|
||||
Input* input = snes->input2; // gun always in input 2
|
||||
uint32_t *c_state = &input->currentState;
|
||||
|
||||
switch (input->type) {
|
||||
case DEVICE_SUPERSCOPE:
|
||||
*c_state |= 0xff00;
|
||||
if (*c_state & SCOPE_FIRE || *c_state & SCOPE_CURSOR) {
|
||||
ppu_latchScope(x1, y1);
|
||||
}
|
||||
break;
|
||||
case DEVICE_JUSTIFIER:
|
||||
*c_state |= 0xe5500; // Justifier serial bit stream "header"
|
||||
|
||||
switch (input->devParam & 1) {
|
||||
case 0:
|
||||
if (is_gun_offscreen(x2, y2)) {
|
||||
ppu_latchScope(x2, y2);
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
if (is_gun_offscreen(x1, y1)) {
|
||||
ppu_latchScope(x1, y1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (device == DEVICE_SUPERSCOPE) {
|
||||
static uint8_t button8_9[2] = { 0, 0 };
|
||||
|
||||
switch (button) {
|
||||
case 8:
|
||||
case 9:
|
||||
button8_9[button & 1] = pressed;
|
||||
break;
|
||||
case 11: // last button
|
||||
*c_state |= 0xff00;
|
||||
if (*c_state & SCOPE_FIRE || *c_state & SCOPE_CURSOR) {
|
||||
ppu_latchScope(button8_9[0], button8_9[1]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void snes_setMouseState(Snes* snes, int player, int16_t x, int16_t y, uint8_t buttonA, uint8_t buttonB) {
|
||||
|
|
Loading…
Reference in New Issue