summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu/info.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/emu/info.cpp')
-rw-r--r--src/emu/info.cpp831
1 files changed, 519 insertions, 312 deletions
diff --git a/src/emu/info.cpp b/src/emu/info.cpp
index d9e76cd72d9..f427d017795 100644
--- a/src/emu/info.cpp
+++ b/src/emu/info.cpp
@@ -100,10 +100,11 @@ const char info_xml_creator::s_dtd_string[] =
"\t\t\t<!ATTLIST input service (yes|no) \"no\">\n"
"\t\t\t<!ATTLIST input tilt (yes|no) \"no\">\n"
"\t\t\t<!ATTLIST input players CDATA #REQUIRED>\n"
-"\t\t\t<!ATTLIST input buttons CDATA #IMPLIED>\n"
"\t\t\t<!ATTLIST input coins CDATA #IMPLIED>\n"
"\t\t\t<!ELEMENT control EMPTY>\n"
"\t\t\t\t<!ATTLIST control type CDATA #REQUIRED>\n"
+"\t\t\t\t<!ATTLIST control player CDATA #IMPLIED>\n"
+"\t\t\t\t<!ATTLIST control buttons CDATA #IMPLIED>\n"
"\t\t\t\t<!ATTLIST control minimum CDATA #IMPLIED>\n"
"\t\t\t\t<!ATTLIST control maximum CDATA #IMPLIED>\n"
"\t\t\t\t<!ATTLIST control sensitivity CDATA #IMPLIED>\n"
@@ -147,6 +148,7 @@ const char info_xml_creator::s_dtd_string[] =
"\t\t<!ELEMENT device (instance*, extension*)>\n"
"\t\t\t<!ATTLIST device type CDATA #REQUIRED>\n"
"\t\t\t<!ATTLIST device tag CDATA #IMPLIED>\n"
+"\t\t\t<!ATTLIST device fixed_image CDATA #IMPLIED>\n"
"\t\t\t<!ATTLIST device mandatory CDATA #IMPLIED>\n"
"\t\t\t<!ATTLIST device interface CDATA #IMPLIED>\n"
"\t\t\t<!ELEMENT instance EMPTY>\n"
@@ -248,6 +250,33 @@ void info_xml_creator::output_one()
device_iterator iter(config.root_device());
for (device_t *device = iter.first(); device != nullptr; device = iter.next())
portlist.append(*device, errors);
+ // renumber player numbers for controller ports
+ int player_offset = 0;
+ // but treat keyboard count separately from players' number
+ int kbd_offset = 0;
+ for (device_t *device = iter.first(); device != nullptr; device = iter.next())
+ {
+ int nplayers = 0;
+ bool new_kbd = FALSE;
+ for (ioport_port &port : portlist)
+ if (&port.device() == device)
+ for (ioport_field &field : port.fields())
+ if (field.type() >= IPT_START && field.type() < IPT_ANALOG_LAST)
+ {
+ if (field.type() == IPT_KEYBOARD)
+ {
+ if (!new_kbd) new_kbd = TRUE;
+ field.set_player(field.player() + kbd_offset);
+ }
+ else
+ {
+ nplayers = MAX(nplayers, field.player() + 1);
+ field.set_player(field.player() + player_offset);
+ }
+ }
+ player_offset += nplayers;
+ if (new_kbd) kbd_offset++;
+ }
// print the header and the game name
fprintf(m_output, "\t<%s",XML_TOP);
@@ -792,295 +821,466 @@ void info_xml_creator::output_sound(device_t &device)
void info_xml_creator::output_input(const ioport_list &portlist)
{
- // enumerated list of control types
- enum
- {
- ANALOG_TYPE_PADDLE,
- ANALOG_TYPE_PEDAL,
- ANALOG_TYPE_JOYSTICK,
- ANALOG_TYPE_POSITIONAL,
- ANALOG_TYPE_LIGHTGUN,
- ANALOG_TYPE_DIAL,
- ANALOG_TYPE_TRACKBALL,
- ANALOG_TYPE_MOUSE,
- ANALOG_TYPE_COUNT
- };
-
- // directions
- const UINT8 DIR_UP = 0x01;
- const UINT8 DIR_DOWN = 0x02;
- const UINT8 DIR_LEFT = 0x04;
- const UINT8 DIR_RIGHT = 0x08;
- const UINT8 DIR_4WAY = 0x10;
-
- // initialize the list of control types
- struct
- {
- const char * type; /* general type of input */
- bool analog;
- bool keyb;
- INT32 min; /* analog minimum value */
- INT32 max; /* analog maximum value */
- INT32 sensitivity; /* default analog sensitivity */
- INT32 keydelta; /* default analog keydelta */
- bool reverse; /* default analog reverse setting */
- } control_info[ANALOG_TYPE_COUNT];
-
- memset(&control_info, 0, sizeof(control_info));
-
- // tracking info as we iterate
- int nplayer = 0;
- int nbutton = 0;
- int ncoin = 0;
- UINT8 joytype[3] = { 0,0,0 };
- bool service = false;
- bool tilt = false;
- bool keypad = false;
- bool keyboard = false;
- bool mahjong = false;
- bool hanafuda = false;
- bool gambling = false;
-
- // iterate over the ports
- for (ioport_port &port : portlist)
- for (ioport_field &field : port.fields())
- {
- int analogtype = -1;
-
- // track the highest player number
- if (nplayer < field.player() + 1)
- nplayer = field.player() + 1;
-
- // switch off of the type
- switch (field.type())
- {
- // map which joystick directions are present
- case IPT_JOYSTICK_UP: joytype[0] |= DIR_UP | ((field.way() == 4) ? DIR_4WAY : 0); break;
- case IPT_JOYSTICK_DOWN: joytype[0] |= DIR_DOWN | ((field.way() == 4) ? DIR_4WAY : 0); break;
- case IPT_JOYSTICK_LEFT: joytype[0] |= DIR_LEFT | ((field.way() == 4) ? DIR_4WAY : 0); break;
- case IPT_JOYSTICK_RIGHT: joytype[0] |= DIR_RIGHT | ((field.way() == 4) ? DIR_4WAY : 0); break;
-
- case IPT_JOYSTICKLEFT_UP: joytype[1] |= DIR_UP | ((field.way() == 4) ? DIR_4WAY : 0); break;
- case IPT_JOYSTICKLEFT_DOWN: joytype[1] |= DIR_DOWN | ((field.way() == 4) ? DIR_4WAY : 0); break;
- case IPT_JOYSTICKLEFT_LEFT: joytype[1] |= DIR_LEFT | ((field.way() == 4) ? DIR_4WAY : 0); break;
- case IPT_JOYSTICKLEFT_RIGHT: joytype[1] |= DIR_RIGHT | ((field.way() == 4) ? DIR_4WAY : 0); break;
-
- case IPT_JOYSTICKRIGHT_UP: joytype[2] |= DIR_UP | ((field.way() == 4) ? DIR_4WAY : 0); break;
- case IPT_JOYSTICKRIGHT_DOWN: joytype[2] |= DIR_DOWN | ((field.way() == 4) ? DIR_4WAY : 0); break;
- case IPT_JOYSTICKRIGHT_LEFT: joytype[2] |= DIR_LEFT | ((field.way() == 4) ? DIR_4WAY : 0); break;
- case IPT_JOYSTICKRIGHT_RIGHT: joytype[2] |= DIR_RIGHT | ((field.way() == 4) ? DIR_4WAY : 0); break;
-
- // mark as an analog input, and get analog stats after switch
- case IPT_AD_STICK_X:
- case IPT_AD_STICK_Y:
- case IPT_AD_STICK_Z:
- control_info[analogtype = ANALOG_TYPE_JOYSTICK].type = "stick";
- break;
-
- case IPT_PADDLE:
- case IPT_PADDLE_V:
- control_info[analogtype = ANALOG_TYPE_PADDLE].type = "paddle";
- break;
-
- case IPT_PEDAL:
- case IPT_PEDAL2:
- case IPT_PEDAL3:
- control_info[analogtype = ANALOG_TYPE_PEDAL].type = "pedal";
- break;
-
- case IPT_LIGHTGUN_X:
- case IPT_LIGHTGUN_Y:
- control_info[analogtype = ANALOG_TYPE_LIGHTGUN].type = "lightgun";
- break;
-
- case IPT_POSITIONAL:
- case IPT_POSITIONAL_V:
- control_info[analogtype = ANALOG_TYPE_POSITIONAL].type = "positional";
- break;
-
- case IPT_DIAL:
- case IPT_DIAL_V:
- control_info[analogtype = ANALOG_TYPE_DIAL].type = "dial";
- break;
-
- case IPT_TRACKBALL_X:
- case IPT_TRACKBALL_Y:
- control_info[analogtype = ANALOG_TYPE_TRACKBALL].type = "trackball";
- break;
-
- case IPT_MOUSE_X:
- case IPT_MOUSE_Y:
- control_info[analogtype = ANALOG_TYPE_MOUSE].type = "mouse";
- break;
-
- // track maximum button index
- case IPT_BUTTON1:
- case IPT_BUTTON2:
- case IPT_BUTTON3:
- case IPT_BUTTON4:
- case IPT_BUTTON5:
- case IPT_BUTTON6:
- case IPT_BUTTON7:
- case IPT_BUTTON8:
- case IPT_BUTTON9:
- case IPT_BUTTON10:
- case IPT_BUTTON11:
- case IPT_BUTTON12:
- case IPT_BUTTON13:
- case IPT_BUTTON14:
- case IPT_BUTTON15:
- case IPT_BUTTON16:
- nbutton = MAX(nbutton, field.type() - IPT_BUTTON1 + 1);
- break;
-
- // track maximum coin index
- case IPT_COIN1:
- case IPT_COIN2:
- case IPT_COIN3:
- case IPT_COIN4:
- case IPT_COIN5:
- case IPT_COIN6:
- case IPT_COIN7:
- case IPT_COIN8:
- ncoin = MAX(ncoin, field.type() - IPT_COIN1 + 1);
- break;
-
- // track presence of these guys
- case IPT_KEYPAD:
- keypad = true;
- break;
-
- case IPT_KEYBOARD:
- keyboard = true;
- break;
-
- // additional types
- case IPT_SERVICE:
- service = true;
- break;
-
- case IPT_TILT:
- tilt = true;
- break;
-
- default:
- if (field.type() > IPT_MAHJONG_FIRST && field.type() < IPT_MAHJONG_LAST)
- mahjong = true;
- else if (field.type() > IPT_HANAFUDA_FIRST && field.type() < IPT_HANAFUDA_LAST)
- hanafuda = true;
- else if (field.type() > IPT_GAMBLING_FIRST && field.type() < IPT_GAMBLING_LAST)
- gambling = true;
- break;
- }
-
- // get the analog stats
- if (analogtype != -1)
- {
- if (field.minval() != 0)
- control_info[analogtype].min = field.minval();
- if (field.maxval() != 0)
- control_info[analogtype].max = field.maxval();
- if (field.sensitivity() != 0)
- control_info[analogtype].sensitivity = field.sensitivity();
- if (field.delta() != 0)
- control_info[analogtype].keydelta = field.delta();
- if (field.analog_reverse() != 0)
- control_info[analogtype].reverse = true;
- }
- }
-
- // output the basic info
- fprintf(m_output, "\t\t<input");
- fprintf(m_output, " players=\"%d\"", nplayer);
- if (nbutton != 0)
- fprintf(m_output, " buttons=\"%d\"", nbutton);
- if (ncoin != 0)
- fprintf(m_output, " coins=\"%d\"", ncoin);
- if (service)
- fprintf(m_output, " service=\"yes\"");
- if (tilt)
- fprintf(m_output, " tilt=\"yes\"");
- fprintf(m_output, ">\n");
-
- // output the joystick types
- if (joytype[1]==0 && joytype[2]!=0) { joytype[1] = joytype[2]; joytype[2] = 0; }
- if (joytype[0]==0 && joytype[1]!=0) { joytype[0] = joytype[1]; joytype[1] = 0; }
- if (joytype[1]==0 && joytype[2]!=0) { joytype[1] = joytype[2]; joytype[2] = 0; }
- if (joytype[0] != 0)
- {
- const char *joys = (joytype[2]!=0) ? "triple" : (joytype[1]!=0) ? "double" : "";
- fprintf(m_output, "\t\t\t<control type=\"%sjoy\"", joys);
- for (int lp=0; lp<3 && joytype[lp]!=0; lp++)
- {
- const char *plural = (lp==2) ? "3" : (lp==1) ? "2" : "";
- const char *ways;
- switch (joytype[lp] & (DIR_UP | DIR_DOWN | DIR_LEFT | DIR_RIGHT))
- {
- case DIR_UP | DIR_DOWN | DIR_LEFT | DIR_RIGHT:
- ways = ((joytype[lp] & DIR_4WAY) != 0) ? "4" : "8";
- break;
- case DIR_LEFT | DIR_RIGHT:
- ways = "2";
- break;
- case DIR_UP | DIR_DOWN:
- ways = "vertical2";
- break;
- case DIR_UP:
- case DIR_DOWN:
- case DIR_LEFT:
- case DIR_RIGHT:
- ways = "1";
- break;
- case DIR_UP | DIR_DOWN | DIR_LEFT:
- case DIR_UP | DIR_DOWN | DIR_RIGHT:
- case DIR_UP | DIR_LEFT | DIR_RIGHT:
- case DIR_DOWN | DIR_LEFT | DIR_RIGHT:
- ways = ((joytype[lp] & DIR_4WAY) != 0) ? "3 (half4)" : "5 (half8)";
- break;
- default:
- ways = "strange2";
- break;
- }
- fprintf(m_output, " ways%s=\"%s\"", plural,ways);
- }
- fprintf(m_output, "/>\n");
- }
-
- // output analog types
- for (auto & elem : control_info)
- if (elem.type != nullptr)
- {
- fprintf(m_output, "\t\t\t<control type=\"%s\"", xml_normalize_string(elem.type));
- if (elem.min != 0 || elem.max != 0)
- {
- fprintf(m_output, " minimum=\"%d\"", elem.min);
- fprintf(m_output, " maximum=\"%d\"", elem.max);
- }
- if (elem.sensitivity != 0)
- fprintf(m_output, " sensitivity=\"%d\"", elem.sensitivity);
- if (elem.keydelta != 0)
- fprintf(m_output, " keydelta=\"%d\"", elem.keydelta);
- if (elem.reverse)
- fprintf(m_output, " reverse=\"yes\"");
-
- fprintf(m_output, "/>\n");
- }
-
- // output keypad and keyboard
- if (keypad)
- fprintf(m_output, "\t\t\t<control type=\"keypad\"/>\n");
- if (keyboard)
- fprintf(m_output, "\t\t\t<control type=\"keyboard\"/>\n");
-
- // misc
- if (mahjong)
- fprintf(m_output, "\t\t\t<control type=\"mahjong\"/>\n");
- if (hanafuda)
- fprintf(m_output, "\t\t\t<control type=\"hanafuda\"/>\n");
- if (gambling)
- fprintf(m_output, "\t\t\t<control type=\"gambling\"/>\n");
-
- fprintf(m_output, "\t\t</input>\n");
+ // enumerated list of control types
+ // NOTE: the order is chosen so that 'spare' button inputs are assigned to the
+ // most-likely-correct input device when info is output (you can think of it as
+ // a sort of likelihood order of having buttons)
+ enum
+ {
+ CTRL_DIGITAL_BUTTONS,
+ CTRL_DIGITAL_JOYSTICK,
+ CTRL_ANALOG_JOYSTICK,
+ CTRL_ANALOG_LIGHTGUN,
+ CTRL_ANALOG_DIAL,
+ CTRL_ANALOG_POSITIONAL,
+ CTRL_ANALOG_TRACKBALL,
+ CTRL_ANALOG_MOUSE,
+ CTRL_ANALOG_PADDLE,
+ CTRL_ANALOG_PEDAL,
+ CTRL_DIGITAL_KEYPAD,
+ CTRL_DIGITAL_KEYBOARD,
+ CTRL_DIGITAL_MAHJONG,
+ CTRL_DIGITAL_HANAFUDA,
+ CTRL_DIGITAL_GAMBLING,
+ CTRL_COUNT
+ };
+
+ enum
+ {
+ CTRL_P1,
+ CTRL_P2,
+ CTRL_P3,
+ CTRL_P4,
+ CTRL_P5,
+ CTRL_P6,
+ CTRL_P7,
+ CTRL_P8,
+ CTRL_PCOUNT
+ };
+
+ // directions
+ const UINT8 DIR_UP = 0x01;
+ const UINT8 DIR_DOWN = 0x02;
+ const UINT8 DIR_LEFT = 0x04;
+ const UINT8 DIR_RIGHT = 0x08;
+
+ // initialize the list of control types
+ struct
+ {
+ const char * type; // general type of input
+ int player; // player which the input belongs to
+ int nbuttons; // total number of buttons
+ int maxbuttons; // max index of buttons (using IPT_BUTTONn) [probably to be removed soonish]
+ int ways; // directions for joystick
+ bool analog; // is analog input?
+ UINT8 helper[3]; // for dual joysticks [possibly to be removed soonish]
+ INT32 min; // analog minimum value
+ INT32 max; // analog maximum value
+ INT32 sensitivity; // default analog sensitivity
+ INT32 keydelta; // default analog keydelta
+ bool reverse; // default analog reverse setting
+ } control_info[CTRL_COUNT * CTRL_PCOUNT];
+
+ memset(&control_info, 0, sizeof(control_info));
+
+ // tracking info as we iterate
+ int nplayer = 0;
+ int ncoin = 0;
+ bool service = false;
+ bool tilt = false;
+
+ // iterate over the ports
+ for (ioport_port &port : portlist)
+ {
+ int ctrl_type = CTRL_DIGITAL_BUTTONS;
+ bool ctrl_analog = FALSE;
+ for (ioport_field &field : port.fields())
+ {
+
+ // track the highest player number
+ if (nplayer < field.player() + 1)
+ nplayer = field.player() + 1;
+
+ // switch off of the type
+ switch (field.type())
+ {
+ // map joysticks
+ case IPT_JOYSTICK_UP:
+ ctrl_type = CTRL_DIGITAL_JOYSTICK;
+ control_info[field.player() * CTRL_COUNT + ctrl_type].type = "joy";
+ control_info[field.player() * CTRL_COUNT + ctrl_type].player = field.player() + 1;
+ control_info[field.player() * CTRL_COUNT + ctrl_type].ways = field.way();
+ control_info[field.player() * CTRL_COUNT + ctrl_type].helper[0] |= DIR_UP;
+ break;
+ case IPT_JOYSTICK_DOWN:
+ ctrl_type = CTRL_DIGITAL_JOYSTICK;
+ control_info[field.player() * CTRL_COUNT + ctrl_type].type = "joy";
+ control_info[field.player() * CTRL_COUNT + ctrl_type].player = field.player() + 1;
+ control_info[field.player() * CTRL_COUNT + ctrl_type].ways = field.way();
+ control_info[field.player() * CTRL_COUNT + ctrl_type].helper[0] |= DIR_DOWN;
+ break;
+ case IPT_JOYSTICK_LEFT:
+ ctrl_type = CTRL_DIGITAL_JOYSTICK;
+ control_info[field.player() * CTRL_COUNT + ctrl_type].type = "joy";
+ control_info[field.player() * CTRL_COUNT + ctrl_type].player = field.player() + 1;
+ control_info[field.player() * CTRL_COUNT + ctrl_type].ways = field.way();
+ control_info[field.player() * CTRL_COUNT + ctrl_type].helper[0] |= DIR_LEFT;
+ break;
+ case IPT_JOYSTICK_RIGHT:
+ ctrl_type = CTRL_DIGITAL_JOYSTICK;
+ control_info[field.player() * CTRL_COUNT + ctrl_type].type = "joy";
+ control_info[field.player() * CTRL_COUNT + ctrl_type].player = field.player() + 1;
+ control_info[field.player() * CTRL_COUNT + ctrl_type].ways = field.way();
+ control_info[field.player() * CTRL_COUNT + ctrl_type].helper[0] |= DIR_RIGHT;
+ break;
+
+ case IPT_JOYSTICKLEFT_UP:
+ ctrl_type = CTRL_DIGITAL_JOYSTICK;
+ control_info[field.player() * CTRL_COUNT + ctrl_type].type = "joy";
+ control_info[field.player() * CTRL_COUNT + ctrl_type].player = field.player() + 1;
+ control_info[field.player() * CTRL_COUNT + ctrl_type].ways = field.way();
+ control_info[field.player() * CTRL_COUNT + ctrl_type].helper[1] |= DIR_UP;
+ break;
+ case IPT_JOYSTICKLEFT_DOWN:
+ ctrl_type = CTRL_DIGITAL_JOYSTICK;
+ control_info[field.player() * CTRL_COUNT + ctrl_type].type = "joy";
+ control_info[field.player() * CTRL_COUNT + ctrl_type].player = field.player() + 1;
+ control_info[field.player() * CTRL_COUNT + ctrl_type].ways = field.way();
+ control_info[field.player() * CTRL_COUNT + ctrl_type].helper[1] |= DIR_DOWN;
+ break;
+ case IPT_JOYSTICKLEFT_LEFT:
+ ctrl_type = CTRL_DIGITAL_JOYSTICK;
+ control_info[field.player() * CTRL_COUNT + ctrl_type].type = "joy";
+ control_info[field.player() * CTRL_COUNT + ctrl_type].player = field.player() + 1;
+ control_info[field.player() * CTRL_COUNT + ctrl_type].ways = field.way();
+ control_info[field.player() * CTRL_COUNT + ctrl_type].helper[1] |= DIR_LEFT;
+ break;
+ case IPT_JOYSTICKLEFT_RIGHT:
+ ctrl_type = CTRL_DIGITAL_JOYSTICK;
+ control_info[field.player() * CTRL_COUNT + ctrl_type].type = "joy";
+ control_info[field.player() * CTRL_COUNT + ctrl_type].player = field.player() + 1;
+ control_info[field.player() * CTRL_COUNT + ctrl_type].ways = field.way();
+ control_info[field.player() * CTRL_COUNT + ctrl_type].helper[1] |= DIR_RIGHT;
+ break;
+
+ case IPT_JOYSTICKRIGHT_UP:
+ ctrl_type = CTRL_DIGITAL_JOYSTICK;
+ control_info[field.player() * CTRL_COUNT + ctrl_type].type = "joy";
+ control_info[field.player() * CTRL_COUNT + ctrl_type].player = field.player() + 1;
+ control_info[field.player() * CTRL_COUNT + ctrl_type].ways = field.way();
+ control_info[field.player() * CTRL_COUNT + ctrl_type].helper[2] |= DIR_UP;
+ break;
+ case IPT_JOYSTICKRIGHT_DOWN:
+ ctrl_type = CTRL_DIGITAL_JOYSTICK;
+ control_info[field.player() * CTRL_COUNT + ctrl_type].type = "joy";
+ control_info[field.player() * CTRL_COUNT + ctrl_type].player = field.player() + 1;
+ control_info[field.player() * CTRL_COUNT + ctrl_type].ways = field.way();
+ control_info[field.player() * CTRL_COUNT + ctrl_type].helper[2] |= DIR_DOWN;
+ break;
+ case IPT_JOYSTICKRIGHT_LEFT:
+ ctrl_type = CTRL_DIGITAL_JOYSTICK;
+ control_info[field.player() * CTRL_COUNT + ctrl_type].type = "joy";
+ control_info[field.player() * CTRL_COUNT + ctrl_type].player = field.player() + 1;
+ control_info[field.player() * CTRL_COUNT + ctrl_type].ways = field.way();
+ control_info[field.player() * CTRL_COUNT + ctrl_type].helper[2] |= DIR_LEFT;
+ break;
+ case IPT_JOYSTICKRIGHT_RIGHT:
+ ctrl_type = CTRL_DIGITAL_JOYSTICK;
+ control_info[field.player() * CTRL_COUNT + ctrl_type].type = "joy";
+ control_info[field.player() * CTRL_COUNT + ctrl_type].player = field.player() + 1;
+ control_info[field.player() * CTRL_COUNT + ctrl_type].ways = field.way();
+ control_info[field.player() * CTRL_COUNT + ctrl_type].helper[2] |= DIR_RIGHT;
+ break;
+
+ // map analog inputs
+ case IPT_AD_STICK_X:
+ case IPT_AD_STICK_Y:
+ case IPT_AD_STICK_Z:
+ ctrl_analog = TRUE;
+ ctrl_type = CTRL_ANALOG_JOYSTICK;
+ control_info[field.player() * CTRL_COUNT + ctrl_type].type = "stick";
+ control_info[field.player() * CTRL_COUNT + ctrl_type].player = field.player() + 1;
+ control_info[field.player() * CTRL_COUNT + ctrl_type].analog = TRUE;
+ break;
+
+ case IPT_PADDLE:
+ case IPT_PADDLE_V:
+ ctrl_analog = TRUE;
+ ctrl_type = CTRL_ANALOG_PADDLE;
+ control_info[field.player() * CTRL_COUNT + ctrl_type].type = "paddle";
+ control_info[field.player() * CTRL_COUNT + ctrl_type].player = field.player() + 1;
+ control_info[field.player() * CTRL_COUNT + ctrl_type].analog = TRUE;
+ break;
+
+ case IPT_PEDAL:
+ case IPT_PEDAL2:
+ case IPT_PEDAL3:
+ ctrl_analog = TRUE;
+ ctrl_type = CTRL_ANALOG_PEDAL;
+ control_info[field.player() * CTRL_COUNT + ctrl_type].type = "pedal";
+ control_info[field.player() * CTRL_COUNT + ctrl_type].player = field.player() + 1;
+ control_info[field.player() * CTRL_COUNT + ctrl_type].analog = TRUE;
+ break;
+
+ case IPT_LIGHTGUN_X:
+ case IPT_LIGHTGUN_Y:
+ ctrl_analog = TRUE;
+ ctrl_type = CTRL_ANALOG_LIGHTGUN;
+ control_info[field.player() * CTRL_COUNT + ctrl_type].type = "lightgun";
+ control_info[field.player() * CTRL_COUNT + ctrl_type].player = field.player() + 1;
+ control_info[field.player() * CTRL_COUNT + ctrl_type].analog = TRUE;
+ break;
+
+ case IPT_POSITIONAL:
+ case IPT_POSITIONAL_V:
+ ctrl_analog = TRUE;
+ ctrl_type = CTRL_ANALOG_POSITIONAL;
+ control_info[field.player() * CTRL_COUNT + ctrl_type].type = "positional";
+ control_info[field.player() * CTRL_COUNT + ctrl_type].player = field.player() + 1;
+ control_info[field.player() * CTRL_COUNT + ctrl_type].analog = TRUE;
+ break;
+
+ case IPT_DIAL:
+ case IPT_DIAL_V:
+ ctrl_analog = TRUE;
+ ctrl_type = CTRL_ANALOG_DIAL;
+ control_info[field.player() * CTRL_COUNT + ctrl_type].type = "dial";
+ control_info[field.player() * CTRL_COUNT + ctrl_type].player = field.player() + 1;
+ control_info[field.player() * CTRL_COUNT + ctrl_type].analog = TRUE;
+ break;
+
+ case IPT_TRACKBALL_X:
+ case IPT_TRACKBALL_Y:
+ ctrl_analog = TRUE;
+ ctrl_type = CTRL_ANALOG_TRACKBALL;
+ control_info[field.player() * CTRL_COUNT + ctrl_type].type = "trackball";
+ control_info[field.player() * CTRL_COUNT + ctrl_type].player = field.player() + 1;
+ control_info[field.player() * CTRL_COUNT + ctrl_type].analog = TRUE;
+ break;
+
+ case IPT_MOUSE_X:
+ case IPT_MOUSE_Y:
+ ctrl_analog = TRUE;
+ ctrl_type = CTRL_ANALOG_MOUSE;
+ control_info[field.player() * CTRL_COUNT + ctrl_type].type = "mouse";
+ control_info[field.player() * CTRL_COUNT + ctrl_type].player = field.player() + 1;
+ control_info[field.player() * CTRL_COUNT + ctrl_type].analog = TRUE;
+ break;
+
+ // map buttons
+ case IPT_BUTTON1:
+ case IPT_BUTTON2:
+ case IPT_BUTTON3:
+ case IPT_BUTTON4:
+ case IPT_BUTTON5:
+ case IPT_BUTTON6:
+ case IPT_BUTTON7:
+ case IPT_BUTTON8:
+ case IPT_BUTTON9:
+ case IPT_BUTTON10:
+ case IPT_BUTTON11:
+ case IPT_BUTTON12:
+ case IPT_BUTTON13:
+ case IPT_BUTTON14:
+ case IPT_BUTTON15:
+ case IPT_BUTTON16:
+ ctrl_analog = FALSE;
+ if (control_info[field.player() * CTRL_COUNT + ctrl_type].type == nullptr)
+ {
+ control_info[field.player() * CTRL_COUNT + ctrl_type].type = "only_buttons";
+ control_info[field.player() * CTRL_COUNT + ctrl_type].player = field.player() + 1;
+ control_info[field.player() * CTRL_COUNT + ctrl_type].analog = FALSE;
+ }
+ control_info[field.player() * CTRL_COUNT + ctrl_type].maxbuttons = MAX(control_info[field.player() * CTRL_COUNT + ctrl_type].maxbuttons, field.type() - IPT_BUTTON1 + 1);
+ control_info[field.player() * CTRL_COUNT + ctrl_type].nbuttons++;
+ break;
+
+ // track maximum coin index
+ case IPT_COIN1:
+ case IPT_COIN2:
+ case IPT_COIN3:
+ case IPT_COIN4:
+ case IPT_COIN5:
+ case IPT_COIN6:
+ case IPT_COIN7:
+ case IPT_COIN8:
+ ncoin = MAX(ncoin, field.type() - IPT_COIN1 + 1);
+ break;
+
+ // track presence of keypads and keyboards
+ case IPT_KEYPAD:
+ ctrl_type = CTRL_DIGITAL_KEYPAD;
+ control_info[field.player() * CTRL_COUNT + ctrl_type].type = "keypad";
+ control_info[field.player() * CTRL_COUNT + ctrl_type].player = field.player() + 1;
+ control_info[field.player() * CTRL_COUNT + ctrl_type].nbuttons++;
+ break;
+
+ case IPT_KEYBOARD:
+ ctrl_type = CTRL_DIGITAL_KEYBOARD;
+ control_info[field.player() * CTRL_COUNT + ctrl_type].type = "keyboard";
+ control_info[field.player() * CTRL_COUNT + ctrl_type].player = field.player() + 1;
+ control_info[field.player() * CTRL_COUNT + ctrl_type].nbuttons++;
+ break;
+
+ // additional types
+ case IPT_SERVICE:
+ service = true;
+ break;
+
+ case IPT_TILT:
+ tilt = true;
+ break;
+
+ default:
+ if (field.type() > IPT_MAHJONG_FIRST && field.type() < IPT_MAHJONG_LAST)
+ {
+ ctrl_type = CTRL_DIGITAL_MAHJONG;
+ control_info[field.player() * CTRL_COUNT + ctrl_type].type = "mahjong";
+ control_info[field.player() * CTRL_COUNT + ctrl_type].player = field.player() + 1;
+ control_info[field.player() * CTRL_COUNT + ctrl_type].nbuttons++;
+ }
+ else if (field.type() > IPT_HANAFUDA_FIRST && field.type() < IPT_HANAFUDA_LAST)
+ {
+ ctrl_type = CTRL_DIGITAL_HANAFUDA;
+ control_info[field.player() * CTRL_COUNT + ctrl_type].type = "hanafuda";
+ control_info[field.player() * CTRL_COUNT + ctrl_type].player = field.player() + 1;
+ control_info[field.player() * CTRL_COUNT + ctrl_type].nbuttons++;
+ }
+ else if (field.type() > IPT_GAMBLING_FIRST && field.type() < IPT_GAMBLING_LAST)
+ {
+ ctrl_type = CTRL_DIGITAL_GAMBLING;
+ control_info[field.player() * CTRL_COUNT + ctrl_type].type = "gambling";
+ control_info[field.player() * CTRL_COUNT + ctrl_type].player = field.player() + 1;
+ control_info[field.player() * CTRL_COUNT + ctrl_type].nbuttons++;
+ }
+ break;
+ }
+
+ if (ctrl_analog)
+ {
+ // get the analog stats
+ if (field.minval() != 0)
+ control_info[field.player() * CTRL_COUNT + ctrl_type].min = field.minval();
+ if (field.maxval() != 0)
+ control_info[field.player() * CTRL_COUNT + ctrl_type].max = field.maxval();
+ if (field.sensitivity() != 0)
+ control_info[field.player() * CTRL_COUNT + ctrl_type].sensitivity = field.sensitivity();
+ if (field.delta() != 0)
+ control_info[field.player() * CTRL_COUNT + ctrl_type].keydelta = field.delta();
+ if (field.analog_reverse() != 0)
+ control_info[field.player() * CTRL_COUNT + ctrl_type].reverse = TRUE;
+ }
+ }
+ }
+
+ // Clean-up those entries, if any, where buttons were defined in a separate port than the actual controller they belong to.
+ // This is quite often the case, especially for arcades where controls can be easily mapped to separate input ports on PCB.
+ // If such situation would only happen for joystick, it would be possible to work it around by initializing differently
+ // ctrl_type above, but it is quite common among analog inputs as well (for instance, this is the tipical situation
+ // for lightguns) and therefore we really need this separate loop.
+ for (int i = 0; i < CTRL_PCOUNT; i++)
+ {
+ bool fix_done = FALSE;
+ for (int j = 1; j < CTRL_COUNT; j++)
+ if (control_info[i * CTRL_COUNT].type != nullptr && control_info[i * CTRL_COUNT + j].type != nullptr && !fix_done)
+ {
+ control_info[i * CTRL_COUNT + j].nbuttons += control_info[i * CTRL_COUNT].nbuttons;
+ control_info[i * CTRL_COUNT + j].maxbuttons = MAX(control_info[i * CTRL_COUNT + j].maxbuttons, control_info[i * CTRL_COUNT].maxbuttons);
+
+ memset(&control_info[i * CTRL_COUNT], 0, sizeof(control_info[0]));
+ fix_done = TRUE;
+ }
+ }
+
+ // Output the input info
+ // First basic info
+ fprintf(m_output, "\t\t<input");
+ fprintf(m_output, " players=\"%d\"", nplayer);
+ if (ncoin != 0)
+ fprintf(m_output, " coins=\"%d\"", ncoin);
+ if (service)
+ fprintf(m_output, " service=\"yes\"");
+ if (tilt)
+ fprintf(m_output, " tilt=\"yes\"");
+ fprintf(m_output, ">\n");
+
+ // Then controller specific ones
+ for (auto & elem : control_info)
+ if (elem.type != nullptr)
+ {
+ //printf("type %s - player %d - buttons %d\n", elem.type, elem.player, elem.nbuttons);
+ if (elem.analog)
+ {
+ fprintf(m_output, "\t\t\t<control type=\"%s\"", xml_normalize_string(elem.type));
+ if (nplayer > 1)
+ fprintf(m_output, " player=\"%d\"", elem.player);
+ if (elem.nbuttons > 0)
+ fprintf(m_output, " buttons=\"%d\"", strcmp(elem.type, "stick") ? elem.nbuttons : elem.maxbuttons);
+ if (elem.min != 0 || elem.max != 0)
+ {
+ fprintf(m_output, " minimum=\"%d\"", elem.min);
+ fprintf(m_output, " maximum=\"%d\"", elem.max);
+ }
+ if (elem.sensitivity != 0)
+ fprintf(m_output, " sensitivity=\"%d\"", elem.sensitivity);
+ if (elem.keydelta != 0)
+ fprintf(m_output, " keydelta=\"%d\"", elem.keydelta);
+ if (elem.reverse)
+ fprintf(m_output, " reverse=\"yes\"");
+
+ fprintf(m_output, "/>\n");
+ }
+ else
+ {
+ if (elem.helper[1] == 0 && elem.helper[2] != 0) { elem.helper[1] = elem.helper[2]; elem.helper[2] = 0; }
+ if (elem.helper[0] == 0 && elem.helper[1] != 0) { elem.helper[0] = elem.helper[1]; elem.helper[1] = 0; }
+ if (elem.helper[1] == 0 && elem.helper[2] != 0) { elem.helper[1] = elem.helper[2]; elem.helper[2] = 0; }
+ const char *joys = (elem.helper[2] != 0) ? "triple" : (elem.helper[1] != 0) ? "double" : "";
+ fprintf(m_output, "\t\t\t<control type=\"%s%s\"", joys, xml_normalize_string(elem.type));
+ if (nplayer > 1)
+ fprintf(m_output, " player=\"%d\"", elem.player);
+ if (elem.nbuttons > 0)
+ fprintf(m_output, " buttons=\"%d\"", strcmp(elem.type, "joy") ? elem.nbuttons : elem.maxbuttons);
+ for (int lp = 0; lp < 3 && elem.helper[lp] != 0; lp++)
+ {
+ const char *plural = (lp==2) ? "3" : (lp==1) ? "2" : "";
+ const char *ways;
+ std::string helper;
+ switch (elem.helper[lp] & (DIR_UP | DIR_DOWN | DIR_LEFT | DIR_RIGHT))
+ {
+ case DIR_UP | DIR_DOWN | DIR_LEFT | DIR_RIGHT:
+ helper = string_format("%d", (elem.ways == 0) ? 8 : elem.ways);
+ ways = helper.c_str();
+ break;
+ case DIR_LEFT | DIR_RIGHT:
+ ways = "2";
+ break;
+ case DIR_UP | DIR_DOWN:
+ ways = "vertical2";
+ break;
+ case DIR_UP:
+ case DIR_DOWN:
+ case DIR_LEFT:
+ case DIR_RIGHT:
+ ways = "1";
+ break;
+ case DIR_UP | DIR_DOWN | DIR_LEFT:
+ case DIR_UP | DIR_DOWN | DIR_RIGHT:
+ case DIR_UP | DIR_LEFT | DIR_RIGHT:
+ case DIR_DOWN | DIR_LEFT | DIR_RIGHT:
+ ways = (elem.ways == 4) ? "3 (half4)" : "5 (half8)";
+ break;
+ default:
+ ways = "strange2";
+ break;
+ }
+ fprintf(m_output, " ways%s=\"%s\"", plural, ways);
+ }
+ fprintf(m_output, "/>\n");
+ }
+ }
+
+ fprintf(m_output, "\t\t</input>\n");
}
@@ -1229,6 +1429,7 @@ void info_xml_creator::output_images(device_t &device, const char *root_tag)
{
if (strcmp(imagedev->device().tag(), device.tag()))
{
+ bool loadable = imagedev->user_loadable();
std::string newtag(imagedev->device().tag()), oldtag(":");
newtag = newtag.substr(newtag.find(oldtag.append(root_tag)) + oldtag.length());
@@ -1239,9 +1440,13 @@ void info_xml_creator::output_images(device_t &device, const char *root_tag)
if (imagedev->device().tag())
fprintf(m_output, " tag=\"%s\"", xml_normalize_string(newtag.c_str()));
- // is this device mandatory?
- if (imagedev->must_be_loaded())
- fprintf(m_output, " mandatory=\"1\"");
+ // is this device available as media switch?
+ if (!loadable)
+ fprintf(m_output, " fixed_image=\"1\"");
+
+ // is this device mandatory?
+ if (imagedev->must_be_loaded())
+ fprintf(m_output, " mandatory=\"1\"");
if (imagedev->image_interface() && imagedev->image_interface()[0])
fprintf(m_output, " interface=\"%s\"", xml_normalize_string(imagedev->image_interface()));
@@ -1249,25 +1454,27 @@ void info_xml_creator::output_images(device_t &device, const char *root_tag)
// close the XML tag
fprintf(m_output, ">\n");
- const char *name = imagedev->instance_name();
- const char *shortname = imagedev->brief_instance_name();
-
- fprintf(m_output, "\t\t\t<instance");
- fprintf(m_output, " name=\"%s\"", xml_normalize_string(name));
- fprintf(m_output, " briefname=\"%s\"", xml_normalize_string(shortname));
- fprintf(m_output, "/>\n");
-
- std::string extensions(imagedev->file_extensions());
-
- char *ext = strtok((char *)extensions.c_str(), ",");
- while (ext != nullptr)
- {
- fprintf(m_output, "\t\t\t<extension");
- fprintf(m_output, " name=\"%s\"", xml_normalize_string(ext));
- fprintf(m_output, "/>\n");
- ext = strtok(nullptr, ",");
- }
-
+ if (loadable)
+ {
+ const char *name = imagedev->instance_name();
+ const char *shortname = imagedev->brief_instance_name();
+
+ fprintf(m_output, "\t\t\t<instance");
+ fprintf(m_output, " name=\"%s\"", xml_normalize_string(name));
+ fprintf(m_output, " briefname=\"%s\"", xml_normalize_string(shortname));
+ fprintf(m_output, "/>\n");
+
+ std::string extensions(imagedev->file_extensions());
+
+ char *ext = strtok((char *)extensions.c_str(), ",");
+ while (ext != nullptr)
+ {
+ fprintf(m_output, "\t\t\t<extension");
+ fprintf(m_output, " name=\"%s\"", xml_normalize_string(ext));
+ fprintf(m_output, "/>\n");
+ ext = strtok(nullptr, ",");
+ }
+ }
fprintf(m_output, "\t\t</device>\n");
}
}