mirror of
https://github.com/spice2x/spice2x.github.io.git
synced 2026-08-01 14:20:42 -07:00
overlay: small tweaks to auto light matching (#575)
## Link to GitHub Issue or related Pull Request, if one exists #574 ## Description of change * Add binds for Nostroller * Update matching logic to ignore common device-side output names like "Button" "Light" and "LED" (e.g., `Button 1` from a device now matches on `P1 1`) * For RGB matching, in addition to `Light R` on the device also try `LightR` (Nostroller needs this) * Add a confirmation dialog for `Clear All` * Address minor bugs ## Testing Seems to work on arcin, and Nostroller. Still need to retest Faucetwo. Hopefully I didn't break Phoenixwan.
This commit is contained in:
@@ -2416,29 +2416,44 @@ namespace overlay::windows {
|
||||
// clear all
|
||||
ImGui::BeginDisabled(bound.empty());
|
||||
if (ImGui::Button("Clear All")) {
|
||||
if (lights_testing) {
|
||||
if (lights_test_current >= 0 && lights_test_current < (int) bound.size()) {
|
||||
auto &cur = (*lights)[bound[lights_test_current]];
|
||||
GameAPI::Lights::writeLight(RI_MGR, cur, 0.f);
|
||||
RI_MGR->devices_flush_output();
|
||||
}
|
||||
lights_testing = false;
|
||||
lights_test_current = -1;
|
||||
}
|
||||
for (auto &light : *lights) {
|
||||
if (!light.isSet()) {
|
||||
continue;
|
||||
}
|
||||
clear_light(&light, 0);
|
||||
for (int ai = 0; ai < (int) light.getAlternatives().size(); ai++) {
|
||||
clear_light(&light.getAlternatives()[ai], ai + 1);
|
||||
}
|
||||
}
|
||||
ImGui::OpenPopup("Clear all light bindings");
|
||||
}
|
||||
ImGui::EndDisabled();
|
||||
if (ImGui::IsItemHovered(ImGui::TOOLTIP_FLAGS)) {
|
||||
ImGui::SetTooltip("Unbind all lights.");
|
||||
}
|
||||
if (ImGui::BeginPopupModal("Clear all light bindings", nullptr, ImGuiWindowFlags_AlwaysAutoResize)) {
|
||||
ImGui::TextUnformatted("Are you sure? This can't be undone.");
|
||||
ImGui::Spacing();
|
||||
ImGui::Separator();
|
||||
ImGui::Spacing();
|
||||
if (ImGui::Button("Yes")) {
|
||||
if (lights_testing) {
|
||||
if (lights_test_current >= 0 && lights_test_current < (int) bound.size()) {
|
||||
auto &cur = (*lights)[bound[lights_test_current]];
|
||||
GameAPI::Lights::writeLight(RI_MGR, cur, 0.f);
|
||||
RI_MGR->devices_flush_output();
|
||||
}
|
||||
lights_testing = false;
|
||||
lights_test_current = -1;
|
||||
}
|
||||
for (auto &light : *lights) {
|
||||
if (!light.isSet()) {
|
||||
continue;
|
||||
}
|
||||
clear_light(&light, 0);
|
||||
for (int ai = 0; ai < (int) light.getAlternatives().size(); ai++) {
|
||||
clear_light(&light.getAlternatives()[ai], ai + 1);
|
||||
}
|
||||
}
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Cancel")) {
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
|
||||
// test all
|
||||
ImGui::SameLine();
|
||||
@@ -2992,186 +3007,18 @@ namespace overlay::windows {
|
||||
device = auto_match_devices[auto_match_device_selected];
|
||||
}
|
||||
|
||||
struct MatchEntry {
|
||||
std::string game_name;
|
||||
std::string device_name;
|
||||
int light_index;
|
||||
int control_index;
|
||||
bool soft;
|
||||
};
|
||||
std::vector<MatchEntry> matched;
|
||||
std::vector<MatchEntry> unmatched;
|
||||
|
||||
for (int li = 0; li < (int) lights->size(); li++) {
|
||||
matched.push_back({
|
||||
(*lights)[li].getName(), "", li, -1, false
|
||||
});
|
||||
}
|
||||
|
||||
std::vector<MatchEntry> unmatched;
|
||||
std::vector<std::string> raw_names;
|
||||
std::string detected_controller;
|
||||
if (has_device) {
|
||||
// build output name list
|
||||
switch (device->type) {
|
||||
case rawinput::HID: {
|
||||
for (auto &n : device->hidInfo->button_output_caps_names) {
|
||||
raw_names.push_back(n);
|
||||
}
|
||||
for (auto &n : device->hidInfo->value_output_caps_names) {
|
||||
raw_names.push_back(n);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case rawinput::SEXTET_OUTPUT: {
|
||||
for (int i = 0; i < rawinput::SextetDevice::LIGHT_COUNT; i++) {
|
||||
raw_names.emplace_back(
|
||||
rawinput::SextetDevice::LIGHT_NAMES[i]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case rawinput::PIUIO_DEVICE: {
|
||||
for (int i = 0; i < rawinput::PIUIO::PIUIO_MAX_NUM_OF_LIGHTS; i++) {
|
||||
raw_names.emplace_back(
|
||||
rawinput::PIUIO::LIGHT_NAMES[i]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case rawinput::SMX_STAGE: {
|
||||
for (int i = 0; i < rawinput::SmxStageDevice::TOTAL_LIGHT_COUNT; i++) {
|
||||
raw_names.push_back(
|
||||
rawinput::SmxStageDevice::GetLightNameByIndex(i));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case rawinput::SMX_DEDICAB: {
|
||||
for (int i = 0; i < rawinput::SmxDedicabDevice::LIGHTS_COUNT; i++) {
|
||||
raw_names.push_back(
|
||||
rawinput::SmxDedicabDevice::GetLightNameByIndex(i));
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// match by name (hard match, case insensitive, with P1/P2 prefix fallback)
|
||||
std::vector<bool> device_matched(raw_names.size(), false);
|
||||
std::string player_prefix = auto_match_p2 ? "P2 " : "P1 ";
|
||||
auto player_prefix_lower = strtolower(player_prefix);
|
||||
for (auto &entry : matched) {
|
||||
auto game_lower = strtolower(entry.game_name);
|
||||
for (int ci = 0; ci < (int) raw_names.size(); ci++) {
|
||||
if (device_matched[ci]) {
|
||||
continue;
|
||||
}
|
||||
auto dev_lower = strtolower(raw_names[ci]);
|
||||
if (game_lower == dev_lower || game_lower == player_prefix_lower + dev_lower) {
|
||||
entry.device_name = raw_names[ci];
|
||||
entry.control_index = ci;
|
||||
device_matched[ci] = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// soft matching
|
||||
bool is_valkyrie_mode = games::sdvx::is_valkyrie_model();
|
||||
static const char *RGB[] = {" R", " G", " B"};
|
||||
|
||||
// try to match a game light name, first as-is, then with P1/P2 prefix
|
||||
auto try_match = [&](const std::string &game_target, int ci, const char *controller) -> bool {
|
||||
auto target = strtolower(game_target);
|
||||
auto target_player = strtolower(player_prefix + game_target);
|
||||
for (auto &entry : matched) {
|
||||
if (entry.control_index >= 0) {
|
||||
continue;
|
||||
}
|
||||
auto entry_lower = strtolower(entry.game_name);
|
||||
if (entry_lower != target && entry_lower != target_player) {
|
||||
continue;
|
||||
}
|
||||
entry.device_name = raw_names[ci];
|
||||
entry.control_index = ci;
|
||||
entry.soft = true;
|
||||
device_matched[ci] = true;
|
||||
if (detected_controller.empty()) {
|
||||
detected_controller = controller;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
for (int ri = 0; ri < LIGHT_MATCH_MAP_COUNT; ri++) {
|
||||
auto &rule = LIGHT_MATCH_MAP[ri];
|
||||
if (*rule.game && this->games_selected_name != rule.game) {
|
||||
continue;
|
||||
}
|
||||
if (rule.vid && device->hidInfo
|
||||
&& (device->hidInfo->attributes.VendorID != rule.vid
|
||||
|| device->hidInfo->attributes.ProductID != rule.pid)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (*rule.address) {
|
||||
// address mode: match device light at specific index
|
||||
int ci = (int) strtol(rule.address, nullptr, 0);
|
||||
if (ci >= (int) raw_names.size() || device_matched[ci]) {
|
||||
continue;
|
||||
}
|
||||
if (strtolower(raw_names[ci]) != strtolower(std::string(rule.device_light))) {
|
||||
continue;
|
||||
}
|
||||
try_match(rule.game_light, ci, rule.controller);
|
||||
} else if (rule.rgb) {
|
||||
// RGB mode: expand device_light + " R/G/B" + device_suffix
|
||||
const char *game_base = (is_valkyrie_mode && *rule.game_light_alt)
|
||||
? rule.game_light_alt : rule.game_light;
|
||||
if (!*game_base) {
|
||||
continue;
|
||||
}
|
||||
for (int ci = 0; ci < (int) raw_names.size(); ci++) {
|
||||
if (device_matched[ci]) {
|
||||
continue;
|
||||
}
|
||||
auto dev_lower = strtolower(raw_names[ci]);
|
||||
for (int rgb = 0; rgb < 3; rgb++) {
|
||||
auto expected = strtolower(
|
||||
std::string(rule.device_light) + RGB[rgb] + rule.device_suffix);
|
||||
if (dev_lower != expected) {
|
||||
continue;
|
||||
}
|
||||
try_match(std::string(game_base) + RGB[rgb], ci, rule.controller);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// name mode: direct 1:1 device_light → game_light
|
||||
const char *game_base = (is_valkyrie_mode && *rule.game_light_alt)
|
||||
? rule.game_light_alt : rule.game_light;
|
||||
if (!*game_base) {
|
||||
continue;
|
||||
}
|
||||
for (int ci = 0; ci < (int) raw_names.size(); ci++) {
|
||||
if (device_matched[ci]) {
|
||||
continue;
|
||||
}
|
||||
if (strtolower(raw_names[ci]) != strtolower(std::string(rule.device_light))) {
|
||||
continue;
|
||||
}
|
||||
if (try_match(game_base, ci, rule.controller)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// unmatched device lights
|
||||
for (int ci = 0; ci < (int) raw_names.size(); ci++) {
|
||||
if (!device_matched[ci] && strtolower(raw_names[ci]) != "null") {
|
||||
unmatched.push_back({"", raw_names[ci], -1, ci, false});
|
||||
}
|
||||
}
|
||||
detected_controller = match_lights(device, lights, raw_names, matched, unmatched);
|
||||
}
|
||||
|
||||
// partition: matches first, then hard before soft
|
||||
@@ -3553,6 +3400,214 @@ namespace overlay::windows {
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
|
||||
std::string Config::match_lights(
|
||||
rawinput::Device *device,
|
||||
std::vector<Light> *lights,
|
||||
std::vector<std::string> &raw_names,
|
||||
std::vector<MatchEntry> &matched,
|
||||
std::vector<MatchEntry> &unmatched) {
|
||||
|
||||
std::string detected_controller;
|
||||
|
||||
// build output name list
|
||||
switch (device->type) {
|
||||
case rawinput::HID: {
|
||||
for (auto &n : device->hidInfo->button_output_caps_names) {
|
||||
raw_names.push_back(n);
|
||||
}
|
||||
for (auto &n : device->hidInfo->value_output_caps_names) {
|
||||
raw_names.push_back(n);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case rawinput::SEXTET_OUTPUT: {
|
||||
for (int i = 0; i < rawinput::SextetDevice::LIGHT_COUNT; i++) {
|
||||
raw_names.emplace_back(
|
||||
rawinput::SextetDevice::LIGHT_NAMES[i]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case rawinput::PIUIO_DEVICE: {
|
||||
for (int i = 0; i < rawinput::PIUIO::PIUIO_MAX_NUM_OF_LIGHTS; i++) {
|
||||
raw_names.emplace_back(
|
||||
rawinput::PIUIO::LIGHT_NAMES[i]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case rawinput::SMX_STAGE: {
|
||||
for (int i = 0; i < rawinput::SmxStageDevice::TOTAL_LIGHT_COUNT; i++) {
|
||||
raw_names.push_back(
|
||||
rawinput::SmxStageDevice::GetLightNameByIndex(i));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case rawinput::SMX_DEDICAB: {
|
||||
for (int i = 0; i < rawinput::SmxDedicabDevice::LIGHTS_COUNT; i++) {
|
||||
raw_names.push_back(
|
||||
rawinput::SmxDedicabDevice::GetLightNameByIndex(i));
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// match by name (hard match, case insensitive, with P1/P2 prefix fallback)
|
||||
std::vector<bool> device_matched(raw_names.size(), false);
|
||||
const std::string player_prefix = auto_match_p2 ? "p2 " : "p1 ";
|
||||
|
||||
for (auto &entry : matched) {
|
||||
const auto game_lower = strtolower(entry.game_name);
|
||||
|
||||
// match on exact name
|
||||
for (int ci = 0; ci < (int) raw_names.size(); ci++) {
|
||||
if (device_matched[ci]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto dev_lower = strtolower(raw_names[ci]);
|
||||
if (game_lower == dev_lower ||
|
||||
game_lower == player_prefix + dev_lower) {
|
||||
|
||||
entry.device_name = raw_names[ci];
|
||||
entry.control_index = ci;
|
||||
device_matched[ci] = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// raw device name, but stripped of a few common strings, and spaces
|
||||
for (int ci = 0; ci < (int) raw_names.size(); ci++) {
|
||||
if (device_matched[ci]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto dev_stripped = strtolower(raw_names[ci]);;
|
||||
strreplace(dev_stripped, "button", "");
|
||||
strreplace(dev_stripped, "led", "");
|
||||
strreplace(dev_stripped, "light", "");
|
||||
strreplace(dev_stripped, " ", "");
|
||||
|
||||
if (game_lower == dev_stripped ||
|
||||
game_lower == player_prefix + dev_stripped) {
|
||||
|
||||
entry.device_name = raw_names[ci];
|
||||
entry.control_index = ci;
|
||||
device_matched[ci] = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// soft matching
|
||||
const bool is_valkyrie_mode = games::sdvx::is_valkyrie_model();
|
||||
static const char *RGB[] = {"R", "G", "B"};
|
||||
|
||||
// try to match a game light name, first as-is, then with P1/P2 prefix
|
||||
auto try_match = [&](const std::string &game_target, int ci, const char *controller) -> bool {
|
||||
auto target = strtolower(game_target);
|
||||
auto target_player = strtolower(player_prefix + game_target);
|
||||
for (auto &entry : matched) {
|
||||
if (entry.control_index >= 0) {
|
||||
continue;
|
||||
}
|
||||
auto entry_lower = strtolower(entry.game_name);
|
||||
if (entry_lower != target && entry_lower != target_player) {
|
||||
continue;
|
||||
}
|
||||
entry.device_name = raw_names[ci];
|
||||
entry.control_index = ci;
|
||||
entry.soft = true;
|
||||
device_matched[ci] = true;
|
||||
if (detected_controller.empty()) {
|
||||
detected_controller = controller;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
for (int ri = 0; ri < LIGHT_MATCH_MAP_COUNT; ri++) {
|
||||
auto &rule = LIGHT_MATCH_MAP[ri];
|
||||
if (*rule.game && this->games_selected_name != rule.game) {
|
||||
continue;
|
||||
}
|
||||
if (rule.vid && device->hidInfo
|
||||
&& (device->hidInfo->attributes.VendorID != rule.vid
|
||||
|| device->hidInfo->attributes.ProductID != rule.pid)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (*rule.address) {
|
||||
// address mode: match device light at specific index
|
||||
int ci = (int) strtol(rule.address, nullptr, 0);
|
||||
if (ci >= (int) raw_names.size() || device_matched[ci]) {
|
||||
continue;
|
||||
}
|
||||
if (strtolower(raw_names[ci]) != strtolower(std::string(rule.device_light))) {
|
||||
continue;
|
||||
}
|
||||
try_match(rule.game_light, ci, rule.controller);
|
||||
} else if (rule.rgb) {
|
||||
// RGB mode: expand device_light + " R/G/B" + device_suffix
|
||||
const char *game_base = (is_valkyrie_mode && *rule.game_light_alt)
|
||||
? rule.game_light_alt : rule.game_light;
|
||||
if (!*game_base) {
|
||||
continue;
|
||||
}
|
||||
for (int ci = 0; ci < (int) raw_names.size(); ci++) {
|
||||
if (device_matched[ci]) {
|
||||
continue;
|
||||
}
|
||||
auto dev_lower = strtolower(raw_names[ci]);
|
||||
for (int rgb = 0; rgb < 3; rgb++) {
|
||||
// try light name, plus space, plus R/G/B
|
||||
auto expected = strtolower(
|
||||
std::string(rule.device_light) + " " + RGB[rgb] + rule.device_suffix);
|
||||
if (dev_lower == expected) {
|
||||
try_match(std::string(game_base) + " " + RGB[rgb], ci, rule.controller);
|
||||
break;
|
||||
}
|
||||
// try light name, plus R/G/B
|
||||
auto expected2 = strtolower(
|
||||
std::string(rule.device_light) + RGB[rgb] + rule.device_suffix);
|
||||
if (dev_lower == expected2) {
|
||||
try_match(std::string(game_base) + " " + RGB[rgb], ci, rule.controller);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// name mode: direct 1:1 device_light → game_light
|
||||
const char *game_base = (is_valkyrie_mode && *rule.game_light_alt)
|
||||
? rule.game_light_alt : rule.game_light;
|
||||
if (!*game_base) {
|
||||
continue;
|
||||
}
|
||||
for (int ci = 0; ci < (int) raw_names.size(); ci++) {
|
||||
if (device_matched[ci]) {
|
||||
continue;
|
||||
}
|
||||
if (strtolower(raw_names[ci]) != strtolower(std::string(rule.device_light))) {
|
||||
continue;
|
||||
}
|
||||
if (try_match(game_base, ci, rule.controller)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// unmatched device lights
|
||||
for (int ci = 0; ci < (int) raw_names.size(); ci++) {
|
||||
if (!device_matched[ci] && strtolower(raw_names[ci]) != "null") {
|
||||
unmatched.push_back({"", raw_names[ci], -1, ci, false});
|
||||
}
|
||||
}
|
||||
|
||||
return detected_controller;
|
||||
}
|
||||
|
||||
void Config::build_cards() {
|
||||
|
||||
// early quit
|
||||
|
||||
@@ -26,6 +26,14 @@ namespace overlay::windows {
|
||||
CONFIG_TAB_SEARCH,
|
||||
};
|
||||
|
||||
struct MatchEntry {
|
||||
std::string game_name;
|
||||
std::string device_name;
|
||||
int light_index;
|
||||
int control_index;
|
||||
bool soft;
|
||||
};
|
||||
|
||||
class Config : public Window {
|
||||
private:
|
||||
|
||||
@@ -129,6 +137,13 @@ namespace overlay::windows {
|
||||
void edit_light_popup(Light &primary_light, Light *light, const int alt_index);
|
||||
void auto_match_lights_popup(std::vector<Light> *lights);
|
||||
|
||||
std::string match_lights(
|
||||
rawinput::Device *device,
|
||||
std::vector<Light> *lights,
|
||||
std::vector<std::string> &raw_names,
|
||||
std::vector<MatchEntry> &matched,
|
||||
std::vector<MatchEntry> &unmatched);
|
||||
|
||||
void build_cards();
|
||||
std::string build_option_value_picker_title(const OptionDefinition& option);
|
||||
void build_option_value_picker(Option& option);
|
||||
|
||||
@@ -40,6 +40,40 @@ namespace overlay::windows {
|
||||
{"PHOENIXWAN", "Beatmania IIDX", 0x034C, 0x0368, "Generic Indicator", "", "0x04", false, "5", ""},
|
||||
{"PHOENIXWAN", "Beatmania IIDX", 0x034C, 0x0368, "Generic Indicator", "", "0x05", false, "6", ""},
|
||||
{"PHOENIXWAN", "Beatmania IIDX", 0x034C, 0x0368, "Generic Indicator", "", "0x06", false, "7", ""},
|
||||
|
||||
// Nostroller VID_0E8F&PID_1212&MI_03 (Lights 01-14) (RGB)
|
||||
// The lights are named "LED_01R" "LED_01G" "LED_01B" and so on.
|
||||
{"Nostroller (Lights 01-14)", "Nostalgia", 0, 0, "LED_01", "", "", true, "Key 1", ""},
|
||||
{"Nostroller (Lights 01-14)", "Nostalgia", 0, 0, "LED_02", "", "", true, "Key 2", ""},
|
||||
{"Nostroller (Lights 01-14)", "Nostalgia", 0, 0, "LED_03", "", "", true, "Key 3", ""},
|
||||
{"Nostroller (Lights 01-14)", "Nostalgia", 0, 0, "LED_04", "", "", true, "Key 4", ""},
|
||||
{"Nostroller (Lights 01-14)", "Nostalgia", 0, 0, "LED_05", "", "", true, "Key 5", ""},
|
||||
{"Nostroller (Lights 01-14)", "Nostalgia", 0, 0, "LED_06", "", "", true, "Key 6", ""},
|
||||
{"Nostroller (Lights 01-14)", "Nostalgia", 0, 0, "LED_07", "", "", true, "Key 7", ""},
|
||||
{"Nostroller (Lights 01-14)", "Nostalgia", 0, 0, "LED_08", "", "", true, "Key 8", ""},
|
||||
{"Nostroller (Lights 01-14)", "Nostalgia", 0, 0, "LED_09", "", "", true, "Key 9", ""},
|
||||
{"Nostroller (Lights 01-14)", "Nostalgia", 0, 0, "LED_10", "", "", true, "Key 10", ""},
|
||||
{"Nostroller (Lights 01-14)", "Nostalgia", 0, 0, "LED_11", "", "", true, "Key 11", ""},
|
||||
{"Nostroller (Lights 01-14)", "Nostalgia", 0, 0, "LED_12", "", "", true, "Key 12", ""},
|
||||
{"Nostroller (Lights 01-14)", "Nostalgia", 0, 0, "LED_13", "", "", true, "Key 13", ""},
|
||||
{"Nostroller (Lights 01-14)", "Nostalgia", 0, 0, "LED_14", "", "", true, "Key 14", ""},
|
||||
|
||||
// Nostroller VID_0E8F&PID_1212&MI_02 (Lights 15-28) (RGB)
|
||||
{"Nostroller (Lights 15-28)", "Nostalgia", 0, 0, "LED_15", "", "", true, "Key 15", ""},
|
||||
{"Nostroller (Lights 15-28)", "Nostalgia", 0, 0, "LED_16", "", "", true, "Key 16", ""},
|
||||
{"Nostroller (Lights 15-28)", "Nostalgia", 0, 0, "LED_17", "", "", true, "Key 17", ""},
|
||||
{"Nostroller (Lights 15-28)", "Nostalgia", 0, 0, "LED_18", "", "", true, "Key 18", ""},
|
||||
{"Nostroller (Lights 15-28)", "Nostalgia", 0, 0, "LED_19", "", "", true, "Key 19", ""},
|
||||
{"Nostroller (Lights 15-28)", "Nostalgia", 0, 0, "LED_20", "", "", true, "Key 20", ""},
|
||||
{"Nostroller (Lights 15-28)", "Nostalgia", 0, 0, "LED_21", "", "", true, "Key 21", ""},
|
||||
{"Nostroller (Lights 15-28)", "Nostalgia", 0, 0, "LED_22", "", "", true, "Key 22", ""},
|
||||
{"Nostroller (Lights 15-28)", "Nostalgia", 0, 0, "LED_23", "", "", true, "Key 23", ""},
|
||||
{"Nostroller (Lights 15-28)", "Nostalgia", 0, 0, "LED_24", "", "", true, "Key 24", ""},
|
||||
{"Nostroller (Lights 15-28)", "Nostalgia", 0, 0, "LED_25", "", "", true, "Key 25", ""},
|
||||
{"Nostroller (Lights 15-28)", "Nostalgia", 0, 0, "LED_26", "", "", true, "Key 26", ""},
|
||||
{"Nostroller (Lights 15-28)", "Nostalgia", 0, 0, "LED_27", "", "", true, "Key 27", ""},
|
||||
{"Nostroller (Lights 15-28)", "Nostalgia", 0, 0, "LED_28", "", "", true, "Key 28", ""},
|
||||
|
||||
};
|
||||
|
||||
static const int LIGHT_MATCH_MAP_COUNT =
|
||||
|
||||
Reference in New Issue
Block a user