spicetools/games/mga/gunio.cpp

159 lines
4.8 KiB
C++

#include "gunio.h"
#include "util/logging.h"
bool games::mga::SpiceGearGunHandle::open(LPCWSTR lpFileName) {
if (wcscmp(lpFileName, L"COM1") != 0) {
return false;
}
log_info("metalgear", "Opened gun device on COM1");
return true;
}
int games::mga::SpiceGearGunHandle::read(LPVOID lpBuffer, DWORD nNumberOfBytesToRead) {
// minimum buffer size
if ((command == 0u) || nNumberOfBytesToRead < 2)
return 0;
// execute command
int bytes_read = 0;
switch (command) {
case 0x04: // get version
// write version
*((unsigned char *) lpBuffer + bytes_read++) = version;
break;
case 0x08: // get input state
{
// check buffer size
if (nNumberOfBytesToRead < 12)
return 0;
// get cursor position
POINT cursor_pos{};
GetCursorPos(&cursor_pos);
// get screen size
RECT screen_size{};
GetWindowRect(GetDesktopWindow(), &screen_size);
auto screen_width = (unsigned short) (screen_size.right - screen_size.left);
auto screen_height = (unsigned short) (screen_size.bottom - screen_size.top);
// calculate cursor position
p1_x = (unsigned short) (((cursor_pos.x * 1024) / screen_width) % 1024);
p1_y = (unsigned short) (1024 - (((cursor_pos.y * 1024) / screen_height) % 1024));
// gun P1
*((unsigned char *) lpBuffer + bytes_read++) = 0x00;
*((unsigned char *) lpBuffer + bytes_read++) = HIBYTE(p1_x);
*((unsigned char *) lpBuffer + bytes_read++) = LOBYTE(p1_x);
*((unsigned char *) lpBuffer + bytes_read++) = HIBYTE(p1_y);
*((unsigned char *) lpBuffer + bytes_read++) = LOBYTE(p1_y);
bytes_read += 3;
// fill buffer
*((unsigned char *) lpBuffer + bytes_read++) = 0x75;
*((unsigned char *) lpBuffer + bytes_read++) = 0x75;
*((unsigned char *) lpBuffer + bytes_read++) = 0x75;
break;
}
case 0x0C: // not called in game - empty
// empty data
*((unsigned char *) lpBuffer + bytes_read++) = 0x00;
break;
case 0x10: // get DIP switches
// clear bits
*((unsigned char *) lpBuffer + bytes_read) = 0x00;
// set bits
if (frequency == 1)
*((unsigned char *) lpBuffer + bytes_read) |= 0x80;
if (frequency == 2)
*((unsigned char *) lpBuffer + bytes_read) |= 0x40;
if (frequency == 3)
*((unsigned char *) lpBuffer + bytes_read) |= 0x20;
if (frequency == 4)
*((unsigned char *) lpBuffer + bytes_read) |= 0x10;
break;
case 0x14: // frequency 1
// set frequency and return empty data
frequency = 1;
*((unsigned char *) lpBuffer + bytes_read++) = 0x00;
break;
case 0x18: // frequency 2
// set frequency and return empty data
frequency = 2;
*((unsigned char *) lpBuffer + bytes_read++) = 0x00;
break;
case 0x19: // frequency 3
// set frequency and return empty data
frequency = 3;
*((unsigned char *) lpBuffer + bytes_read++) = 0x00;
break;
case 0x1A: // frequency 4
// set frequency and return empty data
frequency = 4;
*((unsigned char *) lpBuffer + bytes_read++) = 0x00;
break;
case 0x1C: // led board check
// check buffer size
if (nNumberOfBytesToRead < 11)
return 0;
// set all bits
memset(lpBuffer, 0xFF, 10);
bytes_read += 10;
break;
default:
log_warning("metalgear", "unknown opcode: 0x{:02X}", command);
*((unsigned char *) lpBuffer + bytes_read++) = 0x01;
}
// reset command
command = 0;
// calculate checksum
unsigned char checksum = 0xFF;
for (int i = 0; i < bytes_read; i++)
checksum -= *((unsigned char *) lpBuffer + i);
*((unsigned char *) lpBuffer + bytes_read++) = checksum;
// return amount of bytes read
return bytes_read;
}
int games::mga::SpiceGearGunHandle::write(LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite) {
// save command
if (nNumberOfBytesToWrite > 0)
command = *((unsigned char *) lpBuffer);
return (int) nNumberOfBytesToWrite;
}
int games::mga::SpiceGearGunHandle::device_io(DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize,
LPVOID lpOutBuffer, DWORD nOutBufferSize) {
return -1;
}
bool games::mga::SpiceGearGunHandle::close() {
log_info("metalgear", "Closed gun device on COM1");
return true;
}