summaryrefslogblamecommitdiffstatshomepage
path: root/src/mame/drivers/mbdtower.cpp
blob: 5d756cefe639dd2ba74943eafc57b5c795aef8b3 (plain) (tree)
1
2
3
4
5
6
7
8
9



                                                                            
                                                                              
 
                           
                                                                            
                                                
                                    
                                                     
 


                                                                          
                                            
 


                                                                             









                                                                            
                                                                                        


                                                    
                               









                                                                   



                                        
          
                                              




                                                                            
                


                                                                            
                                      
 
                                                      
                               
                                     
 
















                                                                       
 





                                                                
 

                                                                     
                                                             











                                                                                      
 

                                            
                                                                                   
 
                                               
 
                                                                                            
 


                                                                                               


                                                    
                                                         
 
                                       

 







                                                                            



                                       
 

                                 
                                                              


                                  
                  
                                                                          

                                  
                   
                          
 
                           
                                                        






                                       
                          

 

                                    

                                
                                                                               


 











                                                                            
 

                                   
 


                                       
 




































                                                                                                        
                   


                              
                           
                               
 
                                  


                                                               
                                    
                                        

 


                                                       
                                                                                         



                                                                 
                                                                                                                                                    


                                                                                                                   







                                                   










                                                                                                          
                                                                                                                     
                                            
                                                                                                                       


       
                                                                                                                                                                                           
// license:BSD-3-Clause
// copyright-holders:hap, Sean Riddle
/***************************************************************************

  ** subclass of hh_tms1k_state (includes/hh_tms1k.h, drivers/hh_tms1k.cpp) **

  Milton Bradley Dark Tower
  * TMS1400NLL MP7332-N1.U1(Rev. B) or MP7332-N2LL(Rev. C), die label MP7332
    (assume same ROM contents between revisions)
  * SN75494N MOS-to-LED digit driver
  * motorized rotating reel + lightsensor, 1bit-sound

  This is a board game, it obviously requires game pieces and the board.
  The emulated part is the centerpiece, a black tower with a rotating card
  panel and LED digits for displaying health, amount of gold, etc. As far
  as MAME is concerned, the game works fine.

  To start up the game, first press [MOVE], the machine now does a self-test.
  Then select level and number of players and the game will start. Read the
  official manual on how to play the game.

***************************************************************************/

#include "includes/hh_tms1k.h"
#include "mbdtower.lh"


class mbdtower_state : public hh_tms1k_state
{
public:
	mbdtower_state(const machine_config &mconfig, device_type type, const char *tag)
		: hh_tms1k_state(mconfig, type, tag)
	{ }

	void prepare_display();
	bool sensor_led_on() { return m_display_decay[0][0] != 0; }

	int m_motor_pos;
	int m_motor_pos_prev;
	int m_motor_decay;
	bool m_motor_on;
	bool m_sensor_blind;

	TIMER_DEVICE_CALLBACK_MEMBER(motor_sim_tick);

	DECLARE_WRITE16_MEMBER(write_r);
	DECLARE_WRITE16_MEMBER(write_o);
	DECLARE_READ8_MEMBER(read_k);

protected:
	virtual void machine_start() override;
};


/***************************************************************************

  Display, Motor

***************************************************************************/

void mbdtower_state::prepare_display()
{
	// declare display matrix size and the 2 7segs
	set_display_size(7, 3);
	set_display_segmask(6, 0x7f);

	// update current state
	if (~m_r & 0x10)
	{
		UINT8 o = BITSWAP8(m_o,7,0,4,3,2,1,6,5) & 0x7f;
		m_display_state[2] = (m_o & 0x80) ? o : 0;
		m_display_state[1] = (m_o & 0x80) ? 0 : o;
		m_display_state[0] = (m_r >> 8 & 1) | (m_r >> 4 & 0xe);

		display_update();
	}
	else
	{
		// display items turned off
		display_matrix(7, 3, 0, 0);
	}
}


TIMER_DEVICE_CALLBACK_MEMBER(mbdtower_state::motor_sim_tick)
{
	// it rotates counter-clockwise (when viewed from above)
	if (m_motor_on)
	{
		m_motor_pos = (m_motor_pos - 1) & 0x7f;

		// give it some time to spin out when it's turned off
		if (m_r & 0x200)
			m_motor_decay += (m_motor_decay < 4);
		else if (m_motor_decay > 0)
			m_motor_decay--;
		else
			m_motor_on = false;
	}

	// 8 evenly spaced holes in the rotation disc for the sensor to 'see' through.
	// The first hole is much bigger, enabling the game to determine the position.
	if ((m_motor_pos & 0xf) < 4 || m_motor_pos < 0xc)
		m_sensor_blind = false;
	else
		m_sensor_blind = true;

	// on change, output info
	if (m_motor_pos != m_motor_pos_prev)
		output().set_value("motor_pos", 100 * (m_motor_pos / (float)0x80));

	/* 3 display cards per hole, like this:

	    (0)                <---- display increments this way <----                   (7)

	    CURSED   VICTORY    WIZARD         DRAGON    GOLD KEY     SCOUT    WARRIOR   (void)
	    LOST     WARRIORS   BAZAAR CLOSED  SWORD     SILVER KEY   HEALER   FOOD      (void)
	    PLAGUE   BRIGANDS   KEY MISSING    PEGASUS   BRASS KEY    GOLD     BEAST     (void)
	*/
	int card_pos = m_motor_pos >> 4 & 7;
	if (card_pos != (m_motor_pos_prev >> 4 & 7))
		output().set_value("card_pos", card_pos);

	m_motor_pos_prev = m_motor_pos;
}



/***************************************************************************

  I/O

***************************************************************************/

WRITE16_MEMBER(mbdtower_state::write_r)
{
	// R0-R2: input mux
	m_inp_mux = data & 7;

	// R9: motor on
	if ((m_r ^ data) & 0x200)
		output().set_value("motor_on", data >> 9 & 1);
	if (data & 0x200)
		m_motor_on = true;

	// R3: N/C
	// R4: 75494 /EN (speaker, lamps, digit select go through that IC)
	// R5-R7: tower lamps
	// R8: rotation sensor led
	m_r = data;
	prepare_display();

	// R10: speaker out
	m_speaker->level_w(~data >> 4 & data >> 10 & 1);
}

WRITE16_MEMBER(mbdtower_state::write_o)
{
	// O0-O6: led segments A-G
	// O7: digit select
	m_o = data;
	prepare_display();
}

READ8_MEMBER(mbdtower_state::read_k)
{
	// K: multiplexed inputs
	// K8: rotation sensor
	return read_inputs(3) | ((!m_sensor_blind && sensor_led_on()) ? 8 : 0);
}



/***************************************************************************

  Inputs

***************************************************************************/

/* physical button layout and labels is like this:

    (green)     (l.blue)    (red)
    [YES/       [REPEAT]    [NO/
     BUY]                    END]

    (yellow)    (blue)      (white)
    [HAGGLE]    [BAZAAR]    [CLEAR]

    (blue)      (blue)      (blue)
    [TOMB/      [MOVE]      [SANCTUARY/
     RUIN]                   CITADEL]

    (orange)    (blue)      (d.yellow)
    [DARK       [FRONTIER]  [INVENTORY]
     TOWER]
*/

static INPUT_PORTS_START( mbdtower )
	PORT_START("IN.0") // R0
	PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_C) PORT_NAME("Inventory")
	PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_3) PORT_NAME("No/End")
	PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_E) PORT_NAME("Clear")
	PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_D) PORT_NAME("Sanctuary/Citadel")

	PORT_START("IN.1") // R1
	PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_X) PORT_NAME("Frontier")
	PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_2) PORT_NAME("Repeat")
	PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_W) PORT_NAME("Bazaar")
	PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_S) PORT_NAME("Move")

	PORT_START("IN.2") // R2
	PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_Z) PORT_NAME("Dark Tower")
	PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_1) PORT_NAME("Yes/Buy")
	PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_Q) PORT_NAME("Haggle")
	PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_A) PORT_NAME("Tomb/Ruin")
INPUT_PORTS_END



/***************************************************************************

  Machine Config

***************************************************************************/

void mbdtower_state::machine_start()
{
	hh_tms1k_state::machine_start();

	// zerofill
	m_motor_pos = 0;
	m_motor_pos_prev = -1;
	m_motor_decay = 0;
	m_motor_on = false;
	m_sensor_blind = false;

	// register for savestates
	save_item(NAME(m_motor_pos));
	/* save_item(NAME(m_motor_pos_prev)); */ // don't save!
	save_item(NAME(m_motor_decay));
	save_item(NAME(m_motor_on));
	save_item(NAME(m_sensor_blind));
}

static MACHINE_CONFIG_START( mbdtower, mbdtower_state )

	/* basic machine hardware */
	MCFG_CPU_ADD("maincpu", TMS1400, 425000) // approximation - RC osc. R=43K, C=56pf
	MCFG_TMS1XXX_READ_K_CB(READ8(mbdtower_state, read_k))
	MCFG_TMS1XXX_WRITE_R_CB(WRITE16(mbdtower_state, write_r))
	MCFG_TMS1XXX_WRITE_O_CB(WRITE16(mbdtower_state, write_o))

	MCFG_TIMER_DRIVER_ADD_PERIODIC("tower_motor", mbdtower_state, motor_sim_tick, attotime::from_msec(3500/0x80)) // ~3.5sec for a full rotation
	MCFG_TIMER_DRIVER_ADD_PERIODIC("display_decay", hh_tms1k_state, display_decay_tick, attotime::from_msec(1))
	MCFG_DEFAULT_LAYOUT(layout_mbdtower)

	/* sound hardware */
	MCFG_SPEAKER_STANDARD_MONO("mono")
	MCFG_SOUND_ADD("speaker", SPEAKER_SOUND, 0)
	MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.25)
MACHINE_CONFIG_END



/***************************************************************************

  Game driver(s)

***************************************************************************/

ROM_START( mbdtower )
	ROM_REGION( 0x1000, "maincpu", 0 )
	ROM_LOAD( "mp7332", 0x0000, 0x1000, CRC(ebeab91a) SHA1(7edbff437da371390fa8f28b3d183f833eaa9be9) )

	ROM_REGION( 867, "maincpu:mpla", 0 )
	ROM_LOAD( "tms1100_common1_micro.pla", 0, 867, CRC(62445fc9) SHA1(d6297f2a4bc7a870b76cc498d19dbb0ce7d69fec) )
	ROM_REGION( 557, "maincpu:opla", 0 )
	ROM_LOAD( "tms1400_mbdtower_output.pla", 0, 557, CRC(64c84697) SHA1(72ce6d24cedf9c606f1742cd5620f75907246e87) )
ROM_END


CONS( 1981, mbdtower, 0, 0, mbdtower, mbdtower, driver_device, 0, "Milton Bradley", "Dark Tower (Milton Bradley)", MACHINE_SUPPORTS_SAVE | MACHINE_CLICKABLE_ARTWORK | MACHINE_MECHANICAL )