summaryrefslogtreecommitdiffstatshomepage
path: root/src/frontend
diff options
context:
space:
mode:
author Vas Crabb <vas@vastheman.com>2020-12-18 15:54:52 +1100
committer Vas Crabb <vas@vastheman.com>2020-12-18 15:54:52 +1100
commit1df245cb99882892678216c3d0c6e243611d627c (patch)
treea8f3563a74d58755f4a82d4cbfc2406cf79543b3 /src/frontend
parentff9c1a0ca91f925e5c23b22a92a53c83f9f655ba (diff)
More Lua engine clean-up and documentation, resulting in core cleanup.
More Lua interface cleanup, additional properties and methods, and documentation migration/expansion. Emulated switch inputs can have "not" codes applied to host input axis directions. It works the same way as host switch inputs - push twice for a "not" prefix. Input polling helpers no longer need to store state in the input device items. There’s less leakage, and less chance of things interfering with each other. Allow snapshot view options to be configured through the internal UI via the video options menu. Made video options menus place initial focus on the currently selected view item. Removed some crud from the menu base class. Fixed the description of the "snapview" option. The value to get raw screen pixels was changed to "native" a long time ago but the description was never updated. Re-arranged the Golden Poker button lamps so that the 6-button layouts for Jolli Witch and Wild Witch make sense. In 6-button mode, the hold buttons double as bonus game and bet buttons, but the lamp outputs don't change. The simplest way to deal with this without requiring the user to switch views or using layout scripting is to place the dedicated buttons directly below the hold buttons that correspond to them. Removed some software list data that was redundantly copied into device_image_interface (m_supported was never even set, so it didn't even work), and made crc() work better (previously it wasn't recalculuated after unloading and loading another image). Made strformat.h and devcb.h play nicer with C++17 and pre-standard C++20. Format precision now correctly limits the length of string views. Confirmed that strformat.{h,cpp} works with pre-standard C++20 support in GCC 9. Removed an auto_alloc from cpu/arm7.
Diffstat (limited to 'src/frontend')
-rw-r--r--src/frontend/mame/iptseqpoll.cpp182
-rw-r--r--src/frontend/mame/iptseqpoll.h4
-rw-r--r--src/frontend/mame/luaengine.cpp803
-rw-r--r--src/frontend/mame/luaengine.h2
-rw-r--r--src/frontend/mame/luaengine.ipp85
-rw-r--r--src/frontend/mame/luaengine_render.cpp150
-rw-r--r--src/frontend/mame/ui/barcode.cpp18
-rw-r--r--src/frontend/mame/ui/devctrl.h10
-rw-r--r--src/frontend/mame/ui/devopt.cpp4
-rw-r--r--src/frontend/mame/ui/info.cpp28
-rw-r--r--src/frontend/mame/ui/inifile.cpp8
-rw-r--r--src/frontend/mame/ui/mainmenu.cpp4
-rw-r--r--src/frontend/mame/ui/menu.cpp57
-rw-r--r--src/frontend/mame/ui/menu.h3
-rw-r--r--src/frontend/mame/ui/miscmenu.cpp31
-rw-r--r--src/frontend/mame/ui/tapectrl.cpp8
-rw-r--r--src/frontend/mame/ui/videoopt.cpp111
-rw-r--r--src/frontend/mame/ui/videoopt.h6
18 files changed, 722 insertions, 792 deletions
diff --git a/src/frontend/mame/iptseqpoll.cpp b/src/frontend/mame/iptseqpoll.cpp
index 145c64f033a..83883e5d970 100644
--- a/src/frontend/mame/iptseqpoll.cpp
+++ b/src/frontend/mame/iptseqpoll.cpp
@@ -11,7 +11,8 @@
input_code_poller::input_code_poller(input_manager &manager) noexcept :
- m_manager(manager)
+ m_manager(manager),
+ m_axis_memory()
{
}
@@ -24,26 +25,31 @@ input_code_poller::~input_code_poller()
void input_code_poller::reset()
{
// iterate over device classes and devices
+ m_axis_memory.clear();
for (input_device_class classno = DEVICE_CLASS_FIRST_VALID; DEVICE_CLASS_LAST_VALID >= classno; ++classno)
{
input_class &devclass(m_manager.device_class(classno));
- for (int devnum = 0; devclass.maxindex() >= devnum; ++devnum)
+ if (devclass.enabled())
{
- // fetch the device; ignore if nullptr
- input_device *const device(devclass.device(devnum));
- if (device)
+ for (int devnum = 0; devclass.maxindex() >= devnum; ++devnum)
{
- // iterate over items within each device
- for (input_item_id itemid = ITEM_ID_FIRST_VALID; device->maxitem() >= itemid; ++itemid)
+ // fetch the device; ignore if nullptr
+ input_device *const device(devclass.device(devnum));
+ if (device)
{
- // for any non-switch items, set memory to the current value
- input_device_item *const item(device->item(itemid));
- if (item && (item->itemclass() != ITEM_CLASS_SWITCH))
- item->set_memory(m_manager.code_value(item->code()));
+ // iterate over items within each device
+ for (input_item_id itemid = ITEM_ID_FIRST_VALID; device->maxitem() >= itemid; ++itemid)
+ {
+ // for any non-switch items, set memory to the current value
+ input_device_item *const item(device->item(itemid));
+ if (item && (item->itemclass() != ITEM_CLASS_SWITCH))
+ m_axis_memory.emplace_back(item, m_manager.code_value(item->code()));
+ }
}
}
}
}
+ std::sort(m_axis_memory.begin(), m_axis_memory.end());
}
@@ -62,7 +68,7 @@ void switch_code_poller_base::reset()
}
-bool switch_code_poller_base::code_pressed_once(input_code code)
+bool switch_code_poller_base::code_pressed_once(input_code code, bool moved)
{
// look for the code in the memory
bool const pressed(m_manager.code_pressed(code));
@@ -78,7 +84,7 @@ bool switch_code_poller_base::code_pressed_once(input_code code)
}
// if we get here, we were not previously pressed; if still not pressed, return false
- if (!pressed)
+ if (!pressed || !moved)
return false;
// otherwise, add the code to the memory and return true
@@ -96,31 +102,14 @@ axis_code_poller::axis_code_poller(input_manager &manager) noexcept :
input_code axis_code_poller::poll()
{
- // iterate over device classes and devices, skipping disabled classes
- for (input_device_class classno = DEVICE_CLASS_FIRST_VALID; DEVICE_CLASS_LAST_VALID >= classno; ++classno)
+ // iterate over the axis items we found
+ for (auto memory = m_axis_memory.begin(); m_axis_memory.end() != memory; ++memory)
{
- input_class &devclass(m_manager.device_class(classno));
- if (devclass.enabled())
+ input_code const code = memory->first->code();
+ if (memory->first->check_axis(code.item_modifier(), memory->second))
{
- for (int devnum = 0; devclass.maxindex() >= devnum; ++devnum)
- {
- // fetch the device; ignore if nullptr
- input_device *const device(devclass.device(devnum));
- if (device)
- {
- // iterate over items within each device
- for (input_item_id itemid = ITEM_ID_FIRST_VALID; device->maxitem() >= itemid; ++itemid)
- {
- input_device_item *const item(device->item(itemid));
- if (item && (item->itemclass() != ITEM_CLASS_SWITCH))
- {
- input_code const code = item->code();
- if (item->check_axis(code.item_modifier()))
- return code;
- }
- }
- }
- }
+ m_axis_memory.erase(memory);
+ return code;
}
}
@@ -142,64 +131,73 @@ input_code switch_code_poller::poll()
for (input_device_class classno = DEVICE_CLASS_FIRST_VALID; DEVICE_CLASS_LAST_VALID >= classno; ++classno)
{
input_class &devclass(m_manager.device_class(classno));
- if (devclass.enabled())
+ if (!devclass.enabled())
+ continue;
+
+ for (int devnum = 0; devclass.maxindex() >= devnum; ++devnum)
{
- for (int devnum = 0; devclass.maxindex() >= devnum; ++devnum)
+ // fetch the device; ignore if nullptr
+ input_device *const device(devclass.device(devnum));
+ if (!device)
+ continue;
+
+ // iterate over items within each device
+ for (input_item_id itemid = ITEM_ID_FIRST_VALID; device->maxitem() >= itemid; ++itemid)
{
- // fetch the device; ignore if nullptr
- input_device *const device(devclass.device(devnum));
- if (device)
+ input_device_item *const item(device->item(itemid));
+ if (!item)
+ continue;
+
+ input_code code = item->code();
+ if (item->itemclass() == ITEM_CLASS_SWITCH)
{
- // iterate over items within each device
- for (input_item_id itemid = ITEM_ID_FIRST_VALID; device->maxitem() >= itemid; ++itemid)
- {
- input_device_item *const item(device->item(itemid));
- if (item)
- {
- input_code code = item->code();
- if (item->itemclass() == ITEM_CLASS_SWITCH)
- {
- // item is natively a switch, poll it
- if (code_pressed_once(code))
- return code;
- }
- else if (item->check_axis(code.item_modifier()))
- {
- // poll axes digitally
- code.set_item_class(ITEM_CLASS_SWITCH);
- if ((classno == DEVICE_CLASS_JOYSTICK) && (code.item_id() == ITEM_ID_XAXIS))
- {
- // joystick X axis - check with left/right modifiers
- code.set_item_modifier(ITEM_MODIFIER_LEFT);
- if (code_pressed_once(code))
- return code;
- code.set_item_modifier(ITEM_MODIFIER_RIGHT);
- if (code_pressed_once(code))
- return code;
- }
- else if ((classno == DEVICE_CLASS_JOYSTICK) && (code.item_id() == ITEM_ID_YAXIS))
- {
- // if this is a joystick Y axis, check with up/down modifiers
- code.set_item_modifier(ITEM_MODIFIER_UP);
- if (code_pressed_once(code))
- return code;
- code.set_item_modifier(ITEM_MODIFIER_DOWN);
- if (code_pressed_once(code))
- return code;
- }
- else
- {
- // any other axis, check with pos/neg modifiers
- code.set_item_modifier(ITEM_MODIFIER_POS);
- if (code_pressed_once(code))
- return code;
- code.set_item_modifier(ITEM_MODIFIER_NEG);
- if (code_pressed_once(code))
- return code;
- }
- }
- }
- }
+ // item is natively a switch, poll it
+ if (code_pressed_once(code, true))
+ return code;
+ else
+ continue;
+ }
+
+ auto const memory(std::lower_bound(
+ m_axis_memory.begin(),
+ m_axis_memory.end(),
+ item,
+ [] (auto const &x, auto const &y) { return x.first < y; }));
+ if ((m_axis_memory.end() == memory) || (item != memory->first))
+ continue;
+
+ // poll axes digitally
+ bool const moved(item->check_axis(code.item_modifier(), memory->second));
+ code.set_item_class(ITEM_CLASS_SWITCH);
+ if ((classno == DEVICE_CLASS_JOYSTICK) && (code.item_id() == ITEM_ID_XAXIS))
+ {
+ // joystick X axis - check with left/right modifiers
+ code.set_item_modifier(ITEM_MODIFIER_LEFT);
+ if (code_pressed_once(code, moved))
+ return code;
+ code.set_item_modifier(ITEM_MODIFIER_RIGHT);
+ if (code_pressed_once(code, moved))
+ return code;
+ }
+ else if ((classno == DEVICE_CLASS_JOYSTICK) && (code.item_id() == ITEM_ID_YAXIS))
+ {
+ // if this is a joystick Y axis, check with up/down modifiers
+ code.set_item_modifier(ITEM_MODIFIER_UP);
+ if (code_pressed_once(code, moved))
+ return code;
+ code.set_item_modifier(ITEM_MODIFIER_DOWN);
+ if (code_pressed_once(code, moved))
+ return code;
+ }
+ else
+ {
+ // any other axis, check with pos/neg modifiers
+ code.set_item_modifier(ITEM_MODIFIER_POS);
+ if (code_pressed_once(code, moved))
+ return code;
+ code.set_item_modifier(ITEM_MODIFIER_NEG);
+ if (code_pressed_once(code, moved))
+ return code;
}
}
}
@@ -237,7 +235,7 @@ input_code keyboard_code_poller::poll()
if (item && (item->itemclass() == ITEM_CLASS_SWITCH))
{
input_code const code = item->code();
- if (code_pressed_once(code))
+ if (code_pressed_once(code, true))
return code;
}
}
diff --git a/src/frontend/mame/iptseqpoll.h b/src/frontend/mame/iptseqpoll.h
index 13c0d9c6484..b9f31f70477 100644
--- a/src/frontend/mame/iptseqpoll.h
+++ b/src/frontend/mame/iptseqpoll.h
@@ -12,6 +12,7 @@
#pragma once
+#include <utility>
#include <vector>
@@ -27,6 +28,7 @@ protected:
input_code_poller(input_manager &manager) noexcept;
input_manager &m_manager;
+ std::vector<std::pair<input_device_item *, s32> > m_axis_memory;
};
@@ -38,7 +40,7 @@ public:
protected:
switch_code_poller_base(input_manager &manager) noexcept;
- bool code_pressed_once(input_code code);
+ bool code_pressed_once(input_code code, bool moved);
private:
std::vector<input_code> m_switch_memory;
diff --git a/src/frontend/mame/luaengine.cpp b/src/frontend/mame/luaengine.cpp
index 4e7fb5412da..98f00a219d0 100644
--- a/src/frontend/mame/luaengine.cpp
+++ b/src/frontend/mame/luaengine.cpp
@@ -47,7 +47,7 @@ int luaopen_lsqlite3(lua_State *L);
template <typename T>
struct lua_engine::devenum
{
- devenum(device_t &d) : device(d), iter(d) { }
+ template <typename... U> devenum(device_t &d, U &&... args) : device(d), iter(d, std::forward<U>(args)...) { }
device_t &device;
T iter;
@@ -55,18 +55,85 @@ struct lua_engine::devenum
};
-template <typename T>
-struct lua_engine::object_ptr_vector_wrapper
+namespace {
+
+void do_draw_box(screen_device &sdev, float x1, float y1, float x2, float y2, uint32_t fgcolor, uint32_t bgcolor)
+{
+ float const sc_width(sdev.visible_area().width());
+ float const sc_height(sdev.visible_area().height());
+ x1 = std::min(std::max(0.0f, x1), sc_width) / sc_width;
+ y1 = std::min(std::max(0.0f, y1), sc_height) / sc_height;
+ x2 = std::min(std::max(0.0f, x2), sc_width) / sc_width;
+ y2 = std::min(std::max(0.0f, y2), sc_height) / sc_height;
+ mame_machine_manager::instance()->ui().draw_outlined_box(sdev.container(), x1, y1, x2, y2, fgcolor, bgcolor);
+}
+
+void do_draw_line(screen_device &sdev, float x1, float y1, float x2, float y2, uint32_t color)
+{
+ float const sc_width(sdev.visible_area().width());
+ float const sc_height(sdev.visible_area().height());
+ x1 = std::min(std::max(0.0f, x1), sc_width) / sc_width;
+ y1 = std::min(std::max(0.0f, y1), sc_height) / sc_height;
+ x2 = std::min(std::max(0.0f, x2), sc_width) / sc_width;
+ y2 = std::min(std::max(0.0f, y2), sc_height) / sc_height;
+ sdev.container().add_line(x1, y1, x2, y2, UI_LINE_WIDTH, rgb_t(color), PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA));
+}
+
+void do_draw_text(lua_State *L, screen_device &sdev, sol::object &xobj, float y, const char *msg, rgb_t fgcolor, rgb_t bgcolor)
+{
+ float const sc_width(sdev.visible_area().width());
+ float const sc_height(sdev.visible_area().height());
+ auto justify = ui::text_layout::LEFT;
+ float x = 0;
+ if (xobj.is<float>())
+ {
+ x = std::min(std::max(0.0f, xobj.as<float>()), sc_width) / sc_width;
+ }
+ else if (xobj.is<char const *>())
+ {
+ char const *const justifystr(xobj.as<char const *>());
+ if (!strcmp(justifystr, "left"))
+ justify = ui::text_layout::LEFT;
+ else if (!strcmp(justifystr, "right"))
+ justify = ui::text_layout::RIGHT;
+ else if (!strcmp(justifystr, "center"))
+ justify = ui::text_layout::CENTER;
+ }
+ else
+ {
+ luaL_error(L, "Error in param 1 to draw_text");
+ return;
+ }
+ y = std::min(std::max(0.0f, y), sc_height) / sc_height;
+ mame_machine_manager::instance()->ui().draw_text_full(
+ sdev.container(),
+ msg,
+ x, y, (1.0f - x),
+ justify, ui::text_layout::WORD,
+ mame_ui_manager::OPAQUE_, fgcolor, bgcolor);
+}
+
+
+struct image_interface_formats
{
- object_ptr_vector_wrapper(std::vector<std::unique_ptr<T>> const &v) : vec(v) { }
+ image_interface_formats(device_image_interface &i) : image(i) { }
+ device_image_interface::formatlist_type const &items() { return image.formatlist(); }
+
+ static image_device_format const &unwrap(device_image_interface::formatlist_type::const_iterator const &it) { return **it; }
+ static int push_key(lua_State *L, device_image_interface::formatlist_type::const_iterator const &it, std::size_t ix) { return sol::stack::push_reference(L, (*it)->name()); }
- std::vector<std::unique_ptr<T>> const &vec;
+ device_image_interface &image;
};
+} // anonymous namespace
+
namespace sol
{
+template <> struct is_container<image_interface_formats> : std::true_type { };
+
+
sol::buffer *sol_lua_get(sol::types<buffer *>, lua_State *L, int index, sol::stack::record &tracking)
{
return new sol::buffer(stack::get<int>(L, index), L);
@@ -181,74 +248,30 @@ public:
};
-template <typename T>
-struct usertype_container<lua_engine::object_ptr_vector_wrapper<T> > : lua_engine::immutable_collection_helper<lua_engine::object_ptr_vector_wrapper<T>, std::vector<std::unique_ptr<T>> const, typename std::vector<std::unique_ptr<T>>::const_iterator>
+template <>
+struct usertype_container<image_interface_formats> : lua_engine::immutable_sequence_helper<image_interface_formats, device_image_interface::formatlist_type const, device_image_interface::formatlist_type::const_iterator>
{
private:
- static int next_pairs(lua_State *L)
- {
- typename usertype_container::indexed_iterator &i(stack::unqualified_get<user<typename usertype_container::indexed_iterator> >(L, 1));
- if (i.src.end() == i.it)
- return stack::push(L, lua_nil);
- int result;
- result = stack::push(L, i.ix + 1);
- result += stack::push_reference(L, i.it->get());
- ++i;
- return result;
- }
+ using format_list = device_image_interface::formatlist_type;
public:
- static int at(lua_State *L)
- {
- lua_engine::object_ptr_vector_wrapper<T> &self(usertype_container::get_self(L));
- std::ptrdiff_t const index(stack::unqualified_get<std::ptrdiff_t>(L, 2));
- if ((0 >= index) || (self.vec.size() < index))
- return stack::push(L, lua_nil);
- return stack::push_reference(L, self.vec[index - 1].get());
- }
-
- static int get(lua_State *L) { return at(L); }
- static int index_get(lua_State *L) { return at(L); }
-
- static int index_of(lua_State *L)
+ static int get(lua_State *L)
{
- lua_engine::object_ptr_vector_wrapper<T> &self(usertype_container::get_self(L));
- T &target(stack::unqualified_get<T>(L, 2));
- auto it(self.vec.begin());
- std::ptrdiff_t ix(0);
- while ((self.vec.end() != it) && (it->get() != &target))
- {
- ++it;
- ++ix;
- }
- if (self.vec.end() == it)
- return stack::push(L, lua_nil);
+ image_interface_formats &self(get_self(L));
+ char const *const name(stack::unqualified_get<char const *>(L));
+ auto const found(std::find_if(
+ self.image.formatlist().begin(),
+ self.image.formatlist().end(),
+ [&name] (std::unique_ptr<image_device_format> const &v) { return v->name() == name; }));
+ if (self.image.formatlist().end() != found)
+ return stack::push_reference(L, **found);
else
- return stack::push(L, ix + 1);
- }
-
- static int size(lua_State *L)
- {
- lua_engine::object_ptr_vector_wrapper<T> &self(usertype_container::get_self(L));
- return stack::push(L, self.vec.size());
- }
-
- static int empty(lua_State *L)
- {
- lua_engine::object_ptr_vector_wrapper<T> &self(usertype_container::get_self(L));
- return stack::push(L, self.vec.empty());
+ return stack::push(L, lua_nil);
}
- static int next(lua_State *L) { return stack::push(L, next_pairs); }
- static int pairs(lua_State *L) { return ipairs(L); }
-
- static int ipairs(lua_State *L)
+ static int index_get(lua_State *L)
{
- lua_engine::object_ptr_vector_wrapper<T> &self(usertype_container::get_self(L));
- stack::push(L, next_pairs);
- stack::push<user<typename usertype_container::indexed_iterator> >(L, self.vec, self.vec.begin());
- stack::push(L, lua_nil);
- return 3;
+ return get(L);
}
};
@@ -300,6 +323,40 @@ bool sol_lua_check(sol::types<osd_file::error>, lua_State *L, int index, Handler
}
+int sol_lua_push(sol::types<screen_type_enum>, lua_State *L, screen_type_enum &&value)
+{
+ switch (value)
+ {
+ case SCREEN_TYPE_INVALID: return sol::stack::push(L, "invalid");
+ case SCREEN_TYPE_RASTER: return sol::stack::push(L, "raster");
+ case SCREEN_TYPE_VECTOR: return sol::stack::push(L, "vector");
+ case SCREEN_TYPE_LCD: return sol::stack::push(L, "svg");
+ case SCREEN_TYPE_SVG: return sol::stack::push(L, "none");
+ }
+ return sol::stack::push(L, "unknown");
+}
+
+int sol_lua_push(sol::types<image_init_result>, lua_State *L, image_init_result &&value)
+{
+ switch (value)
+ {
+ case image_init_result::PASS: return sol::stack::push(L, "pass");
+ case image_init_result::FAIL: return sol::stack::push(L, "fail");
+ }
+ return sol::stack::push(L, "invalid");
+}
+
+int sol_lua_push(sol::types<image_verify_result>, lua_State *L, image_verify_result &&value)
+{
+ switch (value)
+ {
+ case image_verify_result::PASS: return sol::stack::push(L, "pass");
+ case image_verify_result::FAIL: return sol::stack::push(L, "fail");
+ }
+ return sol::stack::push(L, "invalid");
+}
+
+
//-------------------------------------------------
// process_snapshot_filename - processes a snapshot
// filename
@@ -558,14 +615,6 @@ void lua_engine::initialize()
};
- static const enum_parser<ui::text_layout::text_justify, 3> s_text_justify_parser =
- {
- { "left", ui::text_layout::LEFT },
- { "right", ui::text_layout::RIGHT },
- { "center", ui::text_layout::CENTER },
- };
-
-
static const enum_parser<int, 3> s_seek_parser =
{
{ "set", SEEK_SET },
@@ -617,6 +666,7 @@ void lua_engine::initialize()
* emu.device_enumerator(dev) - get device enumerator starting at arbitrary point in tree
* emu.screen_enumerator(dev) - get screen device enumerator starting at arbitrary point in tree
* emu.image_enumerator(dev) - get image interface enumerator starting at arbitrary point in tree
+ * emu.image_enumerator(dev) - get image interface enumerator starting at arbitrary point in tree
*/
sol::table emu = sol().create_named_table("emu");
@@ -712,9 +762,21 @@ void lua_engine::initialize()
osd_subst_env(result, str);
return result;
};
- emu["device_enumerator"] = [] (device_t &d) { return devenum<device_enumerator>(d); };
- emu["screen_enumerator"] = [] (device_t &d) { return devenum<screen_device_enumerator>(d); };
- emu["image_enumerator"] = [] (device_t &d) { return devenum<image_interface_enumerator>(d); };
+ emu["device_enumerator"] = sol::overload(
+ [] (device_t &dev) { return devenum<device_enumerator>(dev); },
+ [] (device_t &dev, int maxdepth) { return devenum<device_enumerator>(dev, maxdepth); });
+ emu["screen_enumerator"] = sol::overload(
+ [] (device_t &dev) { return devenum<screen_device_enumerator>(dev); },
+ [] (device_t &dev, int maxdepth) { return devenum<screen_device_enumerator>(dev, maxdepth); });
+ emu["cassette_enumerator"] = sol::overload(
+ [] (device_t &dev) { return devenum<cassette_device_enumerator>(dev); },
+ [] (device_t &dev, int maxdepth) { return devenum<cassette_device_enumerator>(dev, maxdepth); });
+ emu["image_enumerator"] = sol::overload(
+ [] (device_t &dev) { return devenum<image_interface_enumerator>(dev); },
+ [] (device_t &dev, int maxdepth) { return devenum<image_interface_enumerator>(dev, maxdepth); });
+ emu["slot_enumerator"] = sol::overload(
+ [] (device_t &dev) { return devenum<slot_interface_enumerator>(dev); },
+ [] (device_t &dev, int maxdepth) { return devenum<slot_interface_enumerator>(dev, maxdepth); });
/* emu_file library
@@ -1313,33 +1375,6 @@ void lua_engine::initialize()
game_driver_type["is_incomplete"] = sol::property([] (game_driver const &driver) { return (driver.flags & machine_flags::IS_INCOMPLETE) != 0; });
-/* device_t library
- *
- * manager:machine().devices[device_tag]
- *
- * device:subtag(tag) - get absolute tag relative to this device
- * device:siblingtag(tag) - get absolute tag relative to this device
- * device:memregion(tag) - get memory region
- * device:memshare(tag) - get memory share
- * device:membank(tag) - get memory bank
- * device:ioport(tag) - get I/O port
- * device:subdevice(tag) - get subdevice
- * device:siblingdevice(tag) - get sibling device
- * device:debug() - debug interface, CPUs only
- *
- * device.tag - device tree tag
- * device.basetag - last component of tag ("root" for root device)
- * device.name - device type full name
- * device.shortname - device type short name
- * device.owner - parent device (nil for root device)
- * device.configured - whether configuration is complete
- * device.started - whether the device has been started
- * device.spaces[] - device address spaces table (k=name, v=addr_space)
- * device.state[] - device state entries table (k=name, v=device_state_entry)
- * device.items[] - device save state items table (k=name, v=index)
- * device.roms[] - device rom entry table (k=name, v=rom_entry)
- */
-
auto device_type = sol().registry().new_usertype<device_t>("device", sol::no_constructor);
device_type["subtag"] = &device_t::subtag;
device_type["siblingtag"] = &device_t::siblingtag;
@@ -1349,13 +1384,6 @@ void lua_engine::initialize()
device_type["ioport"] = &device_t::ioport;
device_type["subdevice"] = static_cast<device_t *(device_t::*)(char const *) const>(&device_t::subdevice);
device_type["siblingdevice"] = static_cast<device_t *(device_t::*)(char const *) const>(&device_t::siblingdevice);
- device_type["debug"] =
- [this] (device_t &dev) -> sol::object
- {
- if (!(dev.machine().debug_flags & DEBUG_FLAG_ENABLED) || !dynamic_cast<cpu_device *>(&dev)) // debugger not enabled or not cpu
- return sol::make_object(sol(), sol::lua_nil);
- return sol::make_object(sol(), dev.debug());
- };
device_type["tag"] = sol::property(&device_t::tag);
device_type["basetag"] = sol::property(&device_t::basetag);
device_type["name"] = sol::property(&device_t::name);
@@ -1363,20 +1391,28 @@ void lua_engine::initialize()
device_type["owner"] = sol::property(&device_t::owner);
device_type["configured"] = sol::property(&device_t::configured);
device_type["started"] = sol::property(&device_t::started);
+ device_type["debug"] = sol::property(
+ [this] (device_t &dev) -> sol::object
+ {
+ if (!(dev.machine().debug_flags & DEBUG_FLAG_ENABLED) || !dynamic_cast<cpu_device *>(&dev)) // debugger not enabled or not cpu
+ return sol::make_object(sol(), sol::lua_nil);
+ return sol::make_object(sol(), dev.debug());
+ });
device_type["spaces"] = sol::property(
[this] (device_t &dev)
{
- device_memory_interface *memdev = dynamic_cast<device_memory_interface *>(&dev);
+ device_memory_interface *const memdev = dynamic_cast<device_memory_interface *>(&dev);
sol::table sp_table = sol().create_table();
- if(!memdev)
+ if (!memdev)
return sp_table;
- for(int sp = 0; sp < memdev->max_space_count(); ++sp)
+ for (int sp = 0; sp < memdev->max_space_count(); ++sp)
{
- if(memdev->has_space(sp))
+ if (memdev->has_space(sp))
sp_table[memdev->space(sp).name()] = addr_space(memdev->space(sp), *memdev);
}
return sp_table;
});
+ // FIXME: improve this
device_type["state"] = sol::property(
[this] (device_t &dev)
{
@@ -1388,41 +1424,246 @@ void lua_engine::initialize()
st_table[s->symbol()] = s.get();
return st_table;
});
+ // FIXME: turn into a wrapper - it's stupid slow to walk on every property access
+ // also, this mixes up things like RAM areas with stuff saved by the device itself, so there's potential for key conflicts
device_type["items"] = sol::property(
[this] (device_t &dev)
{
sol::table table = sol().create_table();
- std::string tag = dev.tag();
- // 10000 is enough?
- for(int i = 0; i < 10000; i++)
+ std::string const tag = dev.tag();
+ for (int i = 0; ; i++)
{
- std::string name;
- const char *item;
+ char const *item;
void *base;
uint32_t size, valcount, blockcount, stride;
item = dev.machine().save().indexed_item(i, base, size, valcount, blockcount, stride);
- if(!item)
+ if (!item)
break;
- name = &(strchr(item, '/')[1]);
- if(name.substr(0, name.find('/')) == tag)
- {
- name = name.substr(name.find('/') + 1, std::string::npos);
- table[name] = i;
- }
+
+ char const *name = &strchr(item, '/')[1];
+ if (!strncmp(tag.c_str(), name, tag.length()) && (name[tag.length()] == '/'))
+ table[name + tag.length() + 1] = i;
}
return table;
});
+ // FIXME: this is useless in its current form
device_type["roms"] = sol::property(
[this] (device_t &dev)
{
sol::table table = sol().create_table();
- for(auto rom : dev.rom_region_vector())
- if(!rom.name().empty())
+ for (auto rom : dev.rom_region_vector())
+ if (!rom.name().empty())
table[rom.name()] = rom;
return table;
});
+ auto screen_dev_type = sol().registry().new_usertype<screen_device>(
+ "screen_dev",
+ sol::no_constructor,
+ sol::base_classes, sol::bases<device_t>());
+ screen_dev_type["draw_box"] = sol::overload(
+ [] (screen_device &sdev, float x1, float y1, float x2, float y2, uint32_t fgcolor, uint32_t bgcolor)
+ { do_draw_box(sdev, x1, y1, x2, y2, fgcolor, bgcolor); },
+ [] (screen_device &sdev, float x1, float y1, float x2, float y2, uint32_t fgcolor)
+ { do_draw_box(sdev, x1, y1, x2, y2, fgcolor, mame_machine_manager::instance()->ui().colors().background_color()); },
+ [] (screen_device &sdev, float x1, float y1, float x2, float y2)
+ { auto const &colors(mame_machine_manager::instance()->ui().colors()); do_draw_box(sdev, x1, y1, x2, y2, colors.text_color(), colors.background_color()); });
+ screen_dev_type["draw_line"] = sol::overload(
+ &do_draw_line,
+ [] (screen_device &sdev, float x1, float y1, float x2, float y2)
+ { do_draw_line(sdev, x1, y1, x2, y2, mame_machine_manager::instance()->ui().colors().text_color()); });
+ screen_dev_type["draw_text"] = sol::overload(
+ [this] (screen_device &sdev, sol::object xobj, float y, const char *msg, uint32_t fgcolor, uint32_t bgcolor)
+ { do_draw_text(m_lua_state, sdev, xobj, y, msg, fgcolor, bgcolor); },
+ [this] (screen_device &sdev, sol::object xobj, float y, const char *msg, uint32_t fgcolor)
+ { do_draw_text(m_lua_state, sdev, xobj, y, msg, fgcolor, 0); },
+ [this] (screen_device &sdev, sol::object xobj, float y, const char *msg)
+ { do_draw_text(m_lua_state, sdev, xobj, y, msg, mame_machine_manager::instance()->ui().colors().text_color(), 0); });
+ screen_dev_type["orientation"] =
+ [] (screen_device &sdev)
+ {
+ uint32_t flags = sdev.orientation();
+ int rotation_angle = 0;
+ switch (flags)
+ {
+ case ORIENTATION_SWAP_XY:
+ case ORIENTATION_SWAP_XY | ORIENTATION_FLIP_X:
+ rotation_angle = 90;
+ flags ^= ORIENTATION_FLIP_X;
+ break;
+ case ORIENTATION_FLIP_Y:
+ case ORIENTATION_FLIP_X | ORIENTATION_FLIP_Y:
+ rotation_angle = 180;
+ flags ^= ORIENTATION_FLIP_X | ORIENTATION_FLIP_Y;
+ break;
+ case ORIENTATION_SWAP_XY | ORIENTATION_FLIP_Y:
+ case ORIENTATION_SWAP_XY | ORIENTATION_FLIP_X | ORIENTATION_FLIP_Y:
+ rotation_angle = 270;
+ flags ^= ORIENTATION_FLIP_Y;
+ break;
+ }
+ return std::tuple<int, bool, bool>(rotation_angle, flags & ORIENTATION_FLIP_X, flags & ORIENTATION_FLIP_Y);
+ };
+ screen_dev_type["time_until_pos"] = sol::overload(
+ [] (screen_device &sdev, int vpos) { return sdev.time_until_pos(vpos).as_double(); },
+ [] (screen_device &sdev, int vpos, int hpos) { return sdev.time_until_pos(vpos, hpos).as_double(); });
+ screen_dev_type["time_until_vblank_start"] = &screen_device::time_until_vblank_start;
+ screen_dev_type["time_until_vblank_end"] = &screen_device::time_until_vblank_end;
+ screen_dev_type["snapshot"] =
+ [this] (screen_device &sdev, char const *filename) -> sol::object
+ {
+ std::string snapstr;
+ bool is_absolute_path = false;
+ if (filename)
+ {
+ // a filename was specified; if it isn't absolute post-process it
+ snapstr = process_snapshot_filename(machine(), filename);
+ is_absolute_path = osd_is_absolute_path(snapstr);
+ }
+
+ // open the file
+ emu_file file(is_absolute_path ? "" : machine().options().snapshot_directory(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS);
+ osd_file::error filerr;
+ if (!snapstr.empty())
+ filerr = file.open(snapstr);
+ else
+ filerr = machine().video().open_next(file, "png");
+ if (filerr != osd_file::error::NONE)
+ return sol::make_object(sol(), filerr);
+
+ // and save the snapshot
+ machine().video().save_snapshot(&sdev, file);
+ return sol::make_object(sol(), sol::lua_nil);
+ };
+ screen_dev_type["pixel"] = [] (screen_device &sdev, s32 x, s32 y) { return sdev.pixel(x, y); };
+ screen_dev_type["pixels"] =
+ [] (screen_device &sdev, sol::this_state s)
+ {
+ lua_State *L = s;
+ const rectangle &visarea = sdev.visible_area();
+ luaL_Buffer buff;
+ int size = visarea.height() * visarea.width() * 4;
+ u32 *ptr = (u32 *)luaL_buffinitsize(L, &buff, size);
+ sdev.pixels(ptr);
+ luaL_pushresultsize(&buff, size);
+ return sol::make_reference(L, sol::stack_reference(L, -1));
+ };
+ screen_dev_type["screen_type"] = sol::property(&screen_device::screen_type);
+ screen_dev_type["width"] = sol::property([] (screen_device &sdev) { return sdev.visible_area().width(); });
+ screen_dev_type["height"] = sol::property([] (screen_device &sdev) { return sdev.visible_area().height(); });
+ screen_dev_type["refresh"] = sol::property([] (screen_device &sdev) { return ATTOSECONDS_TO_HZ(sdev.refresh_attoseconds()); });
+ screen_dev_type["refresh_attoseconds"] = sol::property([] (screen_device &sdev) { return sdev.refresh_attoseconds(); });
+ screen_dev_type["xofffset"] = sol::property(&screen_device::xoffset);
+ screen_dev_type["yofffset"] = sol::property(&screen_device::yoffset);
+ screen_dev_type["xscale"] = sol::property(&screen_device::xscale);
+ screen_dev_type["yscale"] = sol::property(&screen_device::yscale);
+ screen_dev_type["pixel_period"] = sol::property([] (screen_device &sdev) { return sdev.pixel_period().as_double(); });
+ screen_dev_type["scan_period"] = sol::property([] (screen_device &sdev) { return sdev.scan_period().as_double(); });
+ screen_dev_type["frame_period"] = sol::property([] (screen_device &sdev) { return sdev.frame_period().as_double(); });
+ screen_dev_type["frame_number"] = &screen_device::frame_number;
+ screen_dev_type["container"] = sol::property(&screen_device::container);
+
+
+ auto cass_type = sol().registry().new_usertype<cassette_image_device>(
+ "cassette",
+ sol::no_constructor,
+ sol::base_classes, sol::bases<device_t, device_image_interface>());
+ cass_type["stop"] = [] (cassette_image_device &c) { c.change_state(CASSETTE_STOPPED, CASSETTE_MASK_UISTATE); };
+ cass_type["play"] = [] (cassette_image_device &c) { c.change_state(CASSETTE_PLAY, CASSETTE_MASK_UISTATE); };
+ cass_type["record"] = [] (cassette_image_device &c) { c.change_state(CASSETTE_RECORD, CASSETTE_MASK_UISTATE); };
+ cass_type["forward"] = &cassette_image_device::go_forward;
+ cass_type["reverse"] = &cassette_image_device::go_reverse;
+ cass_type["seek"] = [] (cassette_image_device &c, double time, const char* origin) { if (c.exists()) c.seek(time, s_seek_parser(origin)); };
+ cass_type["is_stopped"] = sol::property(&cassette_image_device::is_stopped);
+ cass_type["is_playing"] = sol::property(&cassette_image_device::is_playing);
+ cass_type["is_recording"] = sol::property(&cassette_image_device::is_recording);
+ cass_type["motor_state"] = sol::property(&cassette_image_device::motor_on, &cassette_image_device::set_motor);
+ cass_type["speaker_state"] = sol::property(&cassette_image_device::speaker_on, &cassette_image_device::set_speaker);
+ cass_type["position"] = sol::property(&cassette_image_device::get_position);
+ cass_type["length"] = sol::property([] (cassette_image_device &c) { return c.exists() ? c.get_length() : 0.0; });
+
+
+ auto image_type = sol().registry().new_usertype<device_image_interface>("image", "new", sol::no_constructor);
+ image_type["load"] = &device_image_interface::load;
+ image_type["load_software"] = static_cast<image_init_result (device_image_interface::*)(const std::string &)>(&device_image_interface::load_software);
+ image_type["unload"] = &device_image_interface::unload;
+ image_type["create"] = static_cast<image_init_result (device_image_interface::*)(const std::string &)>(&device_image_interface::create);
+ image_type["display"] = &device_image_interface::call_display;
+ image_type["is_readable"] = sol::property(&device_image_interface::is_readable);
+ image_type["is_writeable"] = sol::property(&device_image_interface::is_writeable);
+ image_type["is_creatable"] = sol::property(&device_image_interface::is_creatable);
+ image_type["must_be_loaded"] = sol::property(&device_image_interface::must_be_loaded);
+ image_type["is_reset_on_load"] = sol::property(&device_image_interface::is_reset_on_load);
+ image_type["image_type_name"] = sol::property(&device_image_interface::image_type_name);
+ image_type["instance_name"] = sol::property(&device_image_interface::instance_name);
+ image_type["brief_instance_name"] = sol::property(&device_image_interface::brief_instance_name);
+ image_type["formatlist"] = sol::property([] (device_image_interface &image) { return image_interface_formats(image); });
+ image_type["exists"] = sol::property(&device_image_interface::exists);
+ image_type["readonly"] = sol::property(&device_image_interface::is_readonly);
+ image_type["filename"] = sol::property(&device_image_interface::filename);
+ image_type["crc"] = sol::property(&device_image_interface::crc);
+ image_type["loaded_through_softlist"] = sol::property(&device_image_interface::loaded_through_softlist);
+ image_type["software_list_name"] = sol::property(&device_image_interface::software_list_name);
+ image_type["software_longname"] = sol::property(
+ [] (device_image_interface &di)
+ {
+ software_info const *const si(di.software_entry());
+ return si ? si->longname().c_str() : nullptr;
+ });
+ image_type["software_publisher"] = sol::property(
+ [] (device_image_interface &di)
+ {
+ software_info const *const si(di.software_entry());
+ return si ? si->publisher().c_str() : nullptr;
+ });
+ image_type["software_year"] = sol::property(
+ [] (device_image_interface &di)
+ {
+ software_info const *const si(di.software_entry());
+ return si ? si->year().c_str() : nullptr;
+ });
+ image_type["software_parent"] = sol::property(
+ [] (device_image_interface &di)
+ {
+ software_info const *const si(di.software_entry());
+ return si ? si->parentname().c_str() : nullptr;
+ });
+ image_type["device"] = sol::property(static_cast<device_t & (device_image_interface::*)()>(&device_image_interface::device));
+
+
+ auto format_type = sol().registry().new_usertype<image_device_format>("image_format", sol::no_constructor);
+ format_type["name"] = sol::property(&image_device_format::name);
+ format_type["description"] = sol::property(&image_device_format::description);
+ format_type["extensions"] = sol::property(
+ [this] (image_device_format const &format)
+ {
+ int index = 1;
+ sol::table option_table = sol().create_table();
+ for (std::string const &ext : format.extensions())
+ option_table[index++] = ext;
+ return option_table;
+ });
+ format_type["option_spec"] = sol::property(&image_device_format::optspec);
+
+
+ auto slot_type = sol().registry().new_usertype<device_slot_interface>("slot", sol::no_constructor);
+ slot_type["fixed"] = sol::property(&device_slot_interface::fixed);
+ slot_type["has_selectable_options"] = sol::property(&device_slot_interface::has_selectable_options);
+ slot_type["default_option"] = sol::property(&device_slot_interface::default_option);
+ slot_type["options"] = sol::property([] (device_slot_interface const &slot) { return standard_tag_object_ptr_map<device_slot_interface::slot_option>(slot.option_list()); });
+ slot_type["device"] = sol::property(static_cast<device_t & (device_slot_interface::*)()>(&device_slot_interface::device));
+
+
+ auto dislot_option_type = sol().registry().new_usertype<device_slot_interface::slot_option>("dislot_option", sol::no_constructor);
+ dislot_option_type["name"] = sol::property(&device_slot_interface::slot_option::name);
+ dislot_option_type["device_fullname"] = sol::property([] (device_slot_interface::slot_option &opt) { return opt.devtype().fullname(); });
+ dislot_option_type["device_shortname"] = sol::property([] (device_slot_interface::slot_option &opt) { return opt.devtype().shortname(); });
+ dislot_option_type["selectable"] = sol::property(&device_slot_interface::slot_option::selectable);
+ dislot_option_type["default_bios"] = sol::property(static_cast<char const * (device_slot_interface::slot_option::*)() const>(&device_slot_interface::slot_option::default_bios));
+ dislot_option_type["clock"] = sol::property(static_cast<u32 (device_slot_interface::slot_option::*)() const>(&device_slot_interface::slot_option::clock));
+
+
/* parameters_manager library
*
* manager:machine():parameters()
@@ -1537,160 +1778,6 @@ void lua_engine::initialize()
sound_type.set("attenuation", sol::property(&sound_manager::attenuation, &sound_manager::set_attenuation));
-/* screen_device library
- *
- * manager:machine().screens[screen_tag]
- *
- * screen:draw_box(x1, y1, x2, y2, fillcol, linecol) - draw box from (x1, y1)-(x2, y2) colored linecol
- * filled with fillcol, color is 32bit argb
- * screen:draw_line(x1, y1, x2, y2, linecol) - draw line from (x1, y1)-(x2, y2) colored linecol
- * screen:draw_text(x || justify, y, message, [opt] fgcolor, [opt] bgcolor) - draw message at (x, y) or at line y
- * with left/right/center justification
- * screen:height() - screen height
- * screen:width() - screen width
- * screen:orientation() - screen angle, flipx, flipy
- * screen:refresh() - screen refresh rate in Hz
- * screen:refresh_attoseconds() - screen refresh rate in attoseconds
- * screen:snapshot([opt] filename) - save snap shot
- * screen:type() - screen drawing type
- * screen:frame_number() - screen frame count
- * screen:xscale() - screen x scale factor
- * screen:yscale() - screen y scale factor
- * screen:pixel(x, y) - get pixel at (x, y) as packed RGB in a u32
- * screen:pixels() - get whole screen binary bitmap as string
- * screen:time_until_pos(vpos, hpos) - get the time until this screen pos is reached
- */
-
- auto screen_dev_type = sol().registry().new_usertype<screen_device>(
- "screen_dev",
- sol::no_constructor,
- sol::base_classes, sol::bases<device_t>());
- screen_dev_type.set("container", sol::property(&screen_device::container));
- screen_dev_type.set("draw_box", [](screen_device &sdev, float x1, float y1, float x2, float y2, uint32_t bgcolor, uint32_t fgcolor) {
- int sc_width = sdev.visible_area().width();
- int sc_height = sdev.visible_area().height();
- x1 = std::min(std::max(0.0f, x1), float(sc_width-1)) / float(sc_width);
- y1 = std::min(std::max(0.0f, y1), float(sc_height-1)) / float(sc_height);
- x2 = std::min(std::max(0.0f, x2), float(sc_width-1)) / float(sc_width);
- y2 = std::min(std::max(0.0f, y2), float(sc_height-1)) / float(sc_height);
- mame_machine_manager::instance()->ui().draw_outlined_box(sdev.container(), x1, y1, x2, y2, fgcolor, bgcolor);
- });
- screen_dev_type.set("draw_line", [](screen_device &sdev, float x1, float y1, float x2, float y2, uint32_t color) {
- int sc_width = sdev.visible_area().width();
- int sc_height = sdev.visible_area().height();
- x1 = std::min(std::max(0.0f, x1), float(sc_width-1)) / float(sc_width);
- y1 = std::min(std::max(0.0f, y1), float(sc_height-1)) / float(sc_height);
- x2 = std::min(std::max(0.0f, x2), float(sc_width-1)) / float(sc_width);
- y2 = std::min(std::max(0.0f, y2), float(sc_height-1)) / float(sc_height);
- sdev.container().add_line(x1, y1, x2, y2, UI_LINE_WIDTH, rgb_t(color), PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA));
- });
- screen_dev_type.set("draw_text", [this](screen_device &sdev, sol::object xobj, float y, const char *msg, sol::object color, sol::object bcolor) {
- int sc_width = sdev.visible_area().width();
- int sc_height = sdev.visible_area().height();
- auto justify = ui::text_layout::LEFT;
- float x = 0;
- if(xobj.is<float>())
- {
- x = std::min(std::max(0.0f, xobj.as<float>()), float(sc_width-1)) / float(sc_width);
- y = std::min(std::max(0.0f, y), float(sc_height-1)) / float(sc_height);
- }
- else if(xobj.is<const char *>())
- {
- justify = s_text_justify_parser(xobj.as<const char *>());
- }
- else
- {
- luaL_error(m_lua_state, "Error in param 1 to draw_text");
- return;
- }
- rgb_t textcolor = mame_machine_manager::instance()->ui().colors().text_color();
- rgb_t bgcolor = 0;
- if(color.is<uint32_t>())
- textcolor = rgb_t(color.as<uint32_t>());
- if(bcolor.is<uint32_t>())
- bgcolor = rgb_t(bcolor.as<uint32_t>());
- mame_machine_manager::instance()->ui().draw_text_full(sdev.container(), msg, x, y, (1.0f - x),
- justify, ui::text_layout::WORD, mame_ui_manager::OPAQUE_, textcolor, bgcolor);
- });
- screen_dev_type.set("height", [](screen_device &sdev) { return sdev.visible_area().height(); });
- screen_dev_type.set("width", [](screen_device &sdev) { return sdev.visible_area().width(); });
- screen_dev_type.set("orientation", [](screen_device &sdev) {
- uint32_t flags = sdev.orientation();
- int rotation_angle = 0;
- switch (flags)
- {
- case ORIENTATION_FLIP_X:
- rotation_angle = 0;
- break;
- case ORIENTATION_SWAP_XY:
- case ORIENTATION_SWAP_XY|ORIENTATION_FLIP_X:
- rotation_angle = 90;
- break;
- case ORIENTATION_FLIP_Y:
- case ORIENTATION_FLIP_X|ORIENTATION_FLIP_Y:
- rotation_angle = 180;
- break;
- case ORIENTATION_SWAP_XY|ORIENTATION_FLIP_Y:
- case ORIENTATION_SWAP_XY|ORIENTATION_FLIP_X|ORIENTATION_FLIP_Y:
- rotation_angle = 270;
- break;
- }
- return std::tuple<int, bool, bool>(rotation_angle, flags & ORIENTATION_FLIP_X, flags & ORIENTATION_FLIP_Y);
- });
- screen_dev_type.set("refresh", [](screen_device &sdev) { return ATTOSECONDS_TO_HZ(sdev.refresh_attoseconds()); });
- screen_dev_type.set("refresh_attoseconds", [](screen_device &sdev) { return sdev.refresh_attoseconds(); });
- screen_dev_type.set("snapshot", [this](screen_device &sdev, sol::object filename) -> sol::object {
- std::string snapstr;
- bool is_absolute_path = false;
- if (filename.is<const char *>())
- {
- // a filename was specified; if it isn't absolute postprocess it
- snapstr = process_snapshot_filename(machine(), filename.as<const char *>());
- is_absolute_path = osd_is_absolute_path(snapstr);
- }
-
- // open the file
- emu_file file(is_absolute_path ? "" : machine().options().snapshot_directory(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS);
- osd_file::error filerr;
- if (!snapstr.empty())
- filerr = file.open(snapstr);
- else
- filerr = machine().video().open_next(file, "png");
- if (filerr != osd_file::error::NONE)
- return sol::make_object(sol(), filerr);
-
- // and save the snapshot
- machine().video().save_snapshot(&sdev, file);
- return sol::make_object(sol(), sol::lua_nil);
- });
- screen_dev_type.set("type", [](screen_device &sdev) {
- switch (sdev.screen_type())
- {
- case SCREEN_TYPE_RASTER: return "raster"; break;
- case SCREEN_TYPE_VECTOR: return "vector"; break;
- case SCREEN_TYPE_LCD: return "lcd"; break;
- case SCREEN_TYPE_SVG: return "svg"; break;
- default: break;
- }
- return "unknown";
- });
- screen_dev_type.set("frame_number", &screen_device::frame_number);
- screen_dev_type.set("xscale", &screen_device::xscale);
- screen_dev_type.set("yscale", &screen_device::yscale);
- screen_dev_type.set("pixel", [](screen_device &sdev, float x, float y) { return sdev.pixel((s32)x, (s32)y); });
- screen_dev_type.set("pixels", [](screen_device &sdev, sol::this_state s) {
- lua_State *L = s;
- const rectangle &visarea = sdev.visible_area();
- luaL_Buffer buff;
- int size = visarea.height() * visarea.width() * 4;
- u32 *ptr = (u32 *)luaL_buffinitsize(L, &buff, size);
- sdev.pixels(ptr);
- luaL_pushresultsize(&buff, size);
- return sol::make_reference(L, sol::stack_reference(L, -1));
- });
- screen_dev_type.set("time_until_pos", [](screen_device &sdev, int vpos, int hpos) { return sdev.time_until_pos(vpos, hpos).as_double(); });
-
-
/* mame_ui_manager library
*
* manager:ui()
@@ -1799,160 +1886,6 @@ void lua_engine::initialize()
output_type.set("id_to_name", &output_manager::id_to_name);
-/* device_image_interface library
- *
- * manager:machine().images[image_type]
- *
- * image:exists()
- * image:filename() - full path to the image file
- * image:longname()
- * image:manufacturer()
- * image:year()
- * image:software_list_name()
- * image:image_type_name() - floppy/cart/cdrom/tape/hdd etc
- * image:load(filename)
- * image:load_software(softlist_name)
- * image:unload()
- * image:create()
- * image:crc()
- * image:display()
- *
- * image.device - get associated device_t
- * image.instance_name
- * image.brief_instance_name
- * image.software_parent
- * image.is_readable
- * image.is_writeable
- * image.is_creatable
- * image.is_reset_on_load
- * image.must_be_loaded
- * image.formatlist
- */
-
- auto image_type = sol().registry().new_usertype<device_image_interface>("image", "new", sol::no_constructor);
- image_type.set("exists", &device_image_interface::exists);
- image_type.set("filename", &device_image_interface::filename);
- image_type.set("longname", &device_image_interface::longname);
- image_type.set("manufacturer", &device_image_interface::manufacturer);
- image_type.set("year", &device_image_interface::year);
- image_type.set("software_list_name", &device_image_interface::software_list_name);
- image_type.set("software_parent", sol::property([](device_image_interface &di) {
- const software_info *si = di.software_entry();
- return si ? si->parentname() : "";
- }));
- image_type.set("image_type_name", &device_image_interface::image_type_name);
- image_type.set("load", &device_image_interface::load);
- image_type.set("load_software", static_cast<image_init_result (device_image_interface::*)(const std::string &)>(&device_image_interface::load_software));
- image_type.set("unload", &device_image_interface::unload);
- image_type.set("create", [](device_image_interface &di, const std::string &filename) { return di.create(filename); });
- image_type.set("crc", &device_image_interface::crc);
- image_type.set("display", [](device_image_interface &di) { return di.call_display(); });
- image_type.set("device", sol::property(static_cast<device_t & (device_image_interface::*)()>(&device_image_interface::device)));
- image_type.set("instance_name", sol::property(&device_image_interface::instance_name));
- image_type.set("brief_instance_name", sol::property(&device_image_interface::brief_instance_name));
- image_type.set("is_readable", sol::property(&device_image_interface::is_readable));
- image_type.set("is_writeable", sol::property(&device_image_interface::is_writeable));
- image_type.set("is_creatable", sol::property(&device_image_interface::is_creatable));
- image_type.set("is_reset_on_load", sol::property(&device_image_interface::is_reset_on_load));
- image_type.set("must_be_loaded", sol::property(&device_image_interface::must_be_loaded));
- image_type.set("formatlist", sol::property([](const device_image_interface &image) { return object_ptr_vector_wrapper<image_device_format>(image.formatlist()); }));
-
-
-/* image_device_format library
- *
- * manager:machine().images[tag].formatlist[index]
- *
- * format.name - name of the format (e.g. - "dsk")
- * format.description - the description of the format
- * format.extensions - all of the extensions, as an array
- * format.optspec - the option spec associated with the format
- *
- */
- auto format_type = sol().registry().new_usertype<image_device_format>("image_format", sol::no_constructor);
- format_type["name"] = sol::property(&image_device_format::name);
- format_type["description"] = sol::property(&image_device_format::description);
- format_type["optspec"] = sol::property(&image_device_format::optspec);
- format_type["extensions"] = sol::property([this](const image_device_format &format) {
- int index = 1;
- sol::table option_table = sol().create_table();
- for (const std::string &ext : format.extensions())
- option_table[index++] = ext;
- return option_table;
- });
-
-
-/* device_slot_interface library
- *
- * manager:machine().slots[slot_name]
- *
- * slot.fixed - whether this slot is fixed, and hence not selectable by the user
- * slot.has_selectable_options - does this slot have any selectable options at all?
- * slot.default_option - returns the default option if one exists
- * slot.options[] - get options table (k=name, v=device_slot_interface::slot_option)
- */
-
- auto slot_type = sol().registry().new_usertype<device_slot_interface>("slot", sol::no_constructor);
- slot_type["fixed"] = sol::property(&device_slot_interface::fixed);
- slot_type["has_selectable_options"] = sol::property(&device_slot_interface::has_selectable_options);
- slot_type["default_option"] = sol::property(&device_slot_interface::default_option);
- slot_type["options"] = sol::property([] (device_slot_interface const &slot) { return standard_tag_object_ptr_map<device_slot_interface::slot_option>(slot.option_list()); });
-
-
-/* device_slot_interface::slot_option library
- *
- * manager:machine().slots[slot_name].options[option_name]
- *
- * slot_option.selectable - is this item selectable by the user?
- * slot_option.default_bios - the default bios for this option
- * slot_option.clock - the clock speed associated with this option
- */
-
- auto dislot_option_type = sol().registry().new_usertype<device_slot_interface::slot_option>("dislot_option", sol::no_constructor);
- dislot_option_type["selectable"] = sol::property(&device_slot_interface::slot_option::selectable);
- dislot_option_type["default_bios"] = sol::property(static_cast<char const * (device_slot_interface::slot_option::*)() const>(&device_slot_interface::slot_option::default_bios));
- dislot_option_type["clock"] = sol::property(static_cast<u32 (device_slot_interface::slot_option::*)() const>(&device_slot_interface::slot_option::clock));
-
-
-/* cassette_image_device library
- *
- * manager:machine().cassettes[cass_name]
- *
- * cass:play()
- * cass:stop()
- * cass:record()
- * cass:forward() - forward play direction
- * cass:reverse() - reverse play direction
- * cass:seek(time, origin) - seek time sec from origin: "set", "cur", "end"
- *
- * cass.is_stopped
- * cass.is_playing
- * cass.is_recording
- * cass.motor_state
- * cass.speaker_state
- * cass.position
- * cass.length
- * cass.image - get the device_image_interface for this cassette device
- */
-
- auto cass_type = sol().registry().new_usertype<cassette_image_device>(
- "cassette",
- sol::no_constructor,
- sol::base_classes, sol::bases<device_t, device_image_interface>());
- cass_type["stop"] = [] (cassette_image_device &c) { c.change_state(CASSETTE_STOPPED, CASSETTE_MASK_UISTATE); };
- cass_type["play"] = [] (cassette_image_device &c) { c.change_state(CASSETTE_PLAY, CASSETTE_MASK_UISTATE); };
- cass_type["record"] = [] (cassette_image_device &c) { c.change_state(CASSETTE_RECORD, CASSETTE_MASK_UISTATE); };
- cass_type["forward"] = &cassette_image_device::go_forward;
- cass_type["reverse"] = &cassette_image_device::go_reverse;
- cass_type["seek"] = [] (cassette_image_device &c, double time, const char* origin) { if (c.exists()) c.seek(time, s_seek_parser(origin)); };
- cass_type["is_stopped"] = sol::property(&cassette_image_device::is_stopped);
- cass_type["is_playing"] = sol::property(&cassette_image_device::is_playing);
- cass_type["is_recording"] = sol::property(&cassette_image_device::is_recording);
- cass_type["motor_state"] = sol::property(&cassette_image_device::motor_on, &cassette_image_device::set_motor);
- cass_type["speaker_state"] = sol::property(&cassette_image_device::speaker_on, &cassette_image_device::set_speaker);
- cass_type["position"] = sol::property(&cassette_image_device::get_position);
- cass_type["length"] = sol::property([] (cassette_image_device &c) { return c.exists() ? c.get_length() : 0.0; });
-
-
/* mame_machine_manager library
*
* manager
diff --git a/src/frontend/mame/luaengine.h b/src/frontend/mame/luaengine.h
index b0bbf2210c3..973dfedfd89 100644
--- a/src/frontend/mame/luaengine.h
+++ b/src/frontend/mame/luaengine.h
@@ -34,11 +34,11 @@ public:
// helper structures
template <typename T> struct devenum;
template <typename T> struct simple_list_wrapper;
- template <typename T> struct object_ptr_vector_wrapper;
template <typename T> struct tag_object_ptr_map;
template <typename T> using standard_tag_object_ptr_map = tag_object_ptr_map<std::unordered_map<std::string, std::unique_ptr<T> > >;
template <typename T> struct immutable_container_helper;
template <typename T, typename C, typename I = typename C::iterator> struct immutable_collection_helper;
+ template <typename T, typename C, typename I = typename C::iterator> struct immutable_sequence_helper;
// construction/destruction
lua_engine();
diff --git a/src/frontend/mame/luaengine.ipp b/src/frontend/mame/luaengine.ipp
index 8d51fb0a092..d532b8be1b4 100644
--- a/src/frontend/mame/luaengine.ipp
+++ b/src/frontend/mame/luaengine.ipp
@@ -89,7 +89,6 @@ int sol_lua_push(sol::types<buffer *>, lua_State *L, buffer *value);
template <typename T> struct is_container<lua_engine::devenum<T> > : std::true_type { };
template <typename T> struct is_container<lua_engine::simple_list_wrapper<T> > : std::true_type { };
template <typename T> struct is_container<lua_engine::tag_object_ptr_map<T> > : std::true_type { };
-template <typename T> struct is_container<lua_engine::object_ptr_vector_wrapper<T> > : std::true_type { };
template <typename T> struct usertype_container<lua_engine::devenum<T> >;
@@ -256,7 +255,6 @@ public:
static int ipairs(lua_State *L) { return start_pairs<true>(L); }
};
-
} // namespace sol
@@ -265,10 +263,10 @@ int sol_lua_push(sol::types<osd_file::error>, lua_State *L, osd_file::error &&va
template <typename Handler>
bool sol_lua_check(sol::types<osd_file::error>, lua_State *L, int index, Handler &&handler, sol::stack::record &tracking);
-// map_handler_type customisation
+// enums to automatically convert to strings
int sol_lua_push(sol::types<map_handler_type>, lua_State *L, map_handler_type &&value);
-
-// endianness_t customisation
+int sol_lua_push(sol::types<image_init_result>, lua_State *L, image_init_result &&value);
+int sol_lua_push(sol::types<image_verify_result>, lua_State *L, image_verify_result &&value);
int sol_lua_push(sol::types<endianness_t>, lua_State *L, endianness_t &&value);
@@ -353,6 +351,83 @@ protected:
};
+template <typename T, typename C, typename I>
+struct lua_engine::immutable_sequence_helper : immutable_collection_helper<T, C, I>
+{
+protected:
+ template <bool Indexed>
+ static int next_pairs(lua_State *L)
+ {
+ auto &i(sol::stack::unqualified_get<sol::user<typename immutable_sequence_helper::indexed_iterator> >(L, 1));
+ if (i.src.end() == i.it)
+ return sol::stack::push(L, sol::lua_nil);
+ int result;
+ if constexpr (Indexed)
+ result = sol::stack::push(L, i.ix + 1);
+ else
+ result = T::push_key(L, i.it, i.ix);
+ result += sol::stack::push_reference(L, T::unwrap(i.it));
+ ++i;
+ return result;
+ }
+
+ template <bool Indexed>
+ static int start_pairs(lua_State *L)
+ {
+ T &self(immutable_sequence_helper::get_self(L));
+ sol::stack::push(L, next_pairs<Indexed>);
+ sol::stack::push<sol::user<typename immutable_sequence_helper::indexed_iterator> >(L, self.items(), self.items().begin());
+ sol::stack::push(L, sol::lua_nil);
+ return 3;
+ }
+
+public:
+ static int at(lua_State *L)
+ {
+ T &self(immutable_sequence_helper::get_self(L));
+ std::ptrdiff_t const index(sol::stack::unqualified_get<std::ptrdiff_t>(L, 2));
+ if ((0 >= index) || (self.items().size() < index))
+ return sol::stack::push(L, sol::lua_nil);
+ else
+ return sol::stack::push_reference(L, T::unwrap(std::next(self.items().begin(), index - 1)));
+ }
+
+ static int index_of(lua_State *L)
+ {
+ T &self(immutable_sequence_helper::get_self(L));
+ auto it(self.items().begin());
+ std::ptrdiff_t ix(0);
+ auto const &item(sol::stack::unqualified_get<decltype(T::unwrap(it))>(L, 2));
+ while ((self.items().end() != it) && (&item != &T::unwrap(it)))
+ {
+ ++it;
+ ++ix;
+ }
+ if (self.items().end() == it)
+ return sol::stack::push(L, sol::lua_nil);
+ else
+ return sol::stack::push(L, ix + 1);
+ }
+
+ static int size(lua_State *L)
+ {
+ T &self(immutable_sequence_helper::get_self(L));
+ return sol::stack::push(L, self.items().size());
+ }
+
+ static int empty(lua_State *L)
+ {
+ T &self(immutable_sequence_helper::get_self(L));
+ return sol::stack::push(L, self.items().empty());
+ }
+
+ static int next(lua_State *L) { return sol::stack::push(L, next_pairs<false>); }
+ static int pairs(lua_State *L) { return start_pairs<false>(L); }
+ static int ipairs(lua_State *L) { return start_pairs<true>(L); }
+};
+
+
+
struct lua_engine::addr_space
{
addr_space(address_space &s, device_memory_interface &d) : space(s), dev(d) { }
diff --git a/src/frontend/mame/luaengine_render.cpp b/src/frontend/mame/luaengine_render.cpp
index ca472dba675..b910a717561 100644
--- a/src/frontend/mame/luaengine_render.cpp
+++ b/src/frontend/mame/luaengine_render.cpp
@@ -21,6 +21,10 @@ namespace {
struct layout_file_views
{
layout_file_views(layout_file &f) : file(f) { }
+ layout_file::view_list &items() { return file.views(); }
+
+ static layout_view &unwrap(layout_file::view_list::iterator const &it) { return *it; }
+ static int push_key(lua_State *L, layout_file::view_list::iterator const &it, std::size_t ix) { return sol::stack::push_reference(L, it->unqualified_name()); }
layout_file &file;
};
@@ -29,6 +33,10 @@ struct layout_file_views
struct layout_view_items
{
layout_view_items(layout_view &v) : view(v) { }
+ layout_view::item_list &items() { return view.items(); }
+
+ static layout_view::item &unwrap(layout_view::item_list::iterator const &it) { return *it; }
+ static int push_key(lua_State *L, layout_view::item_list::iterator const &it, std::size_t ix) { return sol::stack::push(L, ix + 1); }
layout_view &view;
};
@@ -53,48 +61,9 @@ template <> struct is_container<render_target_view_names> : std::true_type { };
template <>
-struct usertype_container<layout_file_views> : lua_engine::immutable_collection_helper<layout_file_views, layout_file::view_list>
+struct usertype_container<layout_file_views> : lua_engine::immutable_sequence_helper<layout_file_views, layout_file::view_list>
{
-private:
- using view_list = layout_file::view_list;
-
- template <bool Indexed>
- static int next_pairs(lua_State *L)
- {
- indexed_iterator &i(stack::unqualified_get<user<indexed_iterator> >(L, 1));
- if (i.src.end() == i.it)
- return stack::push(L, lua_nil);
- int result;
- if constexpr (Indexed)
- result = stack::push(L, i.ix + 1);
- else
- result = stack::push_reference(L, i.it->unqualified_name());
- result += stack::push_reference(L, *i.it);
- ++i;
- return result;
- }
-
- template <bool Indexed>
- static int start_pairs(lua_State *L)
- {
- layout_file_views &self(get_self(L));
- stack::push(L, next_pairs<Indexed>);
- stack::push<user<indexed_iterator> >(L, self.file.views(), self.file.views().begin());
- stack::push(L, lua_nil);
- return 3;
- }
-
public:
- static int at(lua_State *L)
- {
- layout_file_views &self(get_self(L));
- std::ptrdiff_t const index(stack::unqualified_get<std::ptrdiff_t>(L, 2));
- if ((0 >= index) || (self.file.views().size() < index))
- return stack::push(L, lua_nil);
- else
- return stack::push_reference(L, *std::next(self.file.views().begin(), index - 1));
- }
-
static int get(lua_State *L)
{
layout_file_views &self(get_self(L));
@@ -113,72 +82,13 @@ public:
{
return get(L);
}
-
- static int index_of(lua_State *L)
- {
- layout_file_views &self(get_self(L));
- layout_view &view(stack::unqualified_get<layout_view>(L, 2));
- auto it(self.file.views().begin());
- std::ptrdiff_t ix(0);
- while ((self.file.views().end() != it) && (&view != &*it))
- {
- ++it;
- ++ix;
- }
- if (self.file.views().end() == it)
- return stack::push(L, lua_nil);
- else
- return stack::push(L, ix + 1);
- }
-
- static int size(lua_State *L)
- {
- layout_file_views &self(get_self(L));
- return stack::push(L, self.file.views().size());
- }
-
- static int empty(lua_State *L)
- {
- layout_file_views &self(get_self(L));
- return stack::push(L, self.file.views().empty());
- }
-
- static int next(lua_State *L) { return stack::push(L, next_pairs<false>); }
- static int pairs(lua_State *L) { return start_pairs<false>(L); }
- static int ipairs(lua_State *L) { return start_pairs<true>(L); }
};
template <>
-struct usertype_container<layout_view_items> : lua_engine::immutable_collection_helper<layout_view_items, layout_view::item_list>
+struct usertype_container<layout_view_items> : lua_engine::immutable_sequence_helper<layout_view_items, layout_view::item_list>
{
-private:
- using item_list = layout_view::item_list;
-
- static int next_pairs(lua_State *L)
- {
- indexed_iterator &i(stack::unqualified_get<user<indexed_iterator> >(L, 1));
- if (i.src.end() == i.it)
- return stack::push(L, lua_nil);
- int result;
- result = stack::push(L, i.ix + 1);
- result += stack::push_reference(L, *i.it);
- ++i.it;
- ++i.ix;
- return result;
- }
-
public:
- static int at(lua_State *L)
- {
- layout_view_items &self(get_self(L));
- std::ptrdiff_t const index(stack::unqualified_get<std::ptrdiff_t>(L, 2));
- if ((0 >= index) || (self.view.items().size() < index))
- return stack::push(L, lua_nil);
- else
- return stack::push_reference(L, *std::next(self.view.items().begin(), index - 1));
- }
-
static int get(lua_State *L)
{
layout_view_items &self(get_self(L));
@@ -195,50 +105,10 @@ public:
return get(L);
}
- static int index_of(lua_State *L)
- {
- layout_view_items &self(get_self(L));
- layout_view::item &item(stack::unqualified_get<layout_view::item>(L, 2));
- auto it(self.view.items().begin());
- std::ptrdiff_t ix(0);
- while ((self.view.items().end() != it) && (&item != &*it))
- {
- ++it;
- ++ix;
- }
- if (self.view.items().end() == it)
- return stack::push(L, lua_nil);
- else
- return stack::push(L, ix + 1);
- }
-
- static int size(lua_State *L)
- {
- layout_view_items &self(get_self(L));
- return stack::push(L, self.view.items().size());
- }
-
- static int empty(lua_State *L)
- {
- layout_view_items &self(get_self(L));
- return stack::push(L, self.view.items().empty());
- }
-
- static int next(lua_State *L) { return stack::push(L, next_pairs); }
-
static int pairs(lua_State *L)
{
return luaL_error(L, "sol: cannot call 'pairs' on type '%s': not iterable by ID", sol::detail::demangle<layout_view_items>().c_str());
}
-
- static int ipairs(lua_State *L)
- {
- layout_view_items &self(get_self(L));
- stack::push(L, next_pairs);
- stack::push<user<indexed_iterator> >(L, self.view.items(), self.view.items().begin());
- stack::push(L, lua_nil);
- return 3;
- }
};
diff --git a/src/frontend/mame/ui/barcode.cpp b/src/frontend/mame/ui/barcode.cpp
index fad2af9ffc6..846f2cc97c5 100644
--- a/src/frontend/mame/ui/barcode.cpp
+++ b/src/frontend/mame/ui/barcode.cpp
@@ -74,8 +74,8 @@ void menu_barcode_reader::populate(float &customtop, float &custombottom)
item_append(_("New Barcode:"), new_barcode, 0, ITEMREF_NEW_BARCODE);
// finish up the menu
- item_append(menu_item_type::SEPARATOR);
item_append(_("Enter Code"), 0, ITEMREF_ENTER_BARCODE);
+ item_append(menu_item_type::SEPARATOR);
customtop = ui().get_line_height() + 3.0f * ui().box_tb_border();
}
@@ -88,9 +88,6 @@ void menu_barcode_reader::populate(float &customtop, float &custombottom)
void menu_barcode_reader::handle()
{
- // rebuild the menu (so to update the selected device, if the user has pressed L or R)
- repopulate(reset_options::REMEMBER_POSITION);
-
// process the menu
const event *event = process(PROCESS_LR_REPEAT);
@@ -127,6 +124,14 @@ void menu_barcode_reader::handle()
}
break;
+ case IPT_UI_CLEAR:
+ if (get_selection_ref() == ITEMREF_NEW_BARCODE)
+ {
+ m_barcode_buffer.clear();
+ reset(reset_options::REMEMBER_POSITION);
+ }
+ break;
+
case IPT_SPECIAL:
if (get_selection_ref() == ITEMREF_NEW_BARCODE)
{
@@ -134,11 +139,6 @@ void menu_barcode_reader::handle()
reset(reset_options::REMEMBER_POSITION);
}
break;
-
- case IPT_UI_CANCEL:
- // reset the char buffer also in this case
- m_barcode_buffer.clear();
- break;
}
}
}
diff --git a/src/frontend/mame/ui/devctrl.h b/src/frontend/mame/ui/devctrl.h
index 1be2385a66f..ec9dc0d2928 100644
--- a/src/frontend/mame/ui/devctrl.h
+++ b/src/frontend/mame/ui/devctrl.h
@@ -84,8 +84,8 @@ int menu_device_control<DeviceType>::current_index()
template<class DeviceType>
void menu_device_control<DeviceType>::previous()
{
- // left arrow - rotate left through cassette devices
- if (m_device != nullptr)
+ // left arrow - rotate left through devices
+ if (m_device && (1 < m_count))
{
enumerator iter(machine().root_device());
int index = iter.indexof(*m_device);
@@ -94,6 +94,7 @@ void menu_device_control<DeviceType>::previous()
else
index = m_count - 1;
m_device = iter.byindex(index);
+ reset(reset_options::REMEMBER_POSITION);
}
}
@@ -106,7 +107,7 @@ template<class DeviceType>
void menu_device_control<DeviceType>::next()
{
// right arrow - rotate right through cassette devices
- if (m_device != nullptr)
+ if (m_device && (1 < m_count))
{
enumerator iter(machine().root_device());
int index = iter.indexof(*m_device);
@@ -115,6 +116,7 @@ void menu_device_control<DeviceType>::next()
else
index = 0;
m_device = iter.byindex(index);
+ reset(reset_options::REMEMBER_POSITION);
}
}
@@ -129,7 +131,7 @@ std::string menu_device_control<DeviceType>::current_display_name()
std::string display_name;
display_name.assign(current_device()->name());
if (count() > 1)
- display_name.append(string_format("%d", current_index() + 1));
+ display_name.append(string_format(" %d", current_index() + 1));
return display_name;
}
diff --git a/src/frontend/mame/ui/devopt.cpp b/src/frontend/mame/ui/devopt.cpp
index e423bfd4370..f5e73f290e0 100644
--- a/src/frontend/mame/ui/devopt.cpp
+++ b/src/frontend/mame/ui/devopt.cpp
@@ -9,12 +9,14 @@
*********************************************************************/
#include "emu.h"
-#include "ui/ui.h"
#include "ui/devopt.h"
+
+#include "ui/ui.h"
#include "romload.h"
namespace ui {
+
/*-------------------------------------------------
device_config - handle the game information
menu
diff --git a/src/frontend/mame/ui/info.cpp b/src/frontend/mame/ui/info.cpp
index 7d11970966f..3a57aac42c0 100644
--- a/src/frontend/mame/ui/info.cpp
+++ b/src/frontend/mame/ui/info.cpp
@@ -567,28 +567,30 @@ void menu_image_info::image_info(device_image_interface *image)
// if image has been loaded through softlist, let's add some more info
if (image->loaded_through_softlist())
{
- // display long filename
- item_append(image->longname(), FLAG_DISABLE, nullptr);
+ software_info const &swinfo(*image->software_entry());
- // display manufacturer and year
- item_append(string_format("%s, %s", image->manufacturer(), image->year()), FLAG_DISABLE, nullptr);
+ // display full name, publisher and year
+ item_append(swinfo.longname(), FLAG_DISABLE, nullptr);
+ item_append(string_format("%1$s, %2$s", swinfo.publisher(), swinfo.year()), FLAG_DISABLE, nullptr);
// display supported information, if available
- switch (image->supported())
+ switch (swinfo.supported())
{
- case SOFTWARE_SUPPORTED_NO:
- item_append(_("Not supported"), FLAG_DISABLE, nullptr);
- break;
- case SOFTWARE_SUPPORTED_PARTIAL:
- item_append(_("Partially supported"), FLAG_DISABLE, nullptr);
- break;
- default:
- break;
+ case SOFTWARE_SUPPORTED_NO:
+ item_append(_("Not supported"), FLAG_DISABLE, nullptr);
+ break;
+ case SOFTWARE_SUPPORTED_PARTIAL:
+ item_append(_("Partially supported"), FLAG_DISABLE, nullptr);
+ break;
+ default:
+ break;
}
}
}
else
+ {
item_append(image->brief_instance_name(), _("[empty]"), 0, nullptr);
+ }
item_append(std::string(), FLAG_DISABLE, nullptr);
}
diff --git a/src/frontend/mame/ui/inifile.cpp b/src/frontend/mame/ui/inifile.cpp
index 253c52c07f3..77dfd1088dc 100644
--- a/src/frontend/mame/ui/inifile.cpp
+++ b/src/frontend/mame/ui/inifile.cpp
@@ -298,11 +298,11 @@ void favorite_manager::add_favorite(running_machine &machine)
// start with simple stuff that can just be copied
info.shortname = software->shortname();
- info.longname = imagedev->longname();
+ info.longname = software->longname();
info.parentname = software->parentname();
- info.year = imagedev->year();
- info.publisher = imagedev->manufacturer();
- info.supported = imagedev->supported();
+ info.year = software->year();
+ info.publisher = software->publisher();
+ info.supported = software->supported();
info.part = part->name();
info.driver = &driver;
info.listname = imagedev->software_list_name();
diff --git a/src/frontend/mame/ui/mainmenu.cpp b/src/frontend/mame/ui/mainmenu.cpp
index 23a68c979c5..1051b322d99 100644
--- a/src/frontend/mame/ui/mainmenu.cpp
+++ b/src/frontend/mame/ui/mainmenu.cpp
@@ -114,7 +114,7 @@ void menu_main::populate(float &customtop, float &custombottom)
item_append(_("Slider Controls"), 0, (void *)SLIDERS);
- item_append(_("Video Options"), 0, (machine().render().target_by_index(1) != nullptr) ? (void *)VIDEO_TARGETS : (void *)VIDEO_OPTIONS);
+ item_append(_("Video Options"), 0, (machine().render().target_by_index(1) || machine().video().snapshot_target().view_name(1)) ? (void *)VIDEO_TARGETS : (void *)VIDEO_OPTIONS);
if (machine().crosshair().get_usage())
item_append(_("Crosshair Options"), 0, (void *)CROSSHAIR);
@@ -229,7 +229,7 @@ void menu_main::handle()
break;
case VIDEO_OPTIONS:
- menu::stack_push<menu_video_options>(ui(), container(), *machine().render().first_target());
+ menu::stack_push<menu_video_options>(ui(), container(), *machine().render().first_target(), false);
break;
case CROSSHAIR:
diff --git a/src/frontend/mame/ui/menu.cpp b/src/frontend/mame/ui/menu.cpp
index 068780f2b6e..4fb9616c355 100644
--- a/src/frontend/mame/ui/menu.cpp
+++ b/src/frontend/mame/ui/menu.cpp
@@ -136,7 +136,6 @@ void menu::global_state::stack_push(std::unique_ptr<menu> &&menu)
{
menu->m_parent = std::move(m_stack);
m_stack = std::move(menu);
- m_stack->reset(reset_options::SELECT_FIRST);
m_stack->machine().ui_input().reset();
}
@@ -289,26 +288,6 @@ void menu::reset(reset_options options)
m_items.clear();
m_visible_items = 0;
m_selected = 0;
-
- // add an item to return
- if (!m_parent)
- {
- item_append(_("Return to Machine"), 0, nullptr);
- }
- else if (m_parent->is_special_main_menu())
- {
- if (machine().options().ui() == emu_options::UI_SIMPLE)
- item_append(_("Exit"), 0, nullptr);
- else
- item_append(_("Exit"), FLAG_LEFT_ARROW | FLAG_RIGHT_ARROW, nullptr);
- }
- else
- {
- if (machine().options().ui() != emu_options::UI_SIMPLE && stack_has_special_main_menu())
- item_append(_("Return to Previous Menu"), FLAG_LEFT_ARROW | FLAG_RIGHT_ARROW, nullptr);
- else
- item_append(_("Return to Previous Menu"), 0, nullptr);
- }
}
@@ -403,17 +382,6 @@ void menu::item_append_on_off(const std::string &text, bool state, uint32_t flag
//-------------------------------------------------
-// repopulate - repopulate menu items
-//-------------------------------------------------
-
-void menu::repopulate(reset_options options)
-{
- reset(options);
- populate(m_customtop, m_custombottom);
-}
-
-
-//-------------------------------------------------
// process - process a menu, drawing it
// and returning any interesting events
//-------------------------------------------------
@@ -1201,8 +1169,31 @@ void menu::validate_selection(int scandir)
void menu::do_handle()
{
- if (m_items.size() < 2)
+ if (m_items.empty())
+ {
+ // add an item to return - this is a really hacky way of doing this
+ if (!m_parent)
+ {
+ item_append(_("Return to Machine"), 0, nullptr);
+ }
+ else if (m_parent->is_special_main_menu())
+ {
+ if (machine().options().ui() == emu_options::UI_SIMPLE)
+ item_append(_("Exit"), 0, nullptr);
+ else
+ item_append(_("Exit"), FLAG_LEFT_ARROW | FLAG_RIGHT_ARROW, nullptr);
+ }
+ else
+ {
+ if (machine().options().ui() != emu_options::UI_SIMPLE && stack_has_special_main_menu())
+ item_append(_("Return to Previous Menu"), FLAG_LEFT_ARROW | FLAG_RIGHT_ARROW, nullptr);
+ else
+ item_append(_("Return to Previous Menu"), 0, nullptr);
+ }
+
+ // let implementation add other items
populate(m_customtop, m_custombottom);
+ }
handle();
}
diff --git a/src/frontend/mame/ui/menu.h b/src/frontend/mame/ui/menu.h
index eacbae32609..8cd0057fc58 100644
--- a/src/frontend/mame/ui/menu.h
+++ b/src/frontend/mame/ui/menu.h
@@ -182,9 +182,6 @@ protected:
void add_cleanup_callback(cleanup_callback &&callback) { m_global_state->add_cleanup_callback(std::move(callback)); }
- // repopulate the menu items
- void repopulate(reset_options options);
-
// process a menu, drawing it and returning any interesting events
const event *process(uint32_t flags, float x0 = 0.0f, float y0 = 0.0f);
void process_parent() { m_parent->process(PROCESS_NOINPUT); }
diff --git a/src/frontend/mame/ui/miscmenu.cpp b/src/frontend/mame/ui/miscmenu.cpp
index 5de57de2ea6..dc5cc2ba9a3 100644
--- a/src/frontend/mame/ui/miscmenu.cpp
+++ b/src/frontend/mame/ui/miscmenu.cpp
@@ -176,33 +176,23 @@ void menu_network_devices::handle()
information menu
-------------------------------------------------*/
-void menu_bookkeeping::handle()
+menu_bookkeeping::menu_bookkeeping(mame_ui_manager &mui, render_container &container) : menu(mui, container)
{
- attotime curtime;
-
- /* if the time has rolled over another second, regenerate */
- curtime = machine().time();
- if (prevtime.seconds() != curtime.seconds())
- {
- prevtime = curtime;
- repopulate(reset_options::SELECT_FIRST);
- }
-
- /* process the menu */
- process(0);
}
-
-/*-------------------------------------------------
- menu_bookkeeping - handle the bookkeeping
- information menu
--------------------------------------------------*/
-menu_bookkeeping::menu_bookkeeping(mame_ui_manager &mui, render_container &container) : menu(mui, container)
+menu_bookkeeping::~menu_bookkeeping()
{
}
-menu_bookkeeping::~menu_bookkeeping()
+void menu_bookkeeping::handle()
{
+ /* process the menu */
+ process(0);
+
+ /* if the time has rolled over another second, regenerate */
+ attotime const curtime = machine().time();
+ if (prevtime.seconds() != curtime.seconds())
+ reset(reset_options::REMEMBER_POSITION);
}
void menu_bookkeeping::populate(float &customtop, float &custombottom)
@@ -212,6 +202,7 @@ void menu_bookkeeping::populate(float &customtop, float &custombottom)
int ctrnum;
/* show total time first */
+ prevtime = machine().time();
if (prevtime.seconds() >= (60 * 60))
util::stream_format(tempstring, _("Uptime: %1$d:%2$02d:%3$02d\n\n"), prevtime.seconds() / (60 * 60), (prevtime.seconds() / 60) % 60, prevtime.seconds() % 60);
else
diff --git a/src/frontend/mame/ui/tapectrl.cpp b/src/frontend/mame/ui/tapectrl.cpp
index 75d62038931..720622f0e81 100644
--- a/src/frontend/mame/ui/tapectrl.cpp
+++ b/src/frontend/mame/ui/tapectrl.cpp
@@ -116,14 +116,11 @@ void menu_tape_control::populate(float &customtop, float &custombottom)
void menu_tape_control::handle()
{
- // rebuild the menu (so to update the selected device, if the user has pressed L or R, and the tape counter)
- repopulate(reset_options::REMEMBER_POSITION);
-
// process the menu
const event *event = process(PROCESS_LR_REPEAT);
if (event != nullptr)
{
- switch(event->iptkey)
+ switch (event->iptkey)
{
case IPT_UI_LEFT:
if (event->itemref == TAPECMD_SLIDER)
@@ -155,6 +152,9 @@ void menu_tape_control::handle()
break;
}
}
+
+ // hacky way to update the tape counter by repopulating every frame
+ reset(reset_options::REMEMBER_POSITION);
}
diff --git a/src/frontend/mame/ui/videoopt.cpp b/src/frontend/mame/ui/videoopt.cpp
index ccb39306208..21ba181ecb7 100644
--- a/src/frontend/mame/ui/videoopt.cpp
+++ b/src/frontend/mame/ui/videoopt.cpp
@@ -55,6 +55,10 @@ void menu_video_targets::populate(float &customtop, float &custombottom)
// add a menu item
item_append(util::string_format(_("Screen #%d"), targetnum), 0, target);
}
+
+ // add option for snapshot target if it has multiple views
+ if (machine().video().snapshot_target().view_name(1))
+ item_append("Snapshot", 0, &machine().video().snapshot_target());
}
/*-------------------------------------------------
@@ -66,7 +70,15 @@ void menu_video_targets::handle()
{
event const *const menu_event = process(0);
if (menu_event && (menu_event->iptkey == IPT_UI_SELECT))
- menu::stack_push<menu_video_options>(ui(), container(), *reinterpret_cast<render_target *>(menu_event->itemref));
+ {
+ render_target *const target = reinterpret_cast<render_target *>(menu_event->itemref);
+ menu::stack_push<menu_video_options>(
+ ui(),
+ container(),
+ std::string(selected_item().text),
+ *target,
+ &machine().video().snapshot_target() == target);
+ }
}
@@ -75,10 +87,35 @@ void menu_video_targets::handle()
video options menu
-------------------------------------------------*/
-menu_video_options::menu_video_options(mame_ui_manager &mui, render_container &container, render_target &target)
+menu_video_options::menu_video_options(
+ mame_ui_manager &mui,
+ render_container &container,
+ render_target &target,
+ bool snapshot)
: menu(mui, container)
, m_target(target)
+ , m_title()
+ , m_show_title(false)
+ , m_snapshot(snapshot)
{
+ set_selected_index(target.view());
+ reset(reset_options::REMEMBER_POSITION);
+}
+
+menu_video_options::menu_video_options(
+ mame_ui_manager &mui,
+ render_container &container,
+ std::string &&title,
+ render_target &target,
+ bool snapshot)
+ : menu(mui, container)
+ , m_target(target)
+ , m_title(std::move(title))
+ , m_show_title(true)
+ , m_snapshot(snapshot)
+{
+ set_selected_index(target.view() + 2);
+ reset(reset_options::REMEMBER_POSITION);
}
menu_video_options::~menu_video_options()
@@ -89,6 +126,13 @@ void menu_video_options::populate(float &customtop, float &custombottom)
{
uintptr_t ref;
+ // add title if requested
+ if (m_show_title)
+ {
+ item_append(m_title, FLAG_DISABLE, nullptr);
+ item_append(menu_item_type::SEPARATOR);
+ }
+
// add items for each view
for (char const *name = m_target.view_name(ref = 0); name; name = m_target.view_name(++ref))
item_append(name, 0, reinterpret_cast<void *>(ITEM_VIEW_FIRST + ref));
@@ -127,33 +171,36 @@ void menu_video_options::populate(float &customtop, float &custombottom)
// cropping
item_append_on_off(_("Zoom to Screen Area"), m_target.zoom_to_screen(), 0, reinterpret_cast<void *>(ITEM_ZOOM));
- // uneven stretch
- switch (m_target.scale_mode())
+ if (!m_snapshot)
{
- case SCALE_FRACTIONAL:
- subtext = _("On");
- break;
+ // uneven stretch
+ switch (m_target.scale_mode())
+ {
+ case SCALE_FRACTIONAL:
+ subtext = _("On");
+ break;
+
+ case SCALE_FRACTIONAL_X:
+ subtext = _("X Only");
+ break;
- case SCALE_FRACTIONAL_X:
- subtext = _("X Only");
- break;
+ case SCALE_FRACTIONAL_Y:
+ subtext = _("Y Only");
+ break;
- case SCALE_FRACTIONAL_Y:
- subtext = _("Y Only");
- break;
+ case SCALE_FRACTIONAL_AUTO:
+ subtext = _("X or Y (Auto)");
+ break;
- case SCALE_FRACTIONAL_AUTO:
- subtext = _("X or Y (Auto)");
- break;
+ case SCALE_INTEGER:
+ subtext = _("Off");
+ break;
+ }
+ item_append(_("Non-Integer Scaling"), subtext, FLAG_LEFT_ARROW | FLAG_RIGHT_ARROW, reinterpret_cast<void *>(ITEM_UNEVENSTRETCH));
- case SCALE_INTEGER:
- subtext = _("Off");
- break;
+ // keep aspect
+ item_append_on_off(_("Maintain Aspect Ratio"), m_target.keepaspect(), 0, reinterpret_cast<void *>(ITEM_KEEPASPECT));
}
- item_append(_("Non-Integer Scaling"), subtext, FLAG_LEFT_ARROW | FLAG_RIGHT_ARROW, reinterpret_cast<void *>(ITEM_UNEVENSTRETCH));
-
- // keep aspect
- item_append_on_off(_("Keep Aspect"), m_target.keepaspect(), 0, reinterpret_cast<void *>(ITEM_KEEPASPECT));
}
@@ -164,6 +211,8 @@ void menu_video_options::populate(float &customtop, float &custombottom)
void menu_video_options::handle()
{
+ auto const lockout_popup([this] () { machine().popmessage(_("Cannot change options while recording!")); });
+ bool const snap_lockout(m_snapshot && machine().video().is_recording());
bool changed(false);
// process the menu
@@ -176,6 +225,8 @@ void menu_video_options::handle()
case ITEM_ROTATE:
if (menu_event->iptkey == IPT_UI_LEFT || menu_event->iptkey == IPT_UI_RIGHT)
{
+ if (snap_lockout)
+ return lockout_popup();
int const delta((menu_event->iptkey == IPT_UI_LEFT) ? ROT270 : ROT90);
m_target.set_orientation(orientation_add(delta, m_target.orientation()));
if (m_target.is_ui_target())
@@ -192,6 +243,8 @@ void menu_video_options::handle()
case ITEM_ZOOM:
if ((menu_event->iptkey == IPT_UI_LEFT) || (menu_event->iptkey == IPT_UI_RIGHT))
{
+ if (snap_lockout)
+ return lockout_popup();
m_target.set_zoom_to_screen(menu_event->iptkey == IPT_UI_RIGHT);
changed = true;
}
@@ -201,6 +254,8 @@ void menu_video_options::handle()
case ITEM_UNEVENSTRETCH:
if (menu_event->iptkey == IPT_UI_LEFT)
{
+ if (snap_lockout)
+ return lockout_popup();
switch (m_target.scale_mode())
{
case SCALE_FRACTIONAL:
@@ -227,6 +282,8 @@ void menu_video_options::handle()
}
else if (menu_event->iptkey == IPT_UI_RIGHT)
{
+ if (snap_lockout)
+ return lockout_popup();
switch (m_target.scale_mode())
{
case SCALE_FRACTIONAL:
@@ -257,6 +314,8 @@ void menu_video_options::handle()
case ITEM_KEEPASPECT:
if ((menu_event->iptkey == IPT_UI_LEFT) || (menu_event->iptkey == IPT_UI_RIGHT))
{
+ if (snap_lockout)
+ return lockout_popup();
m_target.set_keepaspect(menu_event->iptkey == IPT_UI_RIGHT);
changed = true;
}
@@ -266,6 +325,8 @@ void menu_video_options::handle()
default:
if (reinterpret_cast<uintptr_t>(menu_event->itemref) >= ITEM_VIEW_FIRST)
{
+ if (snap_lockout)
+ return lockout_popup();
if (menu_event->iptkey == IPT_UI_SELECT)
{
m_target.set_view(reinterpret_cast<uintptr_t>(menu_event->itemref) - ITEM_VIEW_FIRST);
@@ -274,6 +335,8 @@ void menu_video_options::handle()
}
else if (reinterpret_cast<uintptr_t>(menu_event->itemref) >= ITEM_TOGGLE_FIRST)
{
+ if (snap_lockout)
+ return lockout_popup();
if ((menu_event->iptkey == IPT_UI_LEFT) || (menu_event->iptkey == IPT_UI_RIGHT))
{
m_target.set_visibility_toggle(reinterpret_cast<uintptr_t>(menu_event->itemref) - ITEM_TOGGLE_FIRST, menu_event->iptkey == IPT_UI_RIGHT);
@@ -284,7 +347,7 @@ void menu_video_options::handle()
}
}
- /* if something changed, rebuild the menu */
+ // if something changed, rebuild the menu
if (changed)
reset(reset_options::REMEMBER_REF);
}
diff --git a/src/frontend/mame/ui/videoopt.h b/src/frontend/mame/ui/videoopt.h
index a70e7b8aa94..44a172cf8f5 100644
--- a/src/frontend/mame/ui/videoopt.h
+++ b/src/frontend/mame/ui/videoopt.h
@@ -32,7 +32,8 @@ private:
class menu_video_options : public menu
{
public:
- menu_video_options(mame_ui_manager &mui, render_container &container, render_target &target);
+ menu_video_options(mame_ui_manager &mui, render_container &container, render_target &target, bool snapshot);
+ menu_video_options(mame_ui_manager &mui, render_container &container, std::string &&title, render_target &target, bool snapshot);
virtual ~menu_video_options() override;
private:
@@ -40,6 +41,9 @@ private:
virtual void handle() override;
render_target &m_target;
+ std::string const m_title;
+ bool const m_show_title;
+ bool const m_snapshot;
};
} // namespace ui
> AM_RANGE(0xa802, 0xa802) AM_WRITE(bank_select_w) AM_RANGE(0xa803, 0xa803) AM_READWRITE(pix2_r, pix2_w) //pixel layer related AM_RANGE(0xa804, 0xa804) AM_READWRITE(from_snd_r, sound_command_w) AM_RANGE(0xa805, 0xa805) AM_READ(snd_flag_r) AM_WRITENOP /*sound_reset*/ //???? AM_RANGE(0xa807, 0xa807) AM_READNOP AM_WRITENOP /* unknown */ AM_RANGE(0xa808, 0xa808) AM_READ_PORT("DSW3") AM_RANGE(0xa809, 0xa809) AM_READ_PORT("P1") AM_RANGE(0xa80a, 0xa80a) AM_READ_PORT("SYSTEM") AM_RANGE(0xa80b, 0xa80b) AM_READ_PORT("P2") AM_RANGE(0xa80c, 0xa80c) AM_READ_PORT("DSW1") AM_WRITE_LEGACY(fortyl_pixram_sel_w) /* pixram bank select */ AM_RANGE(0xa80d, 0xa80d) AM_READ_PORT("DSW2") AM_WRITENOP /* unknown */ AM_RANGE(0xb000, 0xb7ff) AM_READWRITE_LEGACY(fortyl_bg_videoram_r, fortyl_bg_videoram_w) AM_BASE(m_videoram) /* #1 M5517P on video board */ AM_RANGE(0xb800, 0xb83f) AM_RAM AM_BASE(m_video_ctrl) /* video control area */ AM_RANGE(0xb840, 0xb87f) AM_RAM AM_BASE_SIZE(m_spriteram, m_spriteram_size) /* sprites part 1 */ AM_RANGE(0xb880, 0xb8bf) AM_READWRITE_LEGACY(fortyl_bg_colorram_r, fortyl_bg_colorram_w) AM_BASE(m_colorram) /* background attributes (2 bytes per line) */ AM_RANGE(0xb8e0, 0xb8ff) AM_RAM AM_BASE_SIZE(m_spriteram2, m_spriteram2_size) /* sprites part 2 */ AM_RANGE(0xc000, 0xffff) AM_READWRITE_LEGACY(fortyl_pixram_r, fortyl_pixram_w) ADDRESS_MAP_END static MACHINE_RESET( ta7630 ) { fortyl_state *state = machine.driver_data<fortyl_state>(); int i; double db = 0.0; double db_step = 1.50; /* 1.50 dB step (at least, maybe more) */ double db_step_inc = 0.125; for (i = 0; i < 16; i++) { double max = 100.0 / pow(10.0, db/20.0); state->m_vol_ctrl[15 - i] = max; /*logerror("vol_ctrl[%x] = %i (%f dB)\n", 15 - i, state->m_vol_ctrl[15 - i], db);*/ db += db_step; db_step += db_step_inc; } /* for (i = 0; i < 8; i++) logerror("SOUND Chan#%i name=%s\n", i, mixer_get_name(i) ); */ /* channels 0-2 AY#0 channels 3,4 MSM5232 group1,group2 */ } static WRITE8_DEVICE_HANDLER( sound_control_0_w ) { fortyl_state *state = device->machine().driver_data<fortyl_state>(); state->m_snd_ctrl0 = data & 0xff; // popmessage("SND0 0=%02x 1=%02x 2=%02x 3=%02x", state->m_snd_ctrl0, state->m_snd_ctrl1, state->m_snd_ctrl2, state->m_snd_ctrl3); /* this definitely controls main melody voice on 2'-1 and 4'-1 outputs */ device_sound_interface *sound; device->interface(sound); sound->set_output_gain(0, state->m_vol_ctrl[(state->m_snd_ctrl0 >> 4) & 15] / 100.0); /* group1 from msm5232 */ sound->set_output_gain(1, state->m_vol_ctrl[(state->m_snd_ctrl0 >> 4) & 15] / 100.0); /* group1 from msm5232 */ sound->set_output_gain(2, state->m_vol_ctrl[(state->m_snd_ctrl0 >> 4) & 15] / 100.0); /* group1 from msm5232 */ sound->set_output_gain(3, state->m_vol_ctrl[(state->m_snd_ctrl0 >> 4) & 15] / 100.0); /* group1 from msm5232 */ } static WRITE8_DEVICE_HANDLER( sound_control_1_w ) { fortyl_state *state = device->machine().driver_data<fortyl_state>(); state->m_snd_ctrl1 = data & 0xff; // popmessage("SND1 0=%02x 1=%02x 2=%02x 3=%02x", state->m_snd_ctrl0, state->m_snd_ctrl1, state->m_snd_ctrl2, state->m_snd_ctrl3); device_sound_interface *sound; device->interface(sound); sound->set_output_gain(4, state->m_vol_ctrl[(state->m_snd_ctrl1 >> 4) & 15] / 100.0); /* group2 from msm5232 */ sound->set_output_gain(5, state->m_vol_ctrl[(state->m_snd_ctrl1 >> 4) & 15] / 100.0); /* group2 from msm5232 */ sound->set_output_gain(6, state->m_vol_ctrl[(state->m_snd_ctrl1 >> 4) & 15] / 100.0); /* group2 from msm5232 */ sound->set_output_gain(7, state->m_vol_ctrl[(state->m_snd_ctrl1 >> 4) & 15] / 100.0); /* group2 from msm5232 */ } static WRITE8_DEVICE_HANDLER( sound_control_2_w ) { fortyl_state *state = device->machine().driver_data<fortyl_state>(); int i; state->m_snd_ctrl2 = data & 0xff; // popmessage("SND2 0=%02x 1=%02x 2=%02x 3=%02x", state->m_snd_ctrl0, state->m_snd_ctrl1, state->m_snd_ctrl2, state->m_snd_ctrl3); device_sound_interface *sound; device->interface(sound); for (i = 0; i < 3; i++) sound->set_output_gain(i, state->m_vol_ctrl[(state->m_snd_ctrl2 >> 4) & 15] / 100.0); /* ym2149f all */ } static WRITE8_DEVICE_HANDLER( sound_control_3_w ) /* unknown */ { fortyl_state *state = device->machine().driver_data<fortyl_state>(); state->m_snd_ctrl3 = data & 0xff; // popmessage("SND3 0=%02x 1=%02x 2=%02x 3=%02x", state->m_snd_ctrl0, state->m_snd_ctrl1, state->m_snd_ctrl2, state->m_snd_ctrl3); } static ADDRESS_MAP_START( sound_map, AS_PROGRAM, 8, fortyl_state ) AM_RANGE(0x0000, 0xbfff) AM_ROM AM_RANGE(0xc000, 0xc7ff) AM_RAM AM_RANGE(0xc800, 0xc801) AM_DEVWRITE_LEGACY("aysnd", ay8910_address_data_w) AM_RANGE(0xca00, 0xca0d) AM_DEVWRITE_LEGACY("msm", msm5232_w) AM_RANGE(0xcc00, 0xcc00) AM_DEVWRITE_LEGACY("msm", sound_control_0_w) AM_RANGE(0xce00, 0xce00) AM_DEVWRITE_LEGACY("msm", sound_control_1_w) AM_RANGE(0xd800, 0xd800) AM_READ_LEGACY(soundlatch_r) AM_WRITE(to_main_w) AM_RANGE(0xda00, 0xda00) AM_READNOP AM_WRITE(nmi_enable_w) /* unknown read */ AM_RANGE(0xdc00, 0xdc00) AM_WRITE(nmi_disable_w) AM_RANGE(0xde00, 0xde00) AM_READNOP AM_DEVWRITE_LEGACY("dac", dac_signed_w) /* signed 8-bit DAC - unknown read */ AM_RANGE(0xe000, 0xefff) AM_ROM /* space for diagnostics ROM */ ADDRESS_MAP_END static INPUT_PORTS_START( 40love ) PORT_START("DSW1") PORT_DIPUNKNOWN_DIPLOC( 0x01, 0x01, "SW1:1" ) PORT_DIPUNKNOWN_DIPLOC( 0x02, 0x02, "SW1:2" ) PORT_DIPNAME( 0x04, 0x04, DEF_STR( Free_Play ) ) PORT_DIPLOCATION("SW1:3") PORT_DIPSETTING( 0x04, DEF_STR( Off ) ) PORT_DIPSETTING( 0x00, DEF_STR( On ) ) PORT_DIPNAME( 0x18, 0x10, DEF_STR( Lives ) ) PORT_DIPLOCATION("SW1:4,5") PORT_DIPSETTING( 0x00, "1" ) PORT_DIPSETTING( 0x08, "2" ) PORT_DIPSETTING( 0x10, "3" ) PORT_DIPSETTING( 0x18, "4" ) PORT_DIPUNKNOWN_DIPLOC( 0x20, 0x20, "SW1:6" ) PORT_DIPNAME( 0x40, 0x00, DEF_STR( Flip_Screen ) ) PORT_DIPLOCATION("SW1:7") PORT_DIPSETTING( 0x00, DEF_STR( Off ) ) PORT_DIPSETTING( 0x40, DEF_STR( On ) ) PORT_DIPNAME( 0x80, 0x00, DEF_STR( Cabinet ) ) PORT_DIPLOCATION("SW1:8") PORT_DIPSETTING( 0x00, DEF_STR( Upright ) ) PORT_DIPSETTING( 0x80, DEF_STR( Cocktail ) ) PORT_START("DSW2") /* All OK */ PORT_DIPNAME( 0x0f, 0x00, DEF_STR( Coin_A ) ) PORT_DIPLOCATION("SW2:1,2,3,4") PORT_DIPSETTING( 0x0f, DEF_STR( 9C_1C ) ) PORT_DIPSETTING( 0x0e, DEF_STR( 8C_1C ) ) PORT_DIPSETTING( 0x0d, DEF_STR( 7C_1C ) ) PORT_DIPSETTING( 0x0c, DEF_STR( 6C_1C ) ) PORT_DIPSETTING( 0x0b, DEF_STR( 5C_1C ) ) PORT_DIPSETTING( 0x0a, DEF_STR( 4C_1C ) ) PORT_DIPSETTING( 0x09, DEF_STR( 3C_1C ) ) PORT_DIPSETTING( 0x08, DEF_STR( 2C_1C ) ) PORT_DIPSETTING( 0x00, DEF_STR( 1C_1C ) ) PORT_DIPSETTING( 0x01, DEF_STR( 1C_2C ) ) PORT_DIPSETTING( 0x02, DEF_STR( 1C_3C ) ) PORT_DIPSETTING( 0x03, DEF_STR( 1C_4C ) ) PORT_DIPSETTING( 0x04, DEF_STR( 1C_5C ) ) PORT_DIPSETTING( 0x05, DEF_STR( 1C_6C ) ) PORT_DIPSETTING( 0x06, DEF_STR( 1C_7C ) ) PORT_DIPSETTING( 0x07, DEF_STR( 1C_8C ) ) PORT_DIPNAME( 0xf0, 0x00, DEF_STR( Coin_B ) ) PORT_DIPLOCATION("SW2:5,6,7,8") PORT_DIPSETTING( 0xf0, DEF_STR( 9C_1C ) ) PORT_DIPSETTING( 0xe0, DEF_STR( 8C_1C ) ) PORT_DIPSETTING( 0xd0, DEF_STR( 7C_1C ) ) PORT_DIPSETTING( 0xc0, DEF_STR( 6C_1C ) ) PORT_DIPSETTING( 0xb0, DEF_STR( 5C_1C ) ) PORT_DIPSETTING( 0xa0, DEF_STR( 4C_1C ) ) PORT_DIPSETTING( 0x90, DEF_STR( 3C_1C ) ) PORT_DIPSETTING( 0x80, DEF_STR( 2C_1C ) ) PORT_DIPSETTING( 0x00, DEF_STR( 1C_1C ) ) PORT_DIPSETTING( 0x10, DEF_STR( 1C_2C ) ) PORT_DIPSETTING( 0x20, DEF_STR( 1C_3C ) ) PORT_DIPSETTING( 0x30, DEF_STR( 1C_4C ) ) PORT_DIPSETTING( 0x40, DEF_STR( 1C_5C ) ) PORT_DIPSETTING( 0x50, DEF_STR( 1C_6C ) ) PORT_DIPSETTING( 0x60, DEF_STR( 1C_7C ) ) PORT_DIPSETTING( 0x70, DEF_STR( 1C_8C ) ) PORT_START("DSW3") PORT_DIPUNKNOWN_DIPLOC( 0x01, 0x01, "SW3:1" ) PORT_DIPUNKNOWN_DIPLOC( 0x02, 0x02, "SW3:2" ) PORT_DIPUNKNOWN_DIPLOC( 0x04, 0x04, "SW3:3" ) PORT_DIPUNKNOWN_DIPLOC( 0x08, 0x08, "SW3:4" ) PORT_DIPNAME( 0x10, 0x10, "Display Credit Settings" ) PORT_DIPLOCATION("SW3:5") PORT_DIPSETTING( 0x00, DEF_STR( Off ) ) PORT_DIPSETTING( 0x10, DEF_STR( On ) ) PORT_DIPNAME( 0x20, 0x20, "Year Display" ) PORT_DIPLOCATION("SW3:6") PORT_DIPSETTING( 0x00, DEF_STR( Off ) ) PORT_DIPSETTING( 0x20, DEF_STR( On ) ) PORT_DIPNAME( 0x40, 0x40, "Score points to: (Cheat)") PORT_DIPLOCATION("SW3:7") PORT_DIPSETTING( 0x40, "Winner" ) PORT_DIPSETTING( 0x00, "Human" ) PORT_DIPNAME( 0x80, 0x00, "Coin Door Type" ) PORT_DIPLOCATION("SW3:8") PORT_DIPSETTING( 0x00, "Single Slot" ) PORT_DIPSETTING( 0x80, "Double Slot" ) PORT_START("SYSTEM") PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_UNKNOWN ) //?? PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_UNKNOWN ) //?? PORT_BIT( 0x04, IP_ACTIVE_HIGH,IPT_COIN1 ) //OK PORT_BIT( 0x08, IP_ACTIVE_HIGH,IPT_COIN2 ) //OK PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_START1 ) //OK PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_START2 ) //OK PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_SERVICE1 ) //OK PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_TILT ) //OK PORT_START("P1") PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_4WAY PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_4WAY PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_4WAY PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_4WAY PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_BUTTON4 ) PORT_START("P2") PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_4WAY PORT_COCKTAIL PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_4WAY PORT_COCKTAIL PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_4WAY PORT_COCKTAIL PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_4WAY PORT_COCKTAIL PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_COCKTAIL PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_COCKTAIL PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_COCKTAIL PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_BUTTON4 ) PORT_COCKTAIL INPUT_PORTS_END static INPUT_PORTS_START( undoukai ) PORT_INCLUDE( 40love ) PORT_MODIFY("DSW1") PORT_DIPNAME( 0x03, 0x03, DEF_STR( Difficulty ) ) PORT_DIPLOCATION("SW1:1,2") PORT_DIPSETTING( 0x00, "4 (Hard)" ) PORT_DIPSETTING( 0x01, "3" ) PORT_DIPSETTING( 0x02, "2" ) PORT_DIPSETTING( 0x03, "1 (Easy)" ) PORT_DIPNAME( 0x08, 0x08, DEF_STR( Lives ) ) PORT_DIPLOCATION("SW1:4") PORT_DIPSETTING( 0x08, "1" ) PORT_DIPSETTING( 0x00, "2" ) PORT_DIPNAME( 0x10, 0x10, DEF_STR( Bonus_Life ) ) PORT_DIPLOCATION("SW1:5") PORT_DIPSETTING( 0x10, DEF_STR( None ) ) PORT_DIPSETTING( 0x00, "100000 200000" ) PORT_DIPNAME( 0x20, 0x20, DEF_STR( Players ) ) PORT_DIPLOCATION("SW1:6") PORT_DIPSETTING( 0x20, "1 Or 2" ) PORT_DIPSETTING( 0x00, "1 To 4" ) PORT_DIPNAME( 0x40, 0x40, DEF_STR( Flip_Screen ) ) PORT_DIPLOCATION("SW1:7") PORT_DIPSETTING( 0x40, DEF_STR( Off ) ) PORT_DIPSETTING( 0x00, DEF_STR( On ) ) PORT_MODIFY("DSW3") /* & START */ PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_START2 ) PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_START1 ) PORT_DIPNAME( 0x04, 0x04, DEF_STR( Demo_Sounds ) ) PORT_DIPLOCATION("SW3:3") PORT_DIPSETTING( 0x00, DEF_STR( Off ) ) PORT_DIPSETTING( 0x04, DEF_STR( On ) ) PORT_DIPNAME( 0x08, 0x08, "Freeze" ) PORT_DIPLOCATION("SW3:4") PORT_DIPSETTING( 0x08, DEF_STR( Off ) ) PORT_DIPSETTING( 0x00, DEF_STR( On ) ) PORT_DIPNAME( 0x40, 0x40, "No Qualify (Cheat)") PORT_DIPLOCATION("SW3:7") PORT_DIPSETTING( 0x40, DEF_STR( Off ) ) PORT_DIPSETTING( 0x00, DEF_STR( On ) ) PORT_MODIFY("SYSTEM") PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_UNKNOWN ) PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_UNKNOWN ) PORT_MODIFY("P1") PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(2) PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(2) PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_PLAYER(2) PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_START3 ) PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_START4 ) PORT_MODIFY("P2") PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(3) PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(3) PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_PLAYER(3) PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(4) PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(4) PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_PLAYER(4) PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_UNKNOWN ) PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_UNKNOWN ) INPUT_PORTS_END static const gfx_layout char_layout = { 8,8, 0x400, 4, { 2*0x2000*8+0, 2*0x2000*8+4, 0,4 }, { 3,2,1,0, 11,10,9,8 }, { 0*8,2*8,4*8,6*8,8*8,10*8,12*8,14*8 }, 16*8 }; static const gfx_layout sprite_layout = { 16,16, RGN_FRAC(1,2), 4, { RGN_FRAC(1,2)+0, RGN_FRAC(1,2)+4, 0,4 }, { 3,2,1,0, 11,10,9,8, 16*8+3, 16*8+2, 16*8+1, 16*8+0, 16*8+11, 16*8+10, 16*8+9, 16*8+8 }, { 0*16, 1*16, 2*16, 3*16, 4*16, 5*16, 6*16, 7*16, 16*16, 17*16, 18*16, 19*16, 20*16, 21*16, 22*16, 23*16 }, 64*8 }; static GFXDECODE_START( 40love ) GFXDECODE_ENTRY( "gfx2", 0, char_layout, 0, 64 ) GFXDECODE_ENTRY( "gfx1", 0, sprite_layout, 0, 64 ) GFXDECODE_END static const ay8910_interface ay8910_config = { AY8910_LEGACY_OUTPUT, AY8910_DEFAULT_LOADS, DEVCB_NULL, DEVCB_NULL, DEVCB_DEVICE_HANDLER("aysnd", sound_control_2_w), DEVCB_HANDLER(sound_control_3_w) }; static const msm5232_interface msm5232_config = { { 1.0e-6, 1.0e-6, 1.0e-6, 1.0e-6, 1.0e-6, 1.0e-6, 1.0e-6, 1.0e-6 } /* 1.0 uF capacitors (verified on real PCB) */ }; /*******************************************************************************/ static MACHINE_START( 40love ) { fortyl_state *state = machine.driver_data<fortyl_state>(); state->m_audiocpu = machine.device("audiocpu"); /* video */ state->save_item(NAME(state->m_pix1)); state->save_item(NAME(state->m_pix2)); /* sound */ state->save_item(NAME(state->m_sound_nmi_enable)); state->save_item(NAME(state->m_pending_nmi)); state->save_item(NAME(state->m_snd_data)); state->save_item(NAME(state->m_snd_flag)); state->save_item(NAME(state->m_vol_ctrl)); state->save_item(NAME(state->m_snd_ctrl0)); state->save_item(NAME(state->m_snd_ctrl1)); state->save_item(NAME(state->m_snd_ctrl2)); state->save_item(NAME(state->m_snd_ctrl3)); } static MACHINE_START( undoukai ) { fortyl_state *state = machine.driver_data<fortyl_state>(); MACHINE_START_CALL(40love); /* fake mcu */ state->save_item(NAME(state->m_from_mcu)); state->save_item(NAME(state->m_mcu_cmd)); state->save_item(NAME(state->m_mcu_in[0])); state->save_item(NAME(state->m_mcu_in[1])); state->save_item(NAME(state->m_mcu_out[0])); state->save_item(NAME(state->m_mcu_out[1])); } static MACHINE_RESET( common ) { fortyl_state *state = machine.driver_data<fortyl_state>(); MACHINE_RESET_CALL(ta7630); /* video */ state->m_pix1 = 0; state->m_pix2[0] = 0; state->m_pix2[1] = 0; /* sound */ state->m_sound_nmi_enable = 0; state->m_pending_nmi = 0; state->m_snd_data = 0; state->m_snd_flag = 0; state->m_snd_ctrl0 = 0; state->m_snd_ctrl1 = 0; state->m_snd_ctrl2 = 0; state->m_snd_ctrl3 = 0; } static MACHINE_RESET( 40love ) { cputag_set_input_line(machine, "mcu", 0, CLEAR_LINE); MACHINE_RESET_CALL(common); } static MACHINE_RESET( undoukai ) { fortyl_state *state = machine.driver_data<fortyl_state>(); int i; MACHINE_RESET_CALL(common); /* fake mcu */ state->m_from_mcu = 0xff; state->m_mcu_cmd = -1; for (i = 0; i < 16; i++) { state->m_mcu_in[0][i] = 0; state->m_mcu_in[1][i] = 0; state->m_mcu_out[0][i] = 0; state->m_mcu_out[1][i] = 0; } } static MACHINE_CONFIG_START( 40love, fortyl_state ) /* basic machine hardware */ MCFG_CPU_ADD("maincpu",Z80,8000000/2) /* OK */ MCFG_CPU_PROGRAM_MAP(40love_map) MCFG_CPU_VBLANK_INT("screen", irq0_line_hold) MCFG_CPU_ADD("audiocpu",Z80,8000000/2) /* OK */ MCFG_CPU_PROGRAM_MAP(sound_map) MCFG_CPU_PERIODIC_INT(irq0_line_hold,2*60) /* source/number of IRQs is unknown */ MCFG_CPU_ADD("mcu",M68705,18432000/6) /* OK */ MCFG_CPU_PROGRAM_MAP(buggychl_mcu_map) MCFG_DEVICE_ADD("bmcu", BUGGYCHL_MCU, 0) MCFG_QUANTUM_TIME(attotime::from_hz(6000)) /* high interleave to ensure proper synchronization of CPUs */ MCFG_MACHINE_START(40love) MCFG_MACHINE_RESET(40love) /* video hardware */ MCFG_SCREEN_ADD("screen", RASTER) MCFG_SCREEN_REFRESH_RATE(60) MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(2500) /* not accurate */) MCFG_SCREEN_SIZE(64*8, 32*8) MCFG_SCREEN_VISIBLE_AREA(128,128+255, 2*8, 30*8-1) MCFG_SCREEN_UPDATE_STATIC(fortyl) MCFG_GFXDECODE(40love) MCFG_PALETTE_LENGTH(1024) MCFG_PALETTE_INIT(fortyl) MCFG_VIDEO_START(fortyl) /* sound hardware */ MCFG_SPEAKER_STANDARD_MONO("mono") MCFG_SOUND_ADD("aysnd", AY8910, 2000000) MCFG_SOUND_CONFIG(ay8910_config) MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.10) MCFG_SOUND_ADD("msm", MSM5232, 8000000/4) MCFG_SOUND_CONFIG(msm5232_config) MCFG_SOUND_ROUTE(0, "mono", 1.0) // pin 28 2'-1 MCFG_SOUND_ROUTE(1, "mono", 1.0) // pin 29 4'-1 MCFG_SOUND_ROUTE(2, "mono", 1.0) // pin 30 8'-1 MCFG_SOUND_ROUTE(3, "mono", 1.0) // pin 31 16'-1 MCFG_SOUND_ROUTE(4, "mono", 1.0) // pin 36 2'-2 MCFG_SOUND_ROUTE(5, "mono", 1.0) // pin 35 4'-2 MCFG_SOUND_ROUTE(6, "mono", 1.0) // pin 34 8'-2 MCFG_SOUND_ROUTE(7, "mono", 1.0) // pin 33 16'-2 // pin 1 SOLO 8' not mapped // pin 2 SOLO 16' not mapped // pin 22 Noise Output not mapped MCFG_SOUND_ADD("dac", DAC, 0) MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.20) MACHINE_CONFIG_END static MACHINE_CONFIG_START( undoukai, fortyl_state ) /* basic machine hardware */ MCFG_CPU_ADD("maincpu",Z80,8000000/2) MCFG_CPU_PROGRAM_MAP(undoukai_map) MCFG_CPU_VBLANK_INT("screen", irq0_line_hold) MCFG_CPU_ADD("audiocpu",Z80,8000000/2) MCFG_CPU_PROGRAM_MAP(sound_map) MCFG_CPU_PERIODIC_INT(irq0_line_hold,2*60) /* source/number of IRQs is unknown */ // MCFG_CPU_ADD("mcu",M68705,18432000/6) // MCFG_CPU_PROGRAM_MAP(buggychl_mcu_map) // MCFG_DEVICE_ADD("bmcu", BUGGYCHL_MCU, 0) MCFG_MACHINE_START(undoukai) MCFG_MACHINE_RESET(undoukai) /* init machine */ /* video hardware */ MCFG_SCREEN_ADD("screen", RASTER) MCFG_SCREEN_REFRESH_RATE(60) MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(2500) /* not accurate */) MCFG_SCREEN_SIZE(64*8, 32*8) MCFG_SCREEN_VISIBLE_AREA(128,128+255, 2*8, 30*8-1) MCFG_SCREEN_UPDATE_STATIC(fortyl) MCFG_GFXDECODE(40love) MCFG_PALETTE_LENGTH(1024) MCFG_PALETTE_INIT(fortyl) MCFG_VIDEO_START(fortyl) /* sound hardware */ MCFG_SPEAKER_STANDARD_MONO("mono") MCFG_SOUND_ADD("aysnd", AY8910, 2000000) MCFG_SOUND_CONFIG(ay8910_config) MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.10) MCFG_SOUND_ADD("msm", MSM5232, 8000000/4) MCFG_SOUND_CONFIG(msm5232_config) MCFG_SOUND_ROUTE(0, "mono", 1.0) // pin 28 2'-1 MCFG_SOUND_ROUTE(1, "mono", 1.0) // pin 29 4'-1 MCFG_SOUND_ROUTE(2, "mono", 1.0) // pin 30 8'-1 MCFG_SOUND_ROUTE(3, "mono", 1.0) // pin 31 16'-1 MCFG_SOUND_ROUTE(4, "mono", 1.0) // pin 36 2'-2 MCFG_SOUND_ROUTE(5, "mono", 1.0) // pin 35 4'-2 MCFG_SOUND_ROUTE(6, "mono", 1.0) // pin 34 8'-2 MCFG_SOUND_ROUTE(7, "mono", 1.0) // pin 33 16'-2 // pin 1 SOLO 8' not mapped // pin 2 SOLO 16' not mapped // pin 22 Noise Output not mapped MCFG_SOUND_ADD("dac", DAC, 0) MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.20) MACHINE_CONFIG_END /*******************************************************************************/ ROM_START( 40love ) ROM_REGION( 0x14000, "maincpu", 0 ) /* Z80 main CPU */ ROM_LOAD( "a30-19.ic1", 0x00000, 0x2000, CRC(7baca598) SHA1(b1767f5af9b3f484afb4423afe1f9c15db92c2ac) ) ROM_LOAD( "a30-20.ic2", 0x02000, 0x2000, CRC(a7b4f2cc) SHA1(67f570874fa0feb21f2a9a0712fadf78ebaad91c) ) ROM_LOAD( "a30-21.ic3", 0x04000, 0x2000, CRC(49a372e8) SHA1(7c15fac65369d2e90b432c0f5c8e1d7295c379d1) ) ROM_LOAD( "a30-22.ic4", 0x06000, 0x2000, CRC(0c06d2b3) SHA1(e5b0c8e57b0a6d131496e168023e12bacc17e93e) ) ROM_LOAD( "a30-23.ic5", 0x10000, 0x2000, CRC(6dcd186e) SHA1(c8d88a2f35ba77ea822bdd8133033c8eb0bb5f72) ) /* banked at 0xa000 */ ROM_LOAD( "a30-24.ic6", 0x12000, 0x2000, CRC(590c20c8) SHA1(93689d6a299dfbe33ffec42d13378091d8589b34) ) /* banked at 0xa000 */ ROM_REGION( 0x10000, "audiocpu", 0 ) /* Z80 sound CPU */ ROM_LOAD( "a30-08.u08", 0x0000, 0x2000, CRC(2fc42ee1) SHA1(b56e5f9acbcdc476252e188f41ad7249dba6f8e1) ) ROM_LOAD( "a30-09.u09", 0x2000, 0x2000, CRC(3a75abce) SHA1(ad2df26789d38196c0677c22ab8f176e99604b18) ) ROM_LOAD( "a30-10.u10", 0x4000, 0x2000, CRC(393c4b5b) SHA1(a8e1dd5c33e929bc832cccc13b85ecd13fff1eb2) ) ROM_LOAD( "a30-11.u37", 0x6000, 0x2000, CRC(11b2c6d2) SHA1(d55690512a37c4df2386a845e0cfb14f8052295b) ) ROM_LOAD( "a30-12.u38", 0x8000, 0x2000, CRC(f7afd475) SHA1(dd09d5ca7fec5e0454f9efb8ebc722561010f124) ) ROM_LOAD( "a30-13.u39", 0xa000, 0x2000, CRC(e806630f) SHA1(09022aae88ea0171a0aacf3260fa3a95e8faeb21) ) ROM_REGION( 0x0800, "mcu", 0 ) /* 2k for the microcontroller */ ROM_LOAD( "a30-14" , 0x0000, 0x0800, CRC(c4690279) SHA1(60bc77e03b9be434bb97a374a2fedeb8d049a660) ) ROM_REGION( 0x8000, "gfx1", 0 ) ROM_LOAD( "a30-25.u22", 0x0000, 0x2000, CRC(15e594cf) SHA1(d2d506a55f6ac2c191e5d5b3127021cde366c71c) ) ROM_LOAD( "415f.26", 0x2000, 0x2000, BAD_DUMP CRC(3a45a205) SHA1(0939ecaabbb9be2a0719ef252e3f244299734ba6) ) /* this actually seems good, but we need to find another one to verify */ ROM_LOAD( "a30-27.u24", 0x4000, 0x2000, CRC(57c67f6f) SHA1(293e5bfa7c859886abd70f78fe2e4b13a3fce3f5) ) ROM_LOAD( "a30-28.u25", 0x6000, 0x2000, CRC(d581d067) SHA1(ce132cf2503917f0846b838c6ce4ad4183181bf9) ) ROM_REGION( 0x8000, "gfx2", 0 ) ROM_LOAD( "a30-29.u62", 0x0000, 0x2000, CRC(02deaf40) SHA1(fb424a40bd9d959664a6d1ddf477fc16e694b9fa) ) ROM_LOAD( "a30-30.u63", 0x2000, 0x2000, CRC(439f3731) SHA1(4661149baa8472989cc8ac85c51e55df69957d99) ) ROM_LOAD( "a30-31.u64", 0x4000, 0x2000, CRC(7ed70e81) SHA1(f90a3ce701ebe746803cf01ea1f6725c552007de) ) ROM_LOAD( "a30-32.u65", 0x6000, 0x2000, CRC(0434655b) SHA1(261c5e60e830967564c053dc1d40fbf1e7194fc8) ) ROM_REGION( 0x1000, "proms", 0 ) ROM_LOAD( "a30-15.u03", 0x0000, 0x0400, CRC(55e38cc7) SHA1(823a6d7f29eadf5d12702d782d4297b0d4c65a0e) ) /* red */ ROM_LOAD( "a30-16.u01", 0x0400, 0x0400, CRC(13997e20) SHA1(9fae1cf633409a88263dc66a17b1c2eeccd05f4f) ) /* green */ ROM_LOAD( "a30-17.u02", 0x0800, 0x0400, CRC(5031f2f3) SHA1(1836d82fdc9f39cb318a791af2a935c27baabfd7) ) /* blue */ ROM_LOAD( "a30-18.u13", 0x0c00, 0x0400, CRC(78697c0f) SHA1(31382ed4c0d44024f7f57a9de6407527f4d5b0d1) ) /* ??? */ ROM_END ROM_START( fieldday ) ROM_REGION( 0x14000, "maincpu", 0 ) /* Z80 main CPU */ ROM_LOAD( "a17_44.bin", 0x00000, 0x2000, CRC(d59812e1) SHA1(f3e7e2f09fba5964c92813cd652aa093fe3e4415) ) ROM_LOAD( "a17_45.bin", 0x02000, 0x2000, CRC(828bfb9a) SHA1(0be24ec076b715d65e9c8e01e3be76628e4f60ed) ) ROM_LOAD( "a23_05.bin", 0x04000, 0x2000, CRC(2670cad3) SHA1(8ba3a6b788fa4e997f9153226f6f13b32fc33124) ) ROM_LOAD( "a23_06.bin", 0x06000, 0x2000, CRC(737ce7de) SHA1(52a46fe14978e217de81dcd529d16d62fb5a4e46) ) ROM_LOAD( "a23_07.bin", 0x10000, 0x2000, CRC(ee2fb306) SHA1(f2b0a6af279b459fe61d56ba4d36d519318376fb) ) ROM_LOAD( "a23_08.bin", 0x12000, 0x2000, CRC(1ed2f1ad) SHA1(e3cf954dd2c34759147d0c85da7a716a8eb0e820) ) ROM_COPY( "maincpu" , 0x10000, 0x8000, 0x2000 ) /* to avoid 'bank bug' */ ROM_REGION( 0x10000, "audiocpu", 0 ) /* Z80 sound CPU */ ROM_LOAD( "a17_24.bin", 0x0000, 0x2000, CRC(6bac6b7f) SHA1(eb95192204a868737d609b789312ac37c31d3071) ) ROM_LOAD( "a17_25.bin", 0x2000, 0x2000, CRC(570b90b1) SHA1(2a8c3bebd15655ffbfeaf40c2db90292afbb11ef) ) ROM_LOAD( "a17_26.bin", 0x4000, 0x2000, CRC(7a8ea7f4) SHA1(1d9d2b54645266f95aa89cdbec6f82d4ac20d6e4) ) ROM_LOAD( "a17_27.bin", 0x6000, 0x2000, CRC(e10594d9) SHA1(3df15b8b0c7af9fed93eca27237e15e6a7a8f835) ) ROM_LOAD( "a17_28.bin", 0x8000, 0x2000, CRC(1a4d1dae) SHA1(fbc3c55ad9f15ead432c136eec648fe22e523ea7) ) ROM_LOAD( "a17_29.bin", 0xa000, 0x2000, CRC(3c540007) SHA1(549e7ff260214c538913ff548dcb088987845911) ) ROM_REGION( 0x0800, "cpu2", 0 ) /* 2k for the microcontroller */ ROM_LOAD( "a17_14.bin", 0x0000, 0x0800, NO_DUMP ) ROM_REGION( 0x8000, "gfx1", 0 ) ROM_LOAD( "a17_36.bin", 0x0000, 0x2000, CRC(e3dd51f7) SHA1(95a97ea925c5bc7bdc00887e6d17d817b36befc4) ) ROM_LOAD( "a17_37.bin", 0x2000, 0x2000, CRC(1623f71f) SHA1(f5df7498b9a08e82ea11cb1b1fcdabca48cbf33a) ) ROM_LOAD( "a17_38.bin", 0x4000, 0x2000, CRC(ca9f74db) SHA1(a002f1dfa9497793bfb18292e7a71ae12d70fb88) ) ROM_LOAD( "a17_39.bin", 0x6000, 0x2000, CRC(fb6c667c) SHA1(da56be8d997db199588ee22fae30cc6d87e80704) ) ROM_REGION( 0x8000, "gfx2", 0 ) ROM_LOAD( "a23_09.bin", 0x0000, 0x2000, CRC(1e430be5) SHA1(9296e1a0d820bb218578d55b739b4fc5fdafb125) ) ROM_LOAD( "a23_10.bin", 0x2000, 0x2000, CRC(ee2e54f0) SHA1(0a92fa39696a8005f9441131b6d98205b7c26e7b) ) ROM_LOAD( "a23_11.bin", 0x4000, 0x2000, CRC(6d37f15c) SHA1(3eb9a2e230d88f2871e6972a01d8e7cc7db1b123) ) ROM_LOAD( "a23_12.bin", 0x6000, 0x2000, CRC(86da42d2) SHA1(aa79cd954c96217ca2daf37addac168f8cca24f9) ) ROM_REGION( 0x1000, "proms", 0 ) ROM_LOAD( "a17-15.10v", 0x0000, 0x0400, CRC(9df472b7) SHA1(0cd9dd735238daf8e8228ba9481df57fb8925328) ) /* red */ ROM_LOAD( "a17-16.8v", 0x0400, 0x0400, CRC(3bf1ff5f) SHA1(a0453851aefa9acdba4a86aaca8c442cb8550987) ) /* green */ ROM_LOAD( "a17-17.9v", 0x0800, 0x0400, CRC(c42ae956) SHA1(057ce3783305c98622f7dfc0ee7d4882137a2ef8) ) /* blue */ ROM_LOAD( "a17-18.23v", 0x0c00, 0x0400, CRC(3023a1da) SHA1(08ce4c6e99d04b358d66f0588852311d07183619) ) /* ??? */ ROM_END ROM_START( undoukai ) ROM_REGION( 0x14000, "maincpu", 0 ) /* Z80 main CPU */ ROM_LOAD( "a17-01.70c", 0x00000, 0x4000, CRC(6ce324d9) SHA1(9c5207ac897eaae5a6aa1a05a918c9cb58544664) ) ROM_LOAD( "a17-02.71c", 0x04000, 0x4000, CRC(055c7ef1) SHA1(f974bd441b8e3621ac5f8d36104791c97051a97a) ) ROM_LOAD( "a17-03.72c", 0x10000, 0x4000, CRC(9034a5c5) SHA1(bc3dae0dee08b6989275ac220fc76bfe61367154) ) /* banked at 0x8000 */ ROM_COPY( "maincpu" , 0x10000, 0x8000, 0x2000 ) /* to avoid 'bank bug' */ ROM_REGION( 0x10000, "audiocpu", 0 ) /* Z80 sound CPU */ ROM_LOAD( "a17-08.8s", 0x0000, 0x2000, CRC(2545aa0e) SHA1(190ef99890251e1e49b14ffd28f2badb4d0d8fbe) ) ROM_LOAD( "a17-09.9s", 0x2000, 0x2000, CRC(57e2cdbb) SHA1(ae6187d62fb36a37be06040e0fd85e0252cdf750) ) ROM_LOAD( "a17-10.10s", 0x4000, 0x2000, CRC(38a288fe) SHA1(af4979cae59ca2569a3663132451b9b554552a79) ) ROM_LOAD( "a17-11.37s", 0x6000, 0x2000, CRC(036d6969) SHA1(20e03dab14d44bf3c7c6aace3b28b2826581d1c7) ) ROM_LOAD( "a17-12.38s", 0x8000, 0x2000, CRC(cb7e6dcd) SHA1(5286c6d340c1d465caebae5dd7e3d4ff8b7f8f5e) ) ROM_LOAD( "a17-13.39s", 0xa000, 0x2000, CRC(0a40930e) SHA1(8c4b9fa0aed67a3e269c2136ef81791fc8acd1da) ) ROM_REGION( 0x0800, "cpu2", 0 ) /* 2k for the microcontroller */ ROM_LOAD( "a17-14.41c", 0x0000, 0x0800, NO_DUMP ) ROM_REGION( 0x8000, "gfx1", 0 ) ROM_LOAD( "a17-04.18v", 0x0000, 0x4000, CRC(84dabee2) SHA1(698f12ee4201665988248853dafbf4b16dfc6517) ) ROM_LOAD( "a17-05.19v", 0x4000, 0x4000, CRC(10bf3451) SHA1(23ebb1409c90d225ff5a13ad23d4dff1acaf904a) ) ROM_REGION( 0x8000, "gfx2", 0 ) ROM_LOAD( "a17-06.59v", 0x0000, 0x4000, CRC(50f28ad9) SHA1(001555ad123ac85000999b1aa39c1b2568e26f46) ) ROM_LOAD( "a17-07.60v", 0x4000, 0x4000, CRC(7a4b4238) SHA1(8e58803645e61a7144a659d403f318a8899d36e2) ) ROM_REGION( 0x1000, "proms", 0 ) ROM_LOAD( "a17-15.10v", 0x0000, 0x0400, CRC(9df472b7) SHA1(0cd9dd735238daf8e8228ba9481df57fb8925328) ) /* red */ ROM_LOAD( "a17-16.8v", 0x0400, 0x0400, CRC(3bf1ff5f) SHA1(a0453851aefa9acdba4a86aaca8c442cb8550987) ) /* green */ ROM_LOAD( "a17-17.9v", 0x0800, 0x0400, CRC(c42ae956) SHA1(057ce3783305c98622f7dfc0ee7d4882137a2ef8) ) /* blue */ ROM_LOAD( "a17-18.23v", 0x0c00, 0x0400, CRC(3023a1da) SHA1(08ce4c6e99d04b358d66f0588852311d07183619) ) /* ??? */ ROM_END GAME( 1984, 40love, 0, 40love, 40love, 40love, ROT0, "Taito Corporation", "Forty-Love", GAME_SUPPORTS_SAVE | GAME_IMPERFECT_GRAPHICS ) GAME( 1984, fieldday, 0, undoukai, undoukai, undoukai, ROT0, "Taito Corporation", "Field Day", GAME_SUPPORTS_SAVE ) GAME( 1984, undoukai, fieldday, undoukai, undoukai, undoukai, ROT0, "Taito Corporation", "The Undoukai (Japan)", GAME_SUPPORTS_SAVE )