mirror of
https://github.com/RetroDECK/Supermodel.git
synced 2024-11-22 22:05:38 +00:00
08d4735ee8
-Separate each possible boards (wheel, joystick, skipad, billboard). -Defined a Driveboard type in Games.xml for each games. -Due to the refactoring, Driveboard Savestates have changed (a common base data + a specific board data are saved). -Backwards compatibility with previous save states is maintained. -Driveboard rom section is no longer required anymore. This disables Driveboard emulation in case the rom is not found. -Added Billboard emulation (vf3, vs2, fvipers2, von2). 7 segments and lamps Outputs are redirected to Supermodel outputs. -Changes project to C++ 17 standard.
267 lines
5.9 KiB
C++
267 lines
5.9 KiB
C++
/**
|
|
** Supermodel
|
|
** A Sega Model 3 Arcade Emulator.
|
|
** Copyright 2011-2021 Bart Trzynadlowski, Nik Henson, Ian Curtis,
|
|
** Harry Tuttle, and Spindizzi
|
|
**
|
|
** This file is part of Supermodel.
|
|
**
|
|
** Supermodel is free software: you can redistribute it and/or modify it under
|
|
** the terms of the GNU General Public License as published by the Free
|
|
** Software Foundation, either version 3 of the License, or (at your option)
|
|
** any later version.
|
|
**
|
|
** Supermodel is distributed in the hope that it will be useful, but WITHOUT
|
|
** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
** FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
** more details.
|
|
**
|
|
** You should have received a copy of the GNU General Public License along
|
|
** with Supermodel. If not, see <http://www.gnu.org/licenses/>.
|
|
**/
|
|
|
|
/*
|
|
* SkiBoard.cpp
|
|
*
|
|
* Implementation of the CSkiBoard class: rumble ski pad emulation
|
|
* emulation.
|
|
*
|
|
* NOTE: Simulation does not yet work. Drive board ROMs are required.
|
|
*/
|
|
|
|
#include "Supermodel.h"
|
|
|
|
#include <cstdio>
|
|
#include <cmath>
|
|
#include <algorithm>
|
|
|
|
Game::DriveBoardType CSkiBoard::GetType(void)
|
|
{
|
|
return Game::DRIVE_BOARD_SKI;
|
|
}
|
|
|
|
unsigned CSkiBoard::GetForceFeedbackStrength()
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
void CSkiBoard::SetForceFeedbackStrength(unsigned strength)
|
|
{
|
|
|
|
}
|
|
|
|
void CSkiBoard::LoadState(CBlockFile *SaveState)
|
|
{
|
|
CDriveBoard::LoadState(SaveState);
|
|
|
|
if (!IsDisabled())
|
|
SendVibrate(0);
|
|
}
|
|
|
|
void CSkiBoard::Disable(void)
|
|
{
|
|
SendVibrate(0);
|
|
CDriveBoard::Disable();
|
|
}
|
|
|
|
bool CSkiBoard::Init(const UINT8 *romPtr)
|
|
{
|
|
bool result = CDriveBoard::Init(romPtr);
|
|
m_simulated = true;
|
|
return result;
|
|
}
|
|
|
|
void CSkiBoard::Reset(void)
|
|
{
|
|
CDriveBoard::Reset();
|
|
m_lastVibrate = 0;
|
|
|
|
if (!m_config["ForceFeedback"].ValueAsDefault<bool>(false))
|
|
Disable();
|
|
|
|
// Stop any effects that may still be playing
|
|
if (!IsDisabled())
|
|
SendVibrate(0);
|
|
}
|
|
|
|
UINT8 CSkiBoard::Read(void)
|
|
{
|
|
if (IsDisabled())
|
|
{
|
|
return 0xFF;
|
|
}
|
|
|
|
// TODO - simulate initialization sequence even when emulating to get rid of long pause at boot up (drive board can
|
|
// carry on booting whilst game starts)
|
|
return SimulateRead();
|
|
}
|
|
|
|
void CSkiBoard::Write(UINT8 data)
|
|
{
|
|
if (IsDisabled())
|
|
{
|
|
return;
|
|
}
|
|
|
|
//if (data >= 0x01 && data <= 0x0F ||
|
|
// data >= 0x20 && data <= 0x2F ||
|
|
// data >= 0x30 && data <= 0x3F ||
|
|
// data >= 0x40 && data <= 0x4F ||
|
|
// data >= 0x70 && data <= 0x7F)
|
|
// DebugLog("DriveBoard.Write(%02X)\n", data);
|
|
if (m_simulated)
|
|
SimulateWrite(data);
|
|
}
|
|
|
|
UINT8 CSkiBoard::SimulateRead(void)
|
|
{
|
|
if (m_initialized)
|
|
{
|
|
switch (m_readMode)
|
|
{
|
|
case 0x0: return m_statusFlags; // Status flags
|
|
case 0x1: return m_dip1; // DIP switch 1 value
|
|
case 0x2: return m_dip2; // DIP switch 2 value
|
|
case 0x3: return m_wheelCenter; // Wheel center
|
|
case 0x4: return 0x80; // Cockpit banking center
|
|
case 0x5: return m_inputs->skiX->value; // Wheel position
|
|
case 0x6: return 0x80; // Cockpit banking position
|
|
case 0x7: return m_echoVal; // Init status/echo test
|
|
default: return 0xFF;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
switch (m_initState / 5)
|
|
{
|
|
case 0: return 0xCF; // Initiate start
|
|
case 1: return 0xCE;
|
|
case 2: return 0xCD;
|
|
case 3: return 0xCC; // Centering wheel
|
|
default:
|
|
m_initialized = true;
|
|
return 0x80;
|
|
}
|
|
}
|
|
}
|
|
|
|
void CSkiBoard::SimulateWrite(UINT8 cmd)
|
|
{
|
|
// Following are commands for Scud Race. Daytona 2 has a compatible command set while Sega Rally 2 is completely different
|
|
// TODO - finish for Scud Race and Daytona 2
|
|
// TODO - implement for Sega Rally 2
|
|
UINT8 type = cmd>>4;
|
|
UINT8 val = cmd&0xF;
|
|
|
|
// Ski Champ vibration pad
|
|
|
|
switch (type)
|
|
{
|
|
case 0x00: // nothing to do ?
|
|
break;
|
|
case 0x01: // full stop ?
|
|
if (val == 0)
|
|
SendVibrate(0);
|
|
break;
|
|
case 0x04:
|
|
SendVibrate(val*0x11);
|
|
break;
|
|
case 0x08:
|
|
if (val == 0x08)
|
|
{
|
|
// test driveboard passed ?
|
|
}
|
|
break;
|
|
case 0x0A: // only when test in service menu
|
|
switch (val)
|
|
{
|
|
case 3: // clutch
|
|
break;
|
|
case 5: // motor test
|
|
SendVibrate(val * 0x11);
|
|
break;
|
|
case 6: // end motor test
|
|
SendVibrate(0);
|
|
break;
|
|
}
|
|
break;
|
|
case 0x0C: // game state or reset driveboard ?
|
|
switch (val)
|
|
{
|
|
case 1:
|
|
// in game
|
|
break;
|
|
case 2:
|
|
// game ready
|
|
break;
|
|
case 3:
|
|
// test mode
|
|
break;
|
|
}
|
|
break;
|
|
case 0x0D: // 0xD0-DF Set read mode
|
|
m_readMode = val & 0x7;
|
|
break;
|
|
default:
|
|
//DebugLog("Skipad unknown command %02X , val= %02X\n",type,val);
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
void CSkiBoard::RunFrame(void)
|
|
{
|
|
if (m_simulated)
|
|
{
|
|
if (!m_initialized)
|
|
m_initState++;
|
|
}
|
|
}
|
|
|
|
UINT8 CSkiBoard::Read8(UINT32 addr)
|
|
{
|
|
return 0xFF;
|
|
}
|
|
|
|
void CSkiBoard::Write8(UINT32 addr, UINT8 data)
|
|
{
|
|
}
|
|
|
|
void CSkiBoard::SendVibrate(UINT8 val)
|
|
{
|
|
if (val == m_lastVibrate)
|
|
return;
|
|
/*
|
|
if (val == 0)
|
|
DebugLog(">> Stop Vibrate\n");
|
|
else
|
|
DebugLog(">> Vibrate %02X\n", val);
|
|
*/
|
|
|
|
ForceFeedbackCmd ffCmd;
|
|
ffCmd.id = FFVibrate;
|
|
ffCmd.force = (float)val / 255.0f;
|
|
m_inputs->skiX->SendForceFeedbackCmd(ffCmd);
|
|
|
|
m_lastVibrate = val;
|
|
}
|
|
|
|
|
|
CSkiBoard::CSkiBoard(const Util::Config::Node& config)
|
|
: CDriveBoard(config),
|
|
m_lastVibrate(0)
|
|
{
|
|
m_attached = false;
|
|
m_simulated = false;
|
|
m_initialized = false;
|
|
m_dip1 = 0xCF;
|
|
m_dip2 = 0xFF;
|
|
|
|
DebugLog("Built Drive Board (ski pad)\n");
|
|
}
|
|
|
|
CSkiBoard::~CSkiBoard(void)
|
|
{
|
|
|
|
}
|