Merge pull request #854 from ajrhacker/incompatibility

Check software parts for incompatibility as well as compatibility
This commit is contained in:
etabeta78 2016-05-04 11:50:21 +02:00
commit ea1863db53
8 changed files with 116 additions and 63 deletions

View File

@ -3800,6 +3800,7 @@ Info on Sega chip labels (from Sunbeam / Digital Corruption)
<description>Ishido - The Way of Stones (USA)</description>
<year>1990</year>
<publisher>Accolade</publisher>
<sharedfeat name="incompatibility" value="TMSS"/>
<part name="cart" interface="megadriv_cart">
<feature name="pcb" value="ACBWPC1190"/>
<feature name="ic1" value="MB834200A 2M5 BA 9044 T03 ISS0890"/>
@ -11942,6 +11943,7 @@ but dumps still have to be confirmed.
<description>Budokan - The Martial Spirit (USA)</description>
<year>1990</year>
<publisher>Electronic Arts</publisher>
<sharedfeat name="incompatibility" value="TMSS"/>
<part name="cart" interface="megadriv_cart">
<dataarea name="rom" width="16" endianness="big" size="524288">
<rom name="budokan - the martial spirit (usa).bin" size="524288" crc="acd9f5fc" sha1="93bc8242106bc9b2e0a8a974a3f65b559dd2941d" offset="0x000000"/>
@ -20522,6 +20524,7 @@ Notice that these are not working on real hardware due to bugged code with VDP i
<description>Onslaught (Euro, USA)</description>
<year>1991</year>
<publisher>Ballistic</publisher>
<sharedfeat name="incompatibility" value="TMSS"/>
<part name="cart" interface="megadriv_cart">
<dataarea name="rom" width="16" endianness="big" size="524288">
<rom name="onslaught (euro, usa).bin" size="524288" crc="9f19d6df" sha1="dc542ddfa878f2aed3a7fcedc4b0f8d503eb5d70" offset="0x000000"/>
@ -21578,6 +21581,7 @@ Notice that these are not working on real hardware due to bugged code with VDP i
<description>Populous (USA)</description>
<year>1991</year>
<publisher>Sega</publisher>
<sharedfeat name="incompatibility" value="TMSS"/>
<part name="cart" interface="megadriv_cart">
<dataarea name="rom" width="16" endianness="big" size="524288">
<rom name="populous (usa).bin" size="524288" crc="bd74b31e" sha1="89907c4ba4fd9db4e8ef2271c0253bb0e4b6d52d" offset="0x000000"/>
@ -29417,6 +29421,7 @@ Notice that these are not working on real hardware due to bugged code with VDP i
<description>Zany Golf (Euro, USA)</description>
<year>1990</year>
<publisher>Electronic Arts</publisher>
<sharedfeat name="incompatibility" value="TMSS"/>
<part name="cart" interface="megadriv_cart">
<dataarea name="rom" width="16" endianness="big" size="524288">
<rom name="zany golf (euro, usa).bin" size="524288" crc="ed5d12ea" sha1="4f9bea2d8f489bfbc963718a8dca212e033fb5a2" offset="0x000000"/>

View File

@ -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);
}
}
}

View File

@ -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 &image;
}
}
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());

View File

@ -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

View File

@ -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());
}
}

View File

@ -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;

View File

@ -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

View File

@ -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?