From 32fbe353867ce66e53964de14624cd9c1e8a779d Mon Sep 17 00:00:00 2001 From: AJR Date: Tue, 3 May 2016 23:52:32 -0400 Subject: [PATCH] Check software parts for incompatibility as well as compatibility This new softlist feature is now used by genesis_tmss to exclude several entries from megadriv.xml. - Use popmessage instead of osd_printf_warning for incompatibility warnings - Unify some common software loading code, which reduces indentation levels in clifront.cpp --- hash/megadriv.xml | 5 +++ src/emu/diimage.cpp | 40 +++++++++--------- src/emu/softlist.cpp | 72 +++++++++++++++++++++++++++----- src/emu/softlist.h | 9 +++- src/frontend/mame/clifront.cpp | 44 +++++++------------ src/frontend/mame/ui/selsoft.cpp | 2 +- src/frontend/mame/ui/swlist.cpp | 2 +- src/mame/drivers/megadriv.cpp | 5 ++- 8 files changed, 116 insertions(+), 63 deletions(-) diff --git a/hash/megadriv.xml b/hash/megadriv.xml index 21c0849b2f7..9f25e53fd43 100644 --- a/hash/megadriv.xml +++ b/hash/megadriv.xml @@ -3800,6 +3800,7 @@ Info on Sega chip labels (from Sunbeam / Digital Corruption) Ishido - The Way of Stones (USA) 1990 Accolade + @@ -11942,6 +11943,7 @@ but dumps still have to be confirmed. Budokan - The Martial Spirit (USA) 1990 Electronic Arts + @@ -20522,6 +20524,7 @@ Notice that these are not working on real hardware due to bugged code with VDP i Onslaught (Euro, USA) 1991 Ballistic + @@ -21578,6 +21581,7 @@ Notice that these are not working on real hardware due to bugged code with VDP i Populous (USA) 1991 Sega + @@ -29417,6 +29421,7 @@ Notice that these are not working on real hardware due to bugged code with VDP i Zany Golf (Euro, USA) 1990 Electronic Arts + diff --git a/src/emu/diimage.cpp b/src/emu/diimage.cpp index 198be9d1ac0..3506704d9b5 100644 --- a/src/emu/diimage.cpp +++ b/src/emu/diimage.cpp @@ -1288,14 +1288,26 @@ bool device_image_interface::load_software_part(const char *path, software_part } // Load the software part - bool result = call_softlist_load(swpart->info().list(), swpart->info().shortname(), swpart->romdata()); + software_list_device &swlist = swpart->info().list(); + bool result = call_softlist_load(swlist, swpart->info().shortname(), swpart->romdata()); // Tell the world which part we actually loaded - std::string full_sw_name = string_format("%s:%s:%s", swpart->info().list().list_name(), swpart->info().shortname(), swpart->name()); + std::string full_sw_name = string_format("%s:%s:%s", swlist.list_name(), swpart->info().shortname(), swpart->name()); // check compatibility - if (!swpart->is_compatible(swpart->info().list())) - osd_printf_warning("WARNING! the set %s might not work on this system due to missing filter(s) '%s'\n", swpart->info().shortname(), swpart->info().list().filter()); + switch (swpart->is_compatible(swlist)) + { + case SOFTWARE_IS_COMPATIBLE: + break; + + case SOFTWARE_IS_INCOMPATIBLE: + swlist.popmessage("WARNING! the set %s might not work on this system due to incompatible filter(s) '%s'\n", swpart->info().shortname(), swlist.filter()); + break; + + case SOFTWARE_NOT_COMPATIBLE: + swlist.popmessage("WARNING! the set %s might not work on this system due to missing filter(s) '%s'\n", swpart->info().shortname(), swlist.filter()); + break; + } // check requirements and load those images const char *requirement = swpart->feature("requirement"); @@ -1304,23 +1316,11 @@ bool device_image_interface::load_software_part(const char *path, software_part software_part *req_swpart = find_software_item(requirement, false); if (req_swpart != nullptr) { - for (device_image_interface &req_image : image_interface_iterator(device().machine().root_device())) + device_image_interface *req_image = req_swpart->find_mountable_image(device().mconfig()); + if (req_image != nullptr) { - const char *interface = req_image.image_interface(); - if (interface != nullptr) - { - if (req_swpart->matches_interface(interface)) - { - const char *option = device().mconfig().options().value(req_image.brief_instance_name()); - // mount only if not already mounted - if (*option == '\0' && !req_image.filename()) - { - req_image.set_init_phase(); - req_image.load(requirement); - } - break; - } - } + req_image->set_init_phase(); + req_image->load(requirement); } } } diff --git a/src/emu/softlist.cpp b/src/emu/softlist.cpp index 3b57a60c82c..6f4955e61b1 100644 --- a/src/emu/softlist.cpp +++ b/src/emu/softlist.cpp @@ -140,26 +140,48 @@ const char *software_part::feature(const char *feature_name) const // with the given software_list_device //------------------------------------------------- -bool software_part::is_compatible(const software_list_device &swlistdev) const +software_compatibility software_part::is_compatible(const software_list_device &swlistdev) const { - // get the compatibility feature and the softlist filter; if either is nullptr, assume compatible - const char *compatibility = feature("compatibility"); + // get the softlist filter; if null, assume compatible const char *filter = swlistdev.filter(); - if (compatibility == nullptr || filter == nullptr) - return true; + if (filter == nullptr) + return SOFTWARE_IS_COMPATIBLE; - // copy the comma-delimited strings and ensure they end with a final comma - std::string comp = std::string(compatibility).append(","); + // copy the comma-delimited string and ensure it ends with a final comma std::string filt = std::string(filter).append(","); - // iterate over filter items and see if they exist in the compatibility list; if so, return true + // get the incompatibility filter and test against it first if it exists + const char *incompatibility = feature("incompatibility"); + if (incompatibility != nullptr) + { + // copy the comma-delimited string and ensure it ends with a final comma + std::string incomp = std::string(incompatibility).append(","); + + // iterate over filter items and see if they exist in the list; if so, it's incompatible + for (int start = 0, end = filt.find_first_of(',',start); end != -1; start = end + 1, end = filt.find_first_of(',', start)) + { + std::string token(filt, start, end - start + 1); + if (incomp.find(token) != -1) + return SOFTWARE_IS_INCOMPATIBLE; + } + } + + // get the compatibility feature; if null, assume compatible + const char *compatibility = feature("compatibility"); + if (compatibility == nullptr) + return SOFTWARE_IS_COMPATIBLE; + + // copy the comma-delimited string and ensure it ends with a final comma + std::string comp = std::string(compatibility).append(","); + + // iterate over filter items and see if they exist in the compatibility list; if so, it's compatible for (int start = 0, end = filt.find_first_of(',',start); end != -1; start = end + 1, end = filt.find_first_of(',', start)) { std::string token(filt, start, end - start + 1); if (comp.find(token) != -1) - return true; + return SOFTWARE_IS_COMPATIBLE; } - return false; + return SOFTWARE_NOT_COMPATIBLE; } @@ -183,6 +205,34 @@ bool software_part::matches_interface(const char *interface_list) const } +//------------------------------------------------- +// find_mountable_image - find an image interface +// that can automatically mount this software part +//------------------------------------------------- + +device_image_interface *software_part::find_mountable_image(const machine_config &mconfig) const +{ + // if automount="no", don't bother + const char *mount = feature("automount"); + if (mount != nullptr && strcmp(mount, "no") == 0) + return nullptr; + + for (device_image_interface &image : image_interface_iterator(mconfig.root_device())) + { + const char *interface = image.image_interface(); + if (interface != nullptr && matches_interface(interface)) + { + // mount only if not already mounted + const char *option = mconfig.options().value(image.brief_instance_name()); + if (*option == '\0' && !image.filename()) + + return ℑ + } + } + return nullptr; +} + + //************************************************************************** // SOFTWARE INFO @@ -340,7 +390,7 @@ void software_list_device::find_approx_matches(const char *name, int matches, so for (software_info &swinfo : get_info()) { software_part *part = swinfo.first_part(); - if ((interface == nullptr || part->matches_interface(interface)) && part->is_compatible(*this)) + if ((interface == nullptr || part->matches_interface(interface)) && part->is_compatible(*this) == SOFTWARE_IS_COMPATIBLE) { // pick the best match between driver name and description int longpenalty = driver_list::penalty_compare(name, swinfo.longname()); diff --git a/src/emu/softlist.h b/src/emu/softlist.h index 09fa6981cd2..536ec9d4754 100644 --- a/src/emu/softlist.h +++ b/src/emu/softlist.h @@ -29,6 +29,12 @@ enum softlist_type SOFTWARE_LIST_COMPATIBLE_SYSTEM }; +enum software_compatibility +{ + SOFTWARE_IS_COMPATIBLE, + SOFTWARE_IS_INCOMPATIBLE, + SOFTWARE_NOT_COMPATIBLE +}; //************************************************************************** @@ -115,9 +121,10 @@ public: rom_entry *romdata(unsigned int index = 0) { return (index < m_romdata.size()) ? &m_romdata[index] : nullptr; } // helpers - bool is_compatible(const software_list_device &swlist) const; + software_compatibility is_compatible(const software_list_device &swlist) const; bool matches_interface(const char *interface) const; const char *feature(const char *feature_name) const; + device_image_interface *find_mountable_image(const machine_config &mconfig) const; private: // internal state diff --git a/src/frontend/mame/clifront.cpp b/src/frontend/mame/clifront.cpp index bbe64537aa2..a03479cde61 100644 --- a/src/frontend/mame/clifront.cpp +++ b/src/frontend/mame/clifront.cpp @@ -201,6 +201,7 @@ int cli_frontend::execute(int argc, char **argv) throw emu_fatalerror(EMU_ERR_FATALERROR, "Error: unknown option: %s\n", m_options.software_name()); bool found = false; + bool compatible = false; for (software_list_device &swlistdev : iter) { software_info *swinfo = swlistdev.find(m_options.software_name()); @@ -209,46 +210,33 @@ int cli_frontend::execute(int argc, char **argv) // loop through all parts for (software_part &swpart : swinfo->parts()) { - const char *mount = swpart.feature("automount"); - if (swpart.is_compatible(swlistdev)) + // only load compatible software this way + if (swpart.is_compatible(swlistdev) == SOFTWARE_IS_COMPATIBLE) { - if (mount == nullptr || strcmp(mount,"no") != 0) + device_image_interface *image = swpart.find_mountable_image(config); + if (image != nullptr) { - // search for an image device with the right interface - for (device_image_interface &image : image_interface_iterator(config.root_device())) - { - const char *interface = image.image_interface(); - if (interface != nullptr) - { - if (swpart.matches_interface(interface)) - { - const char *option = m_options.value(image.brief_instance_name()); + std::string val = string_format("%s:%s:%s", swlistdev.list_name(), m_options.software_name(), swpart.name()); - // mount only if not already mounted - if (*option == 0) - { - std::string val = string_format("%s:%s:%s", swlistdev.list_name(), m_options.software_name(), swpart.name()); - - // call this in order to set slot devices according to mounting - mame_options::parse_slot_devices(m_options, argc, argv, option_errors, image.instance_name(), val.c_str(), &swpart); - break; - } - } - } - } + // call this in order to set slot devices according to mounting + mame_options::parse_slot_devices(m_options, argc, argv, option_errors, image->instance_name(), val.c_str(), &swpart); } - found = true; + compatible = true; } } + found = true; } - if (found) + if (compatible) break; } - if (!found) + if (!compatible) { software_list_device::display_matches(config, nullptr, m_options.software_name()); - throw emu_fatalerror(EMU_ERR_FATALERROR, nullptr); + if (!found) + throw emu_fatalerror(EMU_ERR_FATALERROR, nullptr); + else + throw emu_fatalerror(EMU_ERR_FATALERROR, "Software '%s' is incompatible with system '%s'\n", m_options.software_name(), m_options.system_name()); } } diff --git a/src/frontend/mame/ui/selsoft.cpp b/src/frontend/mame/ui/selsoft.cpp index 1c0c1460211..c5f33b8c701 100644 --- a/src/frontend/mame/ui/selsoft.cpp +++ b/src/frontend/mame/ui/selsoft.cpp @@ -538,7 +538,7 @@ void ui_menu_select_software::build_software_list() for (software_info &swinfo : swlist.get_info()) { software_part *part = swinfo.first_part(); - if (part->is_compatible(swlist)) + if (part->is_compatible(swlist) == SOFTWARE_IS_COMPATIBLE) { const char *instance_name = nullptr; const char *type_name = nullptr; diff --git a/src/frontend/mame/ui/swlist.cpp b/src/frontend/mame/ui/swlist.cpp index b6dfc318a28..267f07f69d7 100644 --- a/src/frontend/mame/ui/swlist.cpp +++ b/src/frontend/mame/ui/swlist.cpp @@ -191,7 +191,7 @@ ui_menu_software_list::entry_info *ui_menu_software_list::append_software_entry( // check if at least one of the parts has the correct interface and add a menu entry only in this case for (const software_part &swpart : swinfo.parts()) { - if (swpart.matches_interface(m_interface) && swpart.is_compatible(*m_swlist)) + if (swpart.matches_interface(m_interface) && swpart.is_compatible(*m_swlist) == SOFTWARE_IS_COMPATIBLE) { entry_updated = TRUE; // allocate a new entry diff --git a/src/mame/drivers/megadriv.cpp b/src/mame/drivers/megadriv.cpp index dbbcd3186a2..ce255d3bd69 100644 --- a/src/mame/drivers/megadriv.cpp +++ b/src/mame/drivers/megadriv.cpp @@ -406,6 +406,9 @@ static MACHINE_CONFIG_START( ms_megadpal, md_cons_state ) MCFG_SOFTWARE_LIST_ADD("cart_list","megadriv") MACHINE_CONFIG_END +static MACHINE_CONFIG_DERIVED( genesis_tmss, ms_megadriv ) + MCFG_SOFTWARE_LIST_FILTER("cart_list","TMSS") +MACHINE_CONFIG_END @@ -1058,7 +1061,7 @@ CONS( 1990, megadriv, genesis, 0, ms_megadpal, md, md_cons_state, CONS( 1988, megadrij, genesis, 0, ms_megadriv, md, md_cons_state, md_jpn, "Sega", "Mega Drive (Japan, NTSC)", MACHINE_SUPPORTS_SAVE ) // 1990+ models had the TMSS security chip, leave this as a clone, it reduces compatibility and nothing more. -CONS( 1990, genesis_tmss, genesis, 0, ms_megadriv, md, md_cons_state, genesis, "Sega", "Genesis (USA, NTSC, with TMSS chip)", MACHINE_SUPPORTS_SAVE ) +CONS( 1990, genesis_tmss, genesis, 0, genesis_tmss, md, md_cons_state, genesis, "Sega", "Genesis (USA, NTSC, with TMSS chip)", MACHINE_SUPPORTS_SAVE ) // the 32X plugged in the cart slot, games plugged into the 32x. Maybe it should be handled as an expansion device?