mirror of
https://github.com/libretro/Libretro-Supermodel.git
synced 2026-11-07 11:15:58 -10:00
Add normalized lightgun calibration data
This commit is contained in:
1 parent
476788c4ac
commit
cc21923f58
4 files changed
+132
-9
No files matched your search
@@ -9,13 +9,17 @@ from pathlib import Path
|
||||
|
||||
|
||||
# Every released set for which Automatic Initial NVRAM Setup changes Link Mode,
|
||||
# plus the two released Star Wars Trilogy Arcade sets whose cabinet is forced
|
||||
# to Upright. Prototypes and location tests are intentionally excluded.
|
||||
# the two released Star Wars Trilogy Arcade sets whose cabinet is forced to
|
||||
# Upright, and gun games requiring normalized Service-menu calibration.
|
||||
# Prototypes and location tests are intentionally excluded.
|
||||
GAMES = (
|
||||
"daytona2", "dayto2pe",
|
||||
"dirtdvls", "dirtdvlsu", "dirtdvlsau", "dirtdvlsj", "dirtdvlsg",
|
||||
"harley", "harleya",
|
||||
"lamachin",
|
||||
"lemans24",
|
||||
"lostwsga",
|
||||
"oceanhun", "oceanhuna",
|
||||
"scud", "scudau", "scuddx", "scuddxo", "scudplus", "scudplusa",
|
||||
"skichamp",
|
||||
"spikeofe", "spikeout",
|
||||
@@ -24,7 +28,6 @@ GAMES = (
|
||||
"von2", "von254g", "von2a", "von2o",
|
||||
)
|
||||
|
||||
|
||||
def block_data(blob: bytes, wanted: bytes) -> bytes:
|
||||
offset = 0
|
||||
while offset + 12 <= len(blob):
|
||||
|
||||
@@ -107,6 +107,16 @@ static constexpr Template kTemplates[] = {
|
||||
0x0400, 0x0101, 0x6101, 0x0101, 0x6101, 0x0180, 0xc040, 0xc040,
|
||||
0xc040, 0xc040, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
} },
|
||||
{ "lamachin", {
|
||||
0x4d33, 0x5345, 0x4741, 0x40dc, 0xa310, 0x0470, 0x0001, 0x0401,
|
||||
0x0101, 0x0101, 0x0101, 0x0000, 0x0101, 0x0100, 0x0005, 0x0480,
|
||||
0x0103, 0x0100, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0001, 0x0401, 0x0101, 0x0101, 0x0101,
|
||||
0x0000, 0x0101, 0x0100, 0x0005, 0x0480, 0x0103, 0x0100, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
} },
|
||||
{ "lemans24", {
|
||||
0x4d33, 0x5345, 0x4741, 0x7870, 0xa319, 0x015f, 0x0001, 0x0501,
|
||||
0x0101, 0x0101, 0x0101, 0x0000, 0x0002, 0x0cc0, 0x0005, 0x0070,
|
||||
@@ -117,6 +127,36 @@ static constexpr Template kTemplates[] = {
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x001f, 0xded8, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x001f, 0xded8, 0x0000, 0x0022,
|
||||
} },
|
||||
{ "lostwsga", {
|
||||
0x4d33, 0x5345, 0x4741, 0xeda6, 0xa319, 0x0111, 0x0002, 0x0501,
|
||||
0x0101, 0x0101, 0x0101, 0x0000, 0x0003, 0x0100, 0x0205, 0x0470,
|
||||
0x0100, 0x0100, 0x0000, 0x9001, 0x1001, 0x9001, 0x1001, 0x766e,
|
||||
0xd518, 0xcf0c, 0x7b6c, 0xde1d, 0xc705, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0002, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
} },
|
||||
{ "oceanhun", {
|
||||
0x4d33, 0x5345, 0x4741, 0x8d3b, 0xa110, 0x0360, 0x0001, 0x0002,
|
||||
0x0101, 0x0101, 0x0202, 0x0001, 0x0100, 0x0000, 0x0000, 0x0101,
|
||||
0x0000, 0x0000, 0x0100, 0x80c0, 0x4080, 0xc040, 0x80c0, 0x4080,
|
||||
0xc040, 0x80c0, 0x4080, 0xc040, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0001, 0x0002, 0x0101, 0x0101, 0x0202,
|
||||
0x0001, 0x0100, 0x0000, 0x0000, 0x0101, 0x0000, 0x0000, 0x0100,
|
||||
0x80c0, 0x4080, 0xc040, 0x80c0, 0x4080, 0xc040, 0x80c0, 0x4080,
|
||||
0xc040, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
} },
|
||||
{ "oceanhuna", {
|
||||
0x4d33, 0x5345, 0x4741, 0x8d3b, 0xa110, 0x0360, 0x0001, 0x0002,
|
||||
0x0101, 0x0101, 0x0202, 0x0001, 0x0100, 0x0000, 0x0000, 0x0101,
|
||||
0x0000, 0x0000, 0x0100, 0x80c0, 0x4080, 0xc040, 0x80c0, 0x4080,
|
||||
0xc040, 0x80c0, 0x4080, 0xc040, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0000, 0x0000, 0x0001, 0x0002, 0x0101, 0x0101, 0x0202,
|
||||
0x0001, 0x0100, 0x0000, 0x0000, 0x0101, 0x0000, 0x0000, 0x0100,
|
||||
0x80c0, 0x4080, 0xc040, 0x80c0, 0x4080, 0xc040, 0x80c0, 0x4080,
|
||||
0xc040, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||
} },
|
||||
{ "scud", {
|
||||
0x4d33, 0x5345, 0x4741, 0x18e8, 0xa218, 0x0103, 0x0001, 0x0001,
|
||||
0xffff, 0xff01, 0x0101, 0x0001, 0x0000, 0x0000, 0x0000, 0x0100,
|
||||
|
||||
@@ -21,6 +21,7 @@ enum class Setting : unsigned {
|
||||
Vocal,
|
||||
LeverFeedback,
|
||||
DefaultView,
|
||||
ProvideCalibrationData,
|
||||
Count,
|
||||
};
|
||||
|
||||
@@ -37,6 +38,8 @@ enum Capability : unsigned {
|
||||
Vocal = 1u << static_cast<unsigned>(Setting::Vocal),
|
||||
LeverFeedback = 1u << static_cast<unsigned>(Setting::LeverFeedback),
|
||||
DefaultView = 1u << static_cast<unsigned>(Setting::DefaultView),
|
||||
ProvideCalibrationData =
|
||||
1u << static_cast<unsigned>(Setting::ProvideCalibrationData),
|
||||
};
|
||||
|
||||
constexpr unsigned CapabilityFor(Setting setting)
|
||||
@@ -110,17 +113,21 @@ inline const SupportedGame *GetSupportedGames(size_t &count)
|
||||
{ "harleya", "harley",
|
||||
{ "export", "normal", "stand_alone", "1", "deluxe" } },
|
||||
{ "lamachin", nullptr,
|
||||
{ "japan", "level_5", nullptr, nullptr, "standard" } },
|
||||
{ "japan", "level_5", nullptr, nullptr, "standard", nullptr,
|
||||
nullptr, nullptr, nullptr, nullptr, nullptr, "disabled" } },
|
||||
{ "lemans24", nullptr,
|
||||
{ "japan", "level_8", "no_link", "1", "twin_lemans", "none" } },
|
||||
{ "lostwsga", nullptr,
|
||||
{ "japan", "level_8" } },
|
||||
{ "japan", "level_8", nullptr, nullptr, nullptr, nullptr, nullptr,
|
||||
nullptr, nullptr, nullptr, nullptr, "disabled" } },
|
||||
{ "magtruck", nullptr,
|
||||
{ "export", "level_8", nullptr, nullptr, nullptr, nullptr, nullptr, "off" } },
|
||||
{ "oceanhun", nullptr,
|
||||
{ "japan", "normal", nullptr, nullptr, "deluxe" } },
|
||||
{ "japan", "normal", nullptr, nullptr, "deluxe", nullptr, nullptr,
|
||||
nullptr, nullptr, nullptr, nullptr, "disabled" } },
|
||||
{ "oceanhuna", "oceanhun",
|
||||
{ "japan", "normal", nullptr, nullptr, "deluxe" } },
|
||||
{ "japan", "normal", nullptr, nullptr, "deluxe", nullptr, nullptr,
|
||||
nullptr, nullptr, nullptr, nullptr, "disabled" } },
|
||||
{ "scud", nullptr,
|
||||
{ "japan", "normal", "single", "1", "twin" } },
|
||||
{ "scudau", "scud",
|
||||
@@ -147,10 +154,10 @@ inline const SupportedGame *GetSupportedGames(size_t &count)
|
||||
nullptr, nullptr, nullptr, nullptr, "driver" } },
|
||||
{ "swtrilgy", nullptr,
|
||||
{ "export", "normal", nullptr, nullptr, "upright", nullptr, nullptr,
|
||||
nullptr, nullptr, "enable" } },
|
||||
nullptr, nullptr, "enable", nullptr, "disabled" } },
|
||||
{ "swtrilgya", "swtrilgy",
|
||||
{ "export", "normal", nullptr, nullptr, "upright", nullptr, nullptr,
|
||||
nullptr, nullptr, "enable" } },
|
||||
nullptr, nullptr, "enable", nullptr, "disabled" } },
|
||||
{ "vf3", nullptr,
|
||||
{ "japan", "normal" } },
|
||||
{ "vf3a", "vf3",
|
||||
@@ -210,6 +217,7 @@ inline const char *GetDefaultValue(const Game *game, Setting setting)
|
||||
|
||||
struct Selection {
|
||||
const char *values[static_cast<unsigned>(Setting::Count)] = {};
|
||||
bool normalizeAnalogInputs = false;
|
||||
|
||||
const char *Get(Setting setting) const
|
||||
{
|
||||
@@ -218,6 +226,8 @@ struct Selection {
|
||||
|
||||
bool HasAny() const
|
||||
{
|
||||
if (normalizeAnalogInputs)
|
||||
return true;
|
||||
for (const char *value : values)
|
||||
if (value)
|
||||
return true;
|
||||
@@ -476,6 +486,8 @@ NVRAM_VALUES(kLeverFeedback,
|
||||
{ "enable", "ON", 1 }, { "disable", "Disable", 0 });
|
||||
NVRAM_VALUES(kDefaultView,
|
||||
{ "driver", "Driver", 0 }, { "behind", "Behind", 0x0004 });
|
||||
NVRAM_VALUES(kProvideCalibrationData,
|
||||
{ "disabled", "OFF", 0 }, { "enabled", "ON", 1 });
|
||||
|
||||
NVRAM_INFO(kCountryInfoJuea0, Setting::Country, "Country", "Set the machine country stored in NVRAM.", kCountryJuea0);
|
||||
NVRAM_INFO(kCountryInfoJuea1, Setting::Country, "Country", "Set the machine country stored in NVRAM.", kCountryJuea1);
|
||||
@@ -527,6 +539,10 @@ NVRAM_INFO(kChristmasInfo, Setting::ChristmasMode, "Christmas Mode", "Set Magica
|
||||
NVRAM_INFO(kVocalInfo, Setting::Vocal, "Vocal", "Select the Daytona USA 2 vocal version stored in NVRAM.", kVocal);
|
||||
NVRAM_INFO(kLeverFeedbackInfo, Setting::LeverFeedback, "Lever Feedback", "Enable or disable Star Wars Trilogy Arcade's Deluxe cabinet lever feedback stored in NVRAM.", kLeverFeedback);
|
||||
NVRAM_INFO(kDefaultViewInfo, Setting::DefaultView, "Default View", "Select Sega Rally 2's default driving view stored in NVRAM.", kDefaultView);
|
||||
NVRAM_INFO(kProvideCalibrationDataInfo, Setting::ProvideCalibrationData,
|
||||
"Provide Calibration Data",
|
||||
"Apply validated title-specific calibration data at startup, overwriting calibration stored by the Service Menu.",
|
||||
kProvideCalibrationData);
|
||||
|
||||
#undef NVRAM_INFO
|
||||
#undef NVRAM_VALUES
|
||||
@@ -641,6 +657,15 @@ inline const SettingInfo *GetSettingInfo(const Game *game, Setting setting)
|
||||
return family == Family::StarWars ? &kLeverFeedbackInfo : nullptr;
|
||||
case Setting::DefaultView:
|
||||
return family == Family::SegaRally2 ? &kDefaultViewInfo : nullptr;
|
||||
case Setting::ProvideCalibrationData:
|
||||
switch (family)
|
||||
{
|
||||
case Family::Lamachin:
|
||||
case Family::LostWorld:
|
||||
case Family::OceanHunter:
|
||||
case Family::StarWars: return &kProvideCalibrationDataInfo;
|
||||
default: return nullptr;
|
||||
}
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
@@ -755,6 +780,7 @@ inline const char *OptionSuffix(Setting setting)
|
||||
"vocal",
|
||||
"lever_feedback",
|
||||
"default_view",
|
||||
"provide_calibration_data",
|
||||
};
|
||||
return suffixes[static_cast<unsigned>(setting)];
|
||||
}
|
||||
@@ -843,6 +869,9 @@ inline ApplyResult Apply(const Game &game, uint16_t *words,
|
||||
};
|
||||
|
||||
uint16_t value = 0;
|
||||
const bool provideCalibrationData =
|
||||
SelectedValue(game, Setting::ProvideCalibrationData, selection, value) &&
|
||||
value != 0;
|
||||
switch (family)
|
||||
{
|
||||
case Family::Bass:
|
||||
@@ -906,6 +935,15 @@ inline ApplyResult Apply(const Game &game, uint16_t *words,
|
||||
if (SelectedValue(game, Setting::Country, selection, value)) replaceHigh(words[12], value);
|
||||
if (SelectedValue(game, Setting::Difficulty, selection, value)) replaceMasked(words[15], 0x00e0, value);
|
||||
if (SelectedValue(game, Setting::Cabinet, selection, value)) replaceHigh(words[14], value);
|
||||
if (selection.normalizeAnalogInputs || provideCalibrationData)
|
||||
{
|
||||
// Service-menu P1/P2 X/Y calibration: complete 00-FF range in the
|
||||
// primary settings block and its redundant copy.
|
||||
for (unsigned word = 19; word <= 22; ++word)
|
||||
replaceMasked(words[word], 0xffff, 0xff00);
|
||||
for (unsigned word = 48; word <= 51; ++word)
|
||||
replaceMasked(words[word], 0xffff, 0xff00);
|
||||
}
|
||||
break;
|
||||
case Family::LeMans24:
|
||||
if (SelectedValue(game, Setting::Country, selection, value)) replaceHigh(words[12], value);
|
||||
@@ -918,6 +956,19 @@ inline ApplyResult Apply(const Game &game, uint16_t *words,
|
||||
case Family::LostWorld:
|
||||
if (SelectedValue(game, Setting::Country, selection, value)) replaceHigh(words[12], value);
|
||||
if (SelectedValue(game, Setting::Difficulty, selection, value)) replaceMasked(words[15], 0x00f0, value);
|
||||
if (selection.normalizeAnalogInputs || provideCalibrationData)
|
||||
{
|
||||
// Five-point Service-menu calibration reduced by the game to center and
|
||||
// endpoint values for each axis. Apply the same normalized F4/80/0B
|
||||
// calibration to both players; counters and transient records are not
|
||||
// copied from the captured samples.
|
||||
replaceMasked(words[23], 0xffff, 0x8080); // P1 X/Y center
|
||||
replaceMasked(words[24], 0xffff, 0xf40b); // P1 X endpoints
|
||||
replaceMasked(words[25], 0xffff, 0xf40b); // P1 Y endpoints
|
||||
replaceMasked(words[26], 0xffff, 0x8080); // P2 X/Y center
|
||||
replaceMasked(words[27], 0xffff, 0xf40b); // P2 X endpoints
|
||||
replaceMasked(words[28], 0xffff, 0xf40b); // P2 Y endpoints
|
||||
}
|
||||
break;
|
||||
case Family::MagTruck:
|
||||
if (SelectedValue(game, Setting::Country, selection, value)) replaceHigh(words[12], value);
|
||||
@@ -935,6 +986,23 @@ inline ApplyResult Apply(const Game &game, uint16_t *words,
|
||||
replaceHigh(words[15], value), replaceHigh(words[44], value);
|
||||
if (SelectedValue(game, Setting::Cabinet, selection, value))
|
||||
replaceHigh(words[16], value), replaceHigh(words[45], value);
|
||||
if (selection.normalizeAnalogInputs || provideCalibrationData)
|
||||
{
|
||||
// Service-menu calibration for P1/P2 X/Y: center 80, complete 00-FF
|
||||
// range. Preserve the unused third analog channel in each player group.
|
||||
replaceMasked(words[19], 0xffff, 0x80ff);
|
||||
replaceMasked(words[20], 0xffff, 0x0080);
|
||||
replaceMasked(words[21], 0xffff, 0xff00);
|
||||
replaceMasked(words[24], 0xffff, 0xff00);
|
||||
replaceMasked(words[25], 0xffff, 0x80ff);
|
||||
replaceMasked(words[26], 0xffff, 0x0080);
|
||||
replaceMasked(words[48], 0xffff, 0x80ff);
|
||||
replaceMasked(words[49], 0xffff, 0x0080);
|
||||
replaceMasked(words[50], 0xffff, 0xff00);
|
||||
replaceMasked(words[53], 0xffff, 0xff00);
|
||||
replaceMasked(words[54], 0xffff, 0x80ff);
|
||||
replaceMasked(words[55], 0xffff, 0x0080);
|
||||
}
|
||||
break;
|
||||
case Family::Scud:
|
||||
if (SelectedValue(game, Setting::Country, selection, value))
|
||||
@@ -994,6 +1062,13 @@ inline ApplyResult Apply(const Game &game, uint16_t *words,
|
||||
if (SelectedValue(game, Setting::Difficulty, selection, value)) replaceMasked(words[12], 0x0038, value);
|
||||
if (SelectedValue(game, Setting::Cabinet, selection, value)) replaceMasked(words[12], 0x0400, value);
|
||||
if (SelectedValue(game, Setting::LeverFeedback, selection, value)) replaceMasked(words[13], 0x0001, value);
|
||||
if (selection.normalizeAnalogInputs || provideCalibrationData)
|
||||
{
|
||||
// X/Y calibration is stored as minimum, maximum and center values.
|
||||
replaceMasked(words[24], 0xffff, 0x00ff);
|
||||
replaceMasked(words[25], 0xffff, 0x8000);
|
||||
replaceMasked(words[26], 0xffff, 0xff80);
|
||||
}
|
||||
break;
|
||||
case Family::VirtuaFighter3:
|
||||
if (SelectedValue(game, Setting::Difficulty, selection, value)) replaceBackup(122886, value);
|
||||
|
||||
@@ -633,6 +633,11 @@ static NvramPatchResult apply_initial_nvram_settings(void)
|
||||
link_mode);
|
||||
|
||||
const std::string &name = g_active_input_game.name;
|
||||
if (name == "lamachin" || name == "lostwsga" ||
|
||||
name == "oceanhun" || name == "oceanhuna" ||
|
||||
name == "swtrilgy" || name == "swtrilgya")
|
||||
selection.normalizeAnalogInputs = true;
|
||||
|
||||
if (name == "swtrilgy" || name == "swtrilgya")
|
||||
{
|
||||
const auto cabinet = LibretroNvramSettings::Setting::Cabinet;
|
||||
|
||||
Reference in new issue
Block a user