mirror of
https://github.com/holub/mame
synced 2025-04-16 13:34:55 +03:00
This one documents what I think is a real bug of the Japanese game Sports Pad Soccer: part of the player 2 input is read from player 1 input instead. The patch also reorganizes code of the Japanese Sports Pad controller device and replace some PORT_CUSTOM/PORT_CHANGED callbacks with PORT_READ_LINE/PORT_WRITE_LINE. [Enik]
This commit is contained in:
parent
865253ccb0
commit
33c5196a42
@ -6128,6 +6128,7 @@
|
||||
</part>
|
||||
</software>
|
||||
|
||||
<!-- Notes: This has a player 2 input bug: it reads part of player 1 data instead (see sportsjp.cpp) -->
|
||||
<software name="sportssc" cloneof="worldsoc">
|
||||
<description>Sports Pad Soccer (Jpn)</description>
|
||||
<year>1988</year>
|
||||
|
@ -12,6 +12,13 @@ Release data from the Sega Retro project:
|
||||
Year: 1989 Country/region: BR Model code: 010470
|
||||
Year: 198? Country/region: KR Model code: ?
|
||||
|
||||
Notes:
|
||||
|
||||
The Light Phaser gun doesn't work with the Japanese SMS and Sega Mark III.
|
||||
There are reports about Light Phaser working on the second Korean SMS
|
||||
version, and a Korean advert shows support on the first version (Gam*Boy I,
|
||||
although based on Japanese SMS).
|
||||
|
||||
**********************************************************************/
|
||||
|
||||
#include "lphaser.h"
|
||||
@ -29,7 +36,7 @@ const device_type SMS_LIGHT_PHASER = &device_creator<sms_light_phaser_device>;
|
||||
#define LGUN_X_INTERVAL 4
|
||||
|
||||
|
||||
CUSTOM_INPUT_MEMBER( sms_light_phaser_device::th_pin_r )
|
||||
READ_LINE_MEMBER( sms_light_phaser_device::th_pin_r )
|
||||
{
|
||||
// The returned value is inverted due to IP_ACTIVE_LOW mapping.
|
||||
return ~m_sensor_last_state;
|
||||
@ -46,7 +53,7 @@ INPUT_CHANGED_MEMBER( sms_light_phaser_device::position_changed )
|
||||
static INPUT_PORTS_START( sms_light_phaser )
|
||||
PORT_START("CTRL_PORT")
|
||||
PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_BUTTON1 ) // TL (trigger)
|
||||
PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_SPECIAL ) PORT_CUSTOM_MEMBER(DEVICE_SELF, sms_light_phaser_device, th_pin_r, nullptr)
|
||||
PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_SPECIAL ) PORT_READ_LINE_DEVICE_MEMBER(DEVICE_SELF, sms_light_phaser_device, th_pin_r)
|
||||
PORT_BIT( 0x9f, IP_ACTIVE_LOW, IPT_UNUSED )
|
||||
|
||||
PORT_START("LPHASER_X")
|
||||
|
@ -34,7 +34,7 @@ public:
|
||||
// optional information overrides
|
||||
virtual ioport_constructor device_input_ports() const override;
|
||||
|
||||
DECLARE_CUSTOM_INPUT_MEMBER( th_pin_r );
|
||||
DECLARE_READ_LINE_MEMBER( th_pin_r );
|
||||
DECLARE_INPUT_CHANGED_MEMBER( position_changed );
|
||||
|
||||
protected:
|
||||
|
@ -38,7 +38,7 @@ const device_type SMS_PADDLE = &device_creator<sms_paddle_device>;
|
||||
#define PADDLE_INTERVAL attotime::from_hz(XTAL_53_693175MHz/15/100)
|
||||
|
||||
|
||||
CUSTOM_INPUT_MEMBER( sms_paddle_device::dir_pins_r )
|
||||
CUSTOM_INPUT_MEMBER( sms_paddle_device::rldu_pins_r )
|
||||
{
|
||||
UINT8 data = m_paddle_x->read();
|
||||
|
||||
@ -50,7 +50,7 @@ CUSTOM_INPUT_MEMBER( sms_paddle_device::dir_pins_r )
|
||||
}
|
||||
|
||||
|
||||
CUSTOM_INPUT_MEMBER( sms_paddle_device::tr_pin_r )
|
||||
READ_LINE_MEMBER( sms_paddle_device::tr_pin_r )
|
||||
{
|
||||
// The returned value is inverted due to IP_ACTIVE_LOW mapping.
|
||||
return ~m_read_state;
|
||||
@ -59,11 +59,11 @@ CUSTOM_INPUT_MEMBER( sms_paddle_device::tr_pin_r )
|
||||
|
||||
static INPUT_PORTS_START( sms_paddle )
|
||||
PORT_START("CTRL_PORT")
|
||||
PORT_BIT( 0x0f, IP_ACTIVE_LOW, IPT_SPECIAL ) PORT_CUSTOM_MEMBER(DEVICE_SELF, sms_paddle_device, dir_pins_r, nullptr) // Directional pins
|
||||
PORT_BIT( 0x0f, IP_ACTIVE_LOW, IPT_SPECIAL ) PORT_CUSTOM_MEMBER(DEVICE_SELF, sms_paddle_device, rldu_pins_r, nullptr) // R,L,D,U
|
||||
PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_UNUSED ) // Vcc
|
||||
PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_BUTTON1 ) // TL
|
||||
PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_UNUSED ) // TH
|
||||
PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_SPECIAL ) PORT_CUSTOM_MEMBER(DEVICE_SELF, sms_paddle_device, tr_pin_r, nullptr)
|
||||
PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_SPECIAL ) PORT_READ_LINE_DEVICE_MEMBER( DEVICE_SELF, sms_paddle_device, tr_pin_r ) // TR
|
||||
|
||||
PORT_START("PADDLE_X") // Paddle knob
|
||||
PORT_BIT( 0xff, 0x80, IPT_PADDLE) PORT_SENSITIVITY(40) PORT_KEYDELTA(20) PORT_CENTERDELTA(0) PORT_MINMAX(0,255)
|
||||
|
@ -33,8 +33,8 @@ public:
|
||||
// optional information overrides
|
||||
virtual ioport_constructor device_input_ports() const override;
|
||||
|
||||
DECLARE_CUSTOM_INPUT_MEMBER( dir_pins_r );
|
||||
DECLARE_CUSTOM_INPUT_MEMBER( tr_pin_r );
|
||||
DECLARE_CUSTOM_INPUT_MEMBER( rldu_pins_r ); // Right, Left, Down and Up lines.
|
||||
DECLARE_READ_LINE_MEMBER( tr_pin_r );
|
||||
|
||||
protected:
|
||||
// device-level overrides
|
||||
|
@ -82,21 +82,21 @@ void sms_sports_pad_device::device_timer(emu_timer &timer, device_timer_id id, i
|
||||
}
|
||||
|
||||
|
||||
CUSTOM_INPUT_MEMBER( sms_sports_pad_device::th_pin_r )
|
||||
READ_LINE_MEMBER( sms_sports_pad_device::th_pin_r )
|
||||
{
|
||||
return m_last_data;
|
||||
return m_th_pin_state;
|
||||
}
|
||||
|
||||
|
||||
INPUT_CHANGED_MEMBER( sms_sports_pad_device::th_pin_w )
|
||||
WRITE_LINE_MEMBER( sms_sports_pad_device::th_pin_w )
|
||||
{
|
||||
m_read_state = (m_read_state + 1) & 3;
|
||||
m_sportspad_timer->adjust(m_interval);
|
||||
m_last_data = newval;
|
||||
m_th_pin_state = state;
|
||||
}
|
||||
|
||||
|
||||
CUSTOM_INPUT_MEMBER( sms_sports_pad_device::dir_pins_r )
|
||||
CUSTOM_INPUT_MEMBER( sms_sports_pad_device::rldu_pins_r )
|
||||
{
|
||||
UINT8 data = 0;
|
||||
|
||||
@ -123,17 +123,17 @@ CUSTOM_INPUT_MEMBER( sms_sports_pad_device::dir_pins_r )
|
||||
|
||||
static INPUT_PORTS_START( sms_sports_pad )
|
||||
PORT_START("SPORTS_IN")
|
||||
PORT_BIT( 0x0f, IP_ACTIVE_LOW, IPT_SPECIAL ) PORT_CUSTOM_MEMBER(DEVICE_SELF, sms_sports_pad_device, dir_pins_r, nullptr) // Directional pins
|
||||
PORT_BIT( 0x0f, IP_ACTIVE_LOW, IPT_SPECIAL ) PORT_CUSTOM_MEMBER(DEVICE_SELF, sms_sports_pad_device, rldu_pins_r, nullptr) // R,L,D,U
|
||||
PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_UNUSED ) // Vcc
|
||||
PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_BUTTON1 ) // TL (Button 1)
|
||||
PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_SPECIAL ) PORT_CUSTOM_MEMBER(DEVICE_SELF, sms_sports_pad_device, th_pin_r, nullptr)
|
||||
PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_SPECIAL ) PORT_READ_LINE_DEVICE_MEMBER(DEVICE_SELF, sms_sports_pad_device, th_pin_r) // TH
|
||||
PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_BUTTON2 ) // TR (Button 2)
|
||||
|
||||
PORT_START("SPORTS_OUT")
|
||||
PORT_BIT( 0x0f, IP_ACTIVE_LOW, IPT_UNUSED ) // Directional pins
|
||||
PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_UNUSED ) // Vcc
|
||||
PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_UNUSED ) // TL (Button 1)
|
||||
PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_OUTPUT ) PORT_CHANGED_MEMBER(DEVICE_SELF, sms_sports_pad_device, th_pin_w, nullptr)
|
||||
PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_OUTPUT ) PORT_WRITE_LINE_DEVICE_MEMBER(DEVICE_SELF, sms_sports_pad_device, th_pin_w) // TH
|
||||
PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNUSED ) // TR (Button 2)
|
||||
|
||||
PORT_START("SPORTS_X") /* Sports Pad X axis */
|
||||
@ -171,7 +171,7 @@ sms_sports_pad_device::sms_sports_pad_device(const machine_config &mconfig, cons
|
||||
m_sports_x(*this, "SPORTS_X"),
|
||||
m_sports_y(*this, "SPORTS_Y"),
|
||||
m_read_state(0),
|
||||
m_last_data(0),
|
||||
m_th_pin_state(0),
|
||||
m_x_axis_reset_value(0x80), // value 0x80 helps when start playing paddle games.
|
||||
m_y_axis_reset_value(0x80),
|
||||
m_interval(SPORTS_PAD_INTERVAL), m_sportspad_timer(nullptr)
|
||||
@ -188,7 +188,7 @@ void sms_sports_pad_device::device_start()
|
||||
m_sportspad_timer = timer_alloc(TIMER_SPORTSPAD);
|
||||
|
||||
save_item(NAME(m_read_state));
|
||||
save_item(NAME(m_last_data));
|
||||
save_item(NAME(m_th_pin_state));
|
||||
save_item(NAME(m_x_axis_reset_value));
|
||||
save_item(NAME(m_y_axis_reset_value));
|
||||
}
|
||||
|
@ -33,9 +33,9 @@ public:
|
||||
// optional information overrides
|
||||
virtual ioport_constructor device_input_ports() const override;
|
||||
|
||||
DECLARE_CUSTOM_INPUT_MEMBER( dir_pins_r );
|
||||
DECLARE_CUSTOM_INPUT_MEMBER( th_pin_r );
|
||||
DECLARE_INPUT_CHANGED_MEMBER( th_pin_w );
|
||||
DECLARE_CUSTOM_INPUT_MEMBER( rldu_pins_r ); // Right, Left, Down and Up lines.
|
||||
DECLARE_READ_LINE_MEMBER( th_pin_r );
|
||||
DECLARE_WRITE_LINE_MEMBER( th_pin_w );
|
||||
|
||||
protected:
|
||||
// device-level overrides
|
||||
@ -52,7 +52,7 @@ private:
|
||||
required_ioport m_sports_y;
|
||||
|
||||
UINT8 m_read_state;
|
||||
UINT8 m_last_data;
|
||||
UINT8 m_th_pin_state;
|
||||
UINT8 m_x_axis_reset_value;
|
||||
UINT8 m_y_axis_reset_value;
|
||||
const attotime m_interval;
|
||||
|
@ -22,6 +22,13 @@ Notes:
|
||||
used by the US model, due to the missing TH line on Sega Mark III
|
||||
controller ports.
|
||||
|
||||
A bug was discovered in the player 2 input handling code of the only known
|
||||
good ROM dump of Sports Pad Soccer (JP):
|
||||
size="131072" crc="41c948bf" sha1="7634ce39e87049dad1ee4f32a80d728e4bd1f81f"
|
||||
At address $12D1, instead read the upper 2 bits of port $DC and lower 2 bits
|
||||
of port $DD (to obtain the lower nibble of the current axis for player 2),
|
||||
the code wrongly reads the lower nibble of port $DC, that is player 1 data.
|
||||
|
||||
**********************************************************************/
|
||||
|
||||
#include "sportsjp.h"
|
||||
@ -39,38 +46,24 @@ const device_type SMS_SPORTS_PAD_JP = &device_creator<sms_sports_pad_jp_device>;
|
||||
|
||||
|
||||
|
||||
DECLARE_CUSTOM_INPUT_MEMBER( sms_sports_pad_jp_device::dir_pins_r )
|
||||
{
|
||||
UINT8 data = 0;
|
||||
|
||||
switch (m_read_state)
|
||||
{
|
||||
case 0:
|
||||
data = m_sports_jp_x->read() >> 4;
|
||||
break;
|
||||
case 1:
|
||||
data = m_sports_jp_x->read();
|
||||
break;
|
||||
case 2:
|
||||
data = m_sports_jp_y->read() >> 4;
|
||||
break;
|
||||
case 3:
|
||||
data = m_sports_jp_y->read();
|
||||
break;
|
||||
}
|
||||
|
||||
// The returned value is inverted due to IP_ACTIVE_LOW mapping.
|
||||
return ~(data & 0x0f);
|
||||
}
|
||||
// The returned value is inverted due to IP_ACTIVE_LOW mapping.
|
||||
READ_LINE_MEMBER( sms_sports_pad_jp_device::tl_pin_r ) { return ~m_tl_pin_state; }
|
||||
READ_LINE_MEMBER( sms_sports_pad_jp_device::tr_pin_r ) { return ~m_tr_pin_state; }
|
||||
CUSTOM_INPUT_MEMBER( sms_sports_pad_jp_device::rldu_pins_r ) { return ~(m_rldu_pins_state & 0x0f); }
|
||||
|
||||
|
||||
static INPUT_PORTS_START( sms_sports_pad_jp )
|
||||
PORT_START("SPORTS_JP_IN")
|
||||
PORT_BIT( 0x0f, IP_ACTIVE_LOW, IPT_SPECIAL ) PORT_CUSTOM_MEMBER(DEVICE_SELF, sms_sports_pad_jp_device, dir_pins_r, nullptr) // Directional pins
|
||||
PORT_BIT( 0x0f, IP_ACTIVE_LOW, IPT_SPECIAL ) PORT_CUSTOM_MEMBER(DEVICE_SELF, sms_sports_pad_jp_device, rldu_pins_r, nullptr) // R,L,D,U
|
||||
PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_UNUSED ) // Vcc
|
||||
PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_BUTTON1 ) // TL (Button 1)
|
||||
PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_SPECIAL ) PORT_READ_LINE_DEVICE_MEMBER( DEVICE_SELF, sms_sports_pad_jp_device, tl_pin_r ) // TL
|
||||
PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_UNUSED ) // TH
|
||||
PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_BUTTON2 ) // TR (Button 2)
|
||||
PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_SPECIAL ) PORT_READ_LINE_DEVICE_MEMBER( DEVICE_SELF, sms_sports_pad_jp_device, tr_pin_r ) // TR
|
||||
|
||||
PORT_START("SPORTS_JP_BT") /* Sports Pad buttons nibble */
|
||||
PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_BUTTON1 )
|
||||
PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_BUTTON2 )
|
||||
PORT_BIT( 0x0c, IP_ACTIVE_LOW, IPT_UNUSED )
|
||||
|
||||
PORT_START("SPORTS_JP_X") /* Sports Pad X axis */
|
||||
PORT_BIT( 0xff, 0x00, IPT_TRACKBALL_X ) PORT_SENSITIVITY(50) PORT_KEYDELTA(40)
|
||||
@ -103,9 +96,12 @@ sms_sports_pad_jp_device::sms_sports_pad_jp_device(const machine_config &mconfig
|
||||
device_t(mconfig, SMS_SPORTS_PAD_JP, "Sega SMS Sports Pad JP", tag, owner, clock, "sms_sports_pad_jp", __FILE__),
|
||||
device_sms_control_port_interface(mconfig, *this),
|
||||
m_sports_jp_in(*this, "SPORTS_JP_IN"),
|
||||
m_sports_jp_bt(*this, "SPORTS_JP_BT"),
|
||||
m_sports_jp_x(*this, "SPORTS_JP_X"),
|
||||
m_sports_jp_y(*this, "SPORTS_JP_Y"),
|
||||
m_read_state(0),
|
||||
m_rldu_pins_state(0x0f),
|
||||
m_tl_pin_state(1),
|
||||
m_tr_pin_state(1),
|
||||
m_interval(SPORTS_PAD_JP_INTERVAL)
|
||||
{
|
||||
}
|
||||
@ -120,7 +116,9 @@ void sms_sports_pad_jp_device::device_start()
|
||||
m_start_time = machine().time();
|
||||
|
||||
save_item(NAME(m_start_time));
|
||||
save_item(NAME(m_read_state));
|
||||
save_item(NAME(m_rldu_pins_state));
|
||||
save_item(NAME(m_tl_pin_state));
|
||||
save_item(NAME(m_tr_pin_state));
|
||||
}
|
||||
|
||||
|
||||
@ -130,41 +128,41 @@ void sms_sports_pad_jp_device::device_start()
|
||||
|
||||
UINT8 sms_sports_pad_jp_device::peripheral_r()
|
||||
{
|
||||
UINT8 data;
|
||||
int num_intervals = (machine().time() - m_start_time).as_double() / m_interval.as_double();
|
||||
m_read_state = num_intervals % 5;
|
||||
|
||||
data = m_sports_jp_in->read();
|
||||
|
||||
switch (m_read_state)
|
||||
switch (num_intervals % 5)
|
||||
{
|
||||
case 0:
|
||||
// X high nibble
|
||||
data &= ~0x20; // TL 0
|
||||
data &= ~0x80; // TR 0
|
||||
m_rldu_pins_state = m_sports_jp_x->read() >> 4;
|
||||
m_tl_pin_state = 0;
|
||||
m_tr_pin_state = 0;
|
||||
break;
|
||||
case 1:
|
||||
// X low nibble
|
||||
data |= 0x20; // TL 1
|
||||
data &= ~0x80; // TR 0
|
||||
m_rldu_pins_state = m_sports_jp_x->read();
|
||||
m_tl_pin_state = 1;
|
||||
m_tr_pin_state = 0;
|
||||
break;
|
||||
case 2:
|
||||
// Y high nibble
|
||||
data &= ~0x20; // TL 0
|
||||
data &= ~0x80; // TR 0
|
||||
m_rldu_pins_state = m_sports_jp_y->read() >> 4;
|
||||
m_tl_pin_state = 0;
|
||||
m_tr_pin_state = 0;
|
||||
break;
|
||||
case 3:
|
||||
// Y low nibble
|
||||
data |= 0x20; // TL 1
|
||||
data &= ~0x80; // TR 0
|
||||
m_rldu_pins_state = m_sports_jp_y->read();
|
||||
m_tl_pin_state = 1;
|
||||
m_tr_pin_state = 0;
|
||||
break;
|
||||
case 4:
|
||||
// buttons 1 and 2
|
||||
data = (data & 0x20) >> 5 | (data & 0x80) >> 6 | 0xfc;
|
||||
data |= 0x20; // TL 1
|
||||
data |= 0x80; // TR 1
|
||||
m_rldu_pins_state = m_sports_jp_bt->read();
|
||||
m_tl_pin_state = 1;
|
||||
m_tr_pin_state = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
return data;
|
||||
return m_sports_jp_in->read();
|
||||
}
|
||||
|
@ -33,7 +33,9 @@ public:
|
||||
// optional information overrides
|
||||
virtual ioport_constructor device_input_ports() const override;
|
||||
|
||||
CUSTOM_INPUT_MEMBER( dir_pins_r );
|
||||
DECLARE_CUSTOM_INPUT_MEMBER( rldu_pins_r ); // Right, Left, Down and Up lines.
|
||||
DECLARE_READ_LINE_MEMBER( tl_pin_r );
|
||||
DECLARE_READ_LINE_MEMBER( tr_pin_r );
|
||||
|
||||
protected:
|
||||
// device-level overrides
|
||||
@ -44,10 +46,13 @@ protected:
|
||||
|
||||
private:
|
||||
required_ioport m_sports_jp_in;
|
||||
required_ioport m_sports_jp_bt;
|
||||
required_ioport m_sports_jp_x;
|
||||
required_ioport m_sports_jp_y;
|
||||
|
||||
UINT8 m_read_state;
|
||||
UINT8 m_rldu_pins_state;
|
||||
UINT8 m_tl_pin_state;
|
||||
UINT8 m_tr_pin_state;
|
||||
attotime m_start_time;
|
||||
const attotime m_interval;
|
||||
};
|
||||
|
@ -60,7 +60,7 @@ General compatibility issues on real hardware (not emulation bugs):
|
||||
Paddle controller;
|
||||
- Few games of the ones with FM support need to detect the system region as
|
||||
Japanese to play FM sound;
|
||||
- The Light Phaser gun doesn't work with the Japanese SMS;
|
||||
- The Light Phaser gun doesn't work with the Japanese SMS and Sega Mark III;
|
||||
- There are reports about Light Phaser working on the second Korean SMS
|
||||
version, and a Korean advert shows support on the first version (Gam*Boy I,
|
||||
although based on Japanese SMS);
|
||||
@ -337,10 +337,10 @@ ADDRESS_MAP_END
|
||||
|
||||
// The first Korean SMS version also seems to lack I/O port $3F. Games execute
|
||||
// a region detection procedure that, through that port, sets the mode used by
|
||||
// the TH bits of port $DD and tests their behavior. The region of the first SMS
|
||||
// the TH bits of port $DD and tests their behaviour. The region of the first SMS
|
||||
// version is detected as Japanese (opposite to the second version). However,
|
||||
// as it supports Light Phaser games, it doesn't have the same behavior of the
|
||||
// Japanese SMS. If it had the behavior of other SMS versions, the system
|
||||
// as it supports Light Phaser games, it doesn't have the same behaviour of the
|
||||
// Japanese SMS. If it had the behaviour of other SMS versions, the system
|
||||
// region would be detected as Export, so it probably lacks the port.
|
||||
static ADDRESS_MAP_START( sms1kr_io, AS_IO, 8, sms_state )
|
||||
AM_IMPORT_FROM(sg1000m3_io)
|
||||
|
Loading…
Reference in New Issue
Block a user