Initial re-upload of spice2x-24-08-24

This commit is contained in:
2024-08-28 11:10:34 -04:00
commit caa9e02285
1181 changed files with 380065 additions and 0 deletions

158
games/mga/gunio.cpp Normal file
View File

@@ -0,0 +1,158 @@
#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;
}

29
games/mga/gunio.h Normal file
View File

@@ -0,0 +1,29 @@
#pragma once
#include "hooks/devicehook.h"
namespace games::mga {
// Team FrontLine GUN IO
class SpiceGearGunHandle : public CustomHandle {
private:
unsigned char version = 62;
unsigned char command = 0x00;
unsigned short p1_x = 0;
unsigned short p1_y = 0;
int frequency = 1;
public:
bool open(LPCWSTR lpFileName) override;
int read(LPVOID lpBuffer, DWORD nNumberOfBytesToRead) override;
int write(LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite) override;
int device_io(DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize, LPVOID lpOutBuffer,
DWORD nOutBufferSize) override;
bool close() override;
};
}

73
games/mga/io.cpp Normal file
View File

@@ -0,0 +1,73 @@
#include "io.h"
std::vector<Button> &games::mga::get_buttons() {
static std::vector<Button> buttons;
if (buttons.empty()) {
buttons = GameAPI::Buttons::getButtons("Metal Gear");
GameAPI::Buttons::sortButtons(
&buttons,
"Service",
"Test",
"Coin Mech",
"Start",
"Top",
"Front Top",
"Front Bottom",
"Side Left",
"Side Right",
"Side Lever",
"Trigger Button",
"Switch Button",
"Joy Forwards",
"Joy Backwards",
"Joy Left",
"Joy Right"
);
}
return buttons;
}
std::vector<Analog> &games::mga::get_analogs() {
static std::vector<Analog> analogs;
if (analogs.empty()) {
analogs = GameAPI::Analogs::getAnalogs("Metal Gear");
GameAPI::Analogs::sortAnalogs(
&analogs,
"Joy X",
"Joy Y"
);
}
return analogs;
}
std::vector<Light> &games::mga::get_lights() {
static std::vector<Light> lights;
if (lights.empty()) {
lights = GameAPI::Lights::getLights("Metal Gear");
GameAPI::Lights::sortLights(
&lights,
"Start",
"Left R",
"Left G",
"Left B",
"Right R",
"Right G",
"Right B",
"Gun R",
"Gun G",
"Gun B",
"Gun Vibration"
);
}
return lights;
}

59
games/mga/io.h Normal file
View File

@@ -0,0 +1,59 @@
#pragma once
#include <vector>
#include "cfg/api.h"
namespace games::mga {
// all buttons in correct order
namespace Buttons {
enum {
Service,
Test,
CoinMech,
Start,
Top,
FrontTop,
FrontBottom,
SideLeft,
SideRight,
SideLever,
TriggerButton,
SwitchButton,
JoyForwards,
JoyBackwards,
JoyLeft,
JoyRight,
};
}
// all analogs in correct order
namespace Analogs {
enum {
JoyX,
JoyY,
};
}
// all lights in correct order
namespace Lights {
enum {
Start,
LeftR,
LeftG,
LeftB,
RightR,
RightG,
RightB,
GunR,
GunG,
GunB,
GunVibration,
};
}
// getters
std::vector<Button> &get_buttons();
std::vector<Analog> &get_analogs();
std::vector<Light> &get_lights();
}

82
games/mga/mga.cpp Normal file
View File

@@ -0,0 +1,82 @@
#include "mga.h"
#include "acio/icca/icca.h"
#include "hooks/devicehook.h"
#include "util/detour.h"
#include "util/libutils.h"
#include "util/logging.h"
#include "util/detour.h"
#include "util/sigscan.h"
#include "gunio.h"
namespace games::mga {
void (__cdecl *ess_eventlog_request_error_orig)(const char *, unsigned int, int, int);
static int __cdecl log_change_level_hook(int level) {
log_misc("mga", "ignoring log_change_level({})", level);
return 1;
}
static uintptr_t __cdecl log_change_output_hook(uintptr_t target, uintptr_t a2) {
log_misc("mga", "ignoring log_change_output(0x{:x}, 0x{:x})", target, a2);
return 0;
}
static bool __cdecl setvolume_hook(uint8_t volume) {
log_misc("mga", "ignoring setvolume {}", static_cast<int>(volume));
return false;
}
static void __cdecl ess_eventlog_request_error_hook(const char *a1, unsigned int a2, int a3, int a4) {
log_info("mga", "ess_eventlog_request_error({}, {}, {}, {})", a1, a2, a3, a4);
//ess_eventlog_request_error_orig(a1, a2, a3, a4);
}
MGAGame::MGAGame() : Game("Metal Gear Arcade") {
}
void MGAGame::attach() {
Game::attach();
// load system.dll (along with the serial functions)
auto system = libutils::load_library("system.dll");
// add the gun
devicehook_init();
devicehook_add(new SpiceGearGunHandle());
// fix ICCA
acio::ICCA_COMPAT_ACTIVE = true;
// ignore sound engine failure
if (!replace_pattern(
system,
"E8????????84C0750A68F4010000E8????????E8????????E8????????3BF3750433C0EB0C",
"??????????????????90909090909090909090????????????????????????????????????",
0, 0))
{
log_warning("mga", "failed to patch sound engine");
}
// hook setvolume
if (!detour::iat_try("?setvolume@@YAHPAD@Z", setvolume_hook)) {
log_warning("mga", "setvolume hook failed");
}
// stop the game from redirecting AVS log calls
detour::iat_try("log_change_level", log_change_level_hook);
detour::iat_try("log_change_output", log_change_output_hook);
ess_eventlog_request_error_orig = detour::iat_try("ess_eventlog_request_error", ess_eventlog_request_error_hook);
}
void MGAGame::detach() {
Game::detach();
devicehook_dispose();
}
}

13
games/mga/mga.h Normal file
View File

@@ -0,0 +1,13 @@
#pragma once
#include "games/game.h"
namespace games::mga {
class MGAGame : public games::Game {
public:
MGAGame();
virtual void attach() override;
virtual void detach() override;
};
}