/*******************************************************************************
 Judge Dredd

 by Steve Ellenoff (sellenoff@hotmail.com)
 Dec. 1, 2000

 Never played this game before, but it sounds really cool from the rulesheet! :)
 Much thanks goes to "ari 'apz' sovijärvi" <apz@nic.fi> for answering all my questions
 about the game, since he owns the machine!

 Known Issues-
 Well, I'm not sure if the arm and globe work 100% right, but they seem ok..
 Some timing issues maybe.. the diverter doesn't always send the ball to the planet on lock3!
 Drop Target issues.. not sure they are working 100% correctly.. need someone to confirm!

 If you want help on writing your own seem, see FH.C or PZ.C!

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

/*-------------------------------------------------------------------------------------------------
  Keys for Judge Dredd Simulator:
  ----------------------------
     2  	Buy-In
     E  	Super Game
 L.ALT  	Left FIRE Button
 SPACE  	Right FIRE Button
    +R		L/R Ramp
     R		Middle Ramp
    +I		L/R Inlane
     I  	Inner Right Inlane
    +-		L/R Slingshot
    +L		L/R Loop
    +O		L/R Outlane
     Q		SDTM (Drain Ball)
     A		Air Raid Ramp
     T  	Left Shooter Lane
     Y		Small Loop
     U		Sniper Tower
     H		Advance Crime 3 Bank Target
     S		Subway
     D		EB Left Target
     F		EB Right Target
     G		"?" Target
 ZXCVB		JUDGE Targets
     W		Captive Ball

-------------------------------------------------------------------------------------------------*/

#include "driver.h"
#include "core.h"
#include "wpc.h"
#include "sim.h"
#include "wmssnd.h"


static void init_jd(void);
static void jd_drawMech(BMTYPE **line);
static void jd_drawStatic(BMTYPE **line);
static int  jd_handleBallState(sim_tBallStatus *ball, int *inports);
static void jd_handleMech(int mech);
static int jd_getMech(int mechNo);
static int jd_getSol(int solNo);
static int jd_keyCond(int cond, int ballState, int *inports);
static char * DispDT(void);
static char * DispPlanet(void);
static char * DispClaw(void);
/*-----------------------
  local static variables
 ------------------------*/
static struct {
  int droptargetPos;     /* Drop Target Position */
  int armPos;		 /* Arm Position  */
  int globePos;		 /* Globe Position*/
  int jdtPos;		 /* "J"udge DT Position*/
  int udtPos;		 /* J"u"dge DT Position*/
  int ddtPos;		 /* Ju"d"ge DT Position*/
  int gdtPos;		 /* Jud"g"e DT Position*/
  int edtPos;		 /* Judg"e" DT Position*/
  } locals;

WPC_INPUT_PORTS_START(jd,6)
  PORT_START /* 0 */
    COREPORT_BIT(   0x0001,"Left Qualifier",  KEYCODE_LCONTROL)
    COREPORT_BIT(   0x0002,"Right Qualifier", KEYCODE_RCONTROL)
    COREPORT_BITIMP(0x0004,"L/R Ramp",        KEYCODE_R)
    COREPORT_BITIMP(0x0008,"L/R Outlane",     KEYCODE_O)
    COREPORT_BITIMP(0x0010,"L/R Loop",        KEYCODE_L)
    COREPORT_BIT(   0x0040,"L/R Slingshot",   KEYCODE_MINUS)
    COREPORT_BIT(   0x0080,"L/R Inlane",      KEYCODE_I)
    COREPORT_BIT(   0x0100,"Drain",		     KEYCODE_Q)
    COREPORT_BIT(   0x0200,"Left Fire",	     KEYCODE_LALT)
    COREPORT_BIT(   0x0400,"Buy In",		     KEYCODE_2)
    COREPORT_BIT(   0x0800,"Super Game",	     KEYCODE_E)
    COREPORT_BIT(   0x1000,"Air Rade Ramp",   KEYCODE_A)
    COREPORT_BIT(   0x2000,"L.Shooter",       KEYCODE_T)
    COREPORT_BIT(   0x4000,"Small Loop",      KEYCODE_Y)
    COREPORT_BIT(   0x8000,"Sniper Tower",    KEYCODE_U)

  PORT_START /* 1 */
    COREPORT_BIT(0x0001,"Subway",			 KEYCODE_S)
    COREPORT_BIT(0x0002,"Adv Crime DT",	     KEYCODE_H)
    COREPORT_BIT(0x0004,"EB Left DT",	     KEYCODE_D)
    COREPORT_BIT(0x0008,"EB Right DT",	     KEYCODE_F)
    COREPORT_BIT(0x0010,"'?' Target",	     KEYCODE_G)
    COREPORT_BIT(0x0020,"Captive Ball",	     KEYCODE_W)
    COREPORT_BIT(0x0040,"'J'udge",			 KEYCODE_Z)
    COREPORT_BIT(0x0080,"J'u'dge",			 KEYCODE_X)
    COREPORT_BIT(0x0100,"Ju'd'ge",			 KEYCODE_C)
    COREPORT_BIT(0x0200,"Jud'g'e",			 KEYCODE_V)
    COREPORT_BIT(0x0400,"Judg'e'",			 KEYCODE_B)
WPC_INPUT_PORTS_END

/*-------------------
/ Switch definitions
/--------------------*/
#define swLFire			11
#define swRFire			12
#define swStart			13
#define swTilt			14
#define swLShooter		15
#define swLOut			16
#define swLIn			17
#define sw3Bank			18		//3 Bank Target

#define swSlamTilt		21
#define swCoinDoor		22
#define swTicket		23
#define swAlwaysClosed	24
#define swTRPost		25		//Right EB Target
#define swCapBall1		26
#define swLLTarget		27		// Mystery '?' Target
/*28 Not used*/

#define swBuyIn			31
/*32 Not Used */
#define swTCRollOver	33		//Left Orbit Shot..
#define swIRIn			34
#define swSLoopC		35		//Small Loop Switch!
#define swLPost			36		//Left EB Target
#define swSubway		37
#define swSubway2		38

#define swRShooter		41
#define swROut			42
#define swRIn			43
#define swSuperGame		44
/*45 - 48 Not used */

#define swLSling		51
#define swRSling		52
#define swCapBall2		53
#define sw_Judge		54
#define swJ_udge		55
#define swJu_dge		56
#define swJud_ge		57
#define swJudg_e		58

#define swGlobe1		61		//?
#define swGlobeExit		62		//Fires when ball is dropped from Magnet!
#define swLRampToLock	63		//Switch towards planet!
#define swLRampExit		64
/*65 Not Used*/
#define swCRampExit		66
#define swLRampEnt		67
#define swCapBall3		68

#define swArmFR			71		//Magnet Over Ring - set when magnet ready to pick up ball!
#define swTROpto		72		//Right Orbit Shot
#define swLPopper		73		//Subway Popper
#define swRPopper		74		//Sniper Target
#define swTRRampExit	75		//Air Rade Ramp
#define swRRampExit		76
#define swGlobe2		77		//Planet - Indicates ball can be lifted!
/*78 Not used*/

#define swTrough6		81
#define swTrough5		82
#define swTrough4		83
#define swTrough3		84
#define swTrough2		85
#define swTrough1		86
#define swTroughTop		87
/*88 Not Used*/

/*---------------------
/ Solenoid definitions
/----------------------*/
#define sArmMagnet		1		//Keeps ball in arm
#define sLPopper		2		//Subway Popper
#define sRPopper		3		//Sniper Popper
#define sGlobeArm		4		//Arm Motor
#define sDropTarget		5		//Knock All Drop Targets Up!
#define sGlobeMotor		6		//Spins Planet
#define sKnocker		7
#define sRShooter		8
#define sLShooter		9
#define sTripDropTarget	10		//Pull "D" Drop Target Down
#define sDiverter		11		//Left Ramp Diverter to Planet
/*12 - Not Used*/
#define sTrough			13
/*14 - Not Used*/
#define sLSling			15
#define sRSling			16

/*Define fake solenoid to signal when ball should be droped from claw*/
#define sFakeSol1		CORE_CUSTSOLNO(1) /* 33 */

/*Define custom key condition*/
#define JD_DROPCOND 1

/*Drop Target Positions*/
#define DT_UP  0
#define DT_DOWN  1


enum {stTrough1=SIM_FIRSTSTATE, stTrough2, stTrough3, stTrough4, stTrough5, stTrough6, stTrough,
      stRShooter, stBallLane, stLShooter, stDrain, stLRampEnt,stRRampEnt, stCRampEnt, stLRampExit,
      stLOut, stROut, stLIn, stRIn, stLLoopUp, stLLoopDn, stRLoopUp, stRLoopDn,
      stIRIn, stSmallLoop, stSniper, stSniper2, stSubway, stSubway2, stSubway3, stSubway4,
      stARampEnt, stAHabit, stLRamp2, stPlanet, stPlanet2, stPlanet3,
      stEBLeft, stEBRight, stCaptiveBall, stCBall2, stCBall3, stMystery,
      st_Judge, stJ_udge, stJu_dge, stJud_ge, stJudg_e,
      st_Judge2, stJ_udge2, stJu_dge2, stJud_ge2, stJudg_e2
      };

static sim_tState jd_stateDef[] =  {
  {"Not Installed",		0,0,           0,        stDrain,     0,0,0,SIM_STNOTEXCL},
  {"Moving"},
  {"Playfield",			0,0,           0,        0,           0,0,0,SIM_STNOTEXCL},

  /*Line 1*/
  {"Trough 1",			1,swTrough1,	sTrough,	stRShooter,	1},
  {"Trough 2",			1,swTrough2,	0,			stTrough1,	1},
  {"Trough 3",			1,swTrough3,	0,			stTrough2,	1},
  {"Trough 4",			1,swTrough4,	0,			stTrough3,	1},
  {"Trough 5",			1,swTrough5,	0,			stTrough4,	1},
  {"Trough 6",			1,swTrough6,	0,			stTrough5,	1},
  {"Trough Up",			1,swTroughTop,	0,			stRShooter,	1},

  /*Line 2*/
  {"R.Shooter",			1,swRShooter,	sRShooter,	stBallLane,	1},
  {"Ball Lane",			1,0,			0,			stLLoopDn,	10},
  {"L. Shooter",		1,swLShooter,	sLShooter,	stJu_dge,	10}, //Assume it hits the Middle of the Judge targets everytime!
  {"Drain",				1,0,			0,			stTrough6,	0,0,0,SIM_STNOTEXCL},
  {"Left Ramp",			1,swLRampEnt,	0,			stLRampExit,5, sDiverter, stLRamp2},
  {"Right Ramp",		1,swRRampExit,	0,			stIRIn,		10},
  {"Center Ramp",		1,swCRampExit,	0,			stFree,		10},
  {"Left Ramp Exit",	1,swLRampExit,	0,			stRIn,		10},

  /*Line 3*/
  {"Left Outlane",		1,swLOut,		0,			stDrain,	10},
  {"Right Outlane",		1,swROut,		0,			stDrain,	10},
  {"Left  Inlane",		1,swLIn,		0,			stFree,		5},
  {"Right Inlane",		1,swRIn,		0,			stFree,		5},
  {"Left Orbit Loop",	1,swTCRollOver,	0,			stRLoopDn,	5}, /*Loop Going Up*/
  {"Left Orbit Loop",	1,swTCRollOver,	0,			stFree,		5}, /*Loop Coming Down*/
  {"Right Orbit Loop",	1,swTROpto,		0,			stLLoopDn,	5}, /*Loop Going Up*/
  {"Right Orbit Loop",	1,swTROpto,		0,			stFree,		5}, /*Loop Coming Down*/

  /*Line 4*/
  {"I. Right Inlane",	1,swIRIn,		0,			stFree,		5},
  {"Small Loop",		1,swSLoopC,		0,			stRLoopDn,	5},
  {"Sniper",			1,swRPopper,	sRPopper,	stSniper2,	1},
  {"Sniper Habitrail",	1,0,			0,			stLIn,		10},
  {"Subway",			1,swSubway,		0,			stSubway2,	5},
  {"Subway",			1,swSubway2,	0,			stSubway3,	5},
  {"Subway Popper",		1,swLPopper,	sLPopper,	stSubway4,	1},
  {"Subway Habitrail",	1,0,			0,			stFree,		10},

  /*Line 5*/
  {"Air Raid Ramp",		1,swTRRampExit,	0,			stAHabit,	3},
  {"Air Raid Habitrail",1,0,			0,			stLShooter,	15},
  {"Towards Planet",	1,swLRampToLock,0,			stPlanet,	5},
  {"Planet",			1,swGlobe1,		sArmMagnet,	stPlanet2,	5},	//Keep ball here, till Arm Magnet picks it up!
  {"In Claw",			1,0,			sFakeSol1,	stPlanet3,	1},
  {"Dropped",			1,swGlobeExit,	0,			stFree,		5},	//Dropped by Claw!

  /*Line 6*/
  {"EB Left Target",	1,swLPost,		0,			stFree,		5},
  {"EB Right Target",	1,swTRPost,		0,			stFree,		5},
  {"Captive Ball -",	1,swCapBall1,	0,			stCBall2,	5},
  {"Captive Ball /",	1,swCapBall2,	0,			stCBall3,	5},
  {"Captive Ball |",	1,swCapBall3,	0,			stFree,		5},
  {"'?' Target",		1,swLLTarget,	0,			stFree,		5},

  /*Line 7*/
  {"'J'udge Target",	1,0,			0,			0,			5},
  {"J'u'dge Target",	1,0,			0,			0,			5},
  {"Ju'd'ge Target",	1,0,			0,			0,			5},
  {"Jud'g'e Target",	1,0,			0,			0,			5},
  {"Judg'e' Target",	1,0,			0,			0,			5},

  /*Line 8*/
  {"'J'udge Target",	1,sw_Judge,		0,			stFree,		5, 0, 0, SIM_STSWKEEP},
  {"J'u'dge Target",	1,swJ_udge,		0,			stFree,		5, 0, 0, SIM_STSWKEEP},
  {"Ju'd'ge Target",	1,swJu_dge,		0,			stFree,		5, 0, 0, SIM_STSWKEEP},
  {"Jud'g'e Target",	1,swJud_ge,		0,			stFree,		5, 0, 0, SIM_STSWKEEP},
  {"Judg'e' Target",	1,swJudg_e,		0,			stFree,		5, 0, 0, SIM_STSWKEEP},

  {0}
};

static int  jd_handleBallState(sim_tBallStatus *ball, int *inports) {
  switch (ball->state)
	{
	case st_Judge:
		/*If "J" target is down, go to Immediately, no switch is triggered!*/
		if(locals.jdtPos == DT_UP)
			return setState(st_Judge2,5);
		else
			return setState(stFree,5);
		break;
	case stJ_udge:
		/*If "U" target is down, go to Immediately, no switch is triggered!*/
		if(locals.udtPos == DT_UP)
			return setState(stJ_udge2,5);
		else
			return setState(stFree,5);
		break;
	//*SPECIAL CASE*//
	case stJu_dge:
		/*If "D" target is down, go to subway, otherwise, stay free*/
		if(locals.ddtPos == DT_UP)
			return setState(stJu_dge2,5);
		else
			return setState(stSubway,5);
		break;
	case stJud_ge:
		/*If "J" target is down, go to Immediately, no switch is triggered!*/
		if(locals.gdtPos == DT_UP)
			return setState(stJud_ge2,5);
		else
			return setState(stFree,5);
		break;
	case stJudg_e:
		/*If "E" target is down, go to Immediately, no switch is triggered!*/
		if(locals.edtPos == DT_UP)
			return setState(stJudg_e2,5);
		else
			return setState(stFree,5);
		break;
	}
  return 0;
}

/* The Subway can only be reached if "D" drop target down! */
static int jd_keyCond(int cond, int ballState, int *inports) {
  switch (cond) {
    case JD_DROPCOND:
      /* ball on PF & bank down & drop up */
      return (ballState == stFree) && (locals.ddtPos == DT_DOWN);
  }
  return FALSE;
}

/*---------------------------
/  Keyboard conversion table
/----------------------------
--------------------------------------------------------------------------------------------------
  Layout of inportData array
   ----------------------------
   #1) Inport number
   #2) Mask for this switch (all bits must be set for switch to activate
       Only first match will be used. Placed qualified keys first
   #3) Switch to activate or new ball state
   #4) Condition for the action to occur
                 0                  : ball in stFree state
                 switch             : ball in stFree state and switch active
                 SIM_STANY       : ball can be in any state
                 SIM_CUSTCOND(n) : call custom condition handler (keyCond)
--------------------------------------------------------------------------------------------------*/

static sim_tInportData jd_inportData[] = {
  {0, 0x0005, stLRampEnt},
  {0, 0x0006, stRRampEnt},
  {0, 0x0004, stCRampEnt},
  {0, 0x0009, stLOut},
  {0, 0x000a, stROut},
  {0, 0x0011, stLLoopUp},
  {0, 0x0012, stRLoopUp},
  {0, 0x0041, swLSling},
  {0, 0x0042, swRSling},
  {0, 0x0081, stLIn},
  {0, 0x0082, stRIn},
  {0, 0x0100, stDrain},
  {0, 0x0200, swLFire, SIM_STANY},
  {0, 0x0400, swBuyIn, SIM_STANY},
  {0, 0x0800, swSuperGame, SIM_STANY},
  {0, 0x1000, stARampEnt},
  {0, 0x2000, stLShooter},
  {0, 0x4000, stSmallLoop},
  {0, 0x8000, stSniper},

  {1, 0x0001, stSubway,SIM_CUSTCOND(JD_DROPCOND)},
  {1, 0x0002, sw3Bank},
  {1, 0x0004, stEBLeft},
  {1, 0x0008, stEBRight},
  {1, 0x0010, stMystery},
  {1, 0x0020, stCaptiveBall},
  {1, 0x0040, st_Judge},
  {1, 0x0080, stJ_udge},
  {1, 0x0100, stJu_dge},
  {1, 0x0200, stJud_ge},
  {1, 0x0400, stJudg_e},
  {0}
};

/*--------------------
  Drawing information
  --------------------*/
  static void jd_drawMech(BMTYPE **line) {
  core_textOutf(30,  0,BLACK,"Claw:%-25s",DispClaw());
  core_textOutf(30, 10,BLACK,"Planet:%-14s",DispPlanet());
  core_textOutf(30, 20,BLACK,"Drop Targets:%-5s",DispDT());
  }
  /* Help */
  static void jd_drawStatic(BMTYPE **line) {
  core_textOutf(30, 30, BLACK,"Help on this Simulator:");
  core_textOutf(30, 40, BLACK,"2/E=Buy-In,Super Game");
  core_textOutf(30, 50,BLACK,"L.Alt/Space=L/R FIRE");
  core_textOutf(30, 60,BLACK,"L/R Ctrl+- =L/R Sling");
  core_textOutf(30, 70,BLACK,"L/R Ctrl+I/O = L/R Inlane/Outlane");
  core_textOutf(30, 80,BLACK,"L/R Ctrl+R,R = L/R/C Ramps");
  core_textOutf(30, 90,BLACK,"L/R Ctrl+L = L/R Orbit Loops");
  core_textOutf(30, 100,BLACK,"Q = Drain Ball, I = Inner R.Inlane");
  core_textOutf(30, 110,BLACK,"A = Air Raid Ramp, S = Subway");
  core_textOutf(30, 120,BLACK,"T = L.Shooter Lane, Y = Small Loop");
  core_textOutf(30, 130,BLACK,"H = Avd Crim DT, U = Sniper Tower");
  core_textOutf(30, 140,BLACK,"D/F = Extra Ball L/R Target");
  core_textOutf(30, 150,BLACK,"G = '?' Target, W = Captive Ball");
  core_textOutf(30, 160,BLACK,"Z/X/C/V/B = JUDGE Targets");
  }

/*-----------------
/  ROM definitions
/------------------*/
#define JD_SOUND_L1 \
DCS_SOUNDROM8x( "jdsnd_u2.bin",CRC(d8f453c6) SHA1(5dd677fde46436dbf2d2e9058f06dd3048600234), \
                "jdsnd_u3.bin",CRC(0a11f673) SHA1(ab556477a25e3493555b8a281ca86677caec8947), \
                "jdsnd_u4.bin",CRC(93f6ebc1) SHA1(5cb306afa693e60887069745588dfd5b930c5951), \
                "jdsnd_u5.bin",CRC(c9f28ba6) SHA1(8447372428e3b9fc86a98286c05f95a13abe26b0), \
                "jdsnd_u6.bin",CRC(ef0bf094) SHA1(c0860cecd436d352fe2c2208533ff6dc71bfced1), \
                "jdsnd_u7.bin",CRC(aebab88b) SHA1(d3f1be60a6840d9d085e22b43aafea1354771980), \
                "jdsnd_u8.bin",CRC(77604893) SHA1(a9a4a66412096edd88ee7adfd960eef6f5d16476), \
                "jdsnd_u9.bin",CRC(885b7c70) SHA1(be3bb42aeda3020a72c527f52c5330d0bafa9966))

/*
These are the L3 sound ROMs for Judge Dredd that are installed at U2 and U3. If you are running L2 game code or greater and do not have a locking ring in Deadworld, this is the matching sound ROM set.
In the 8 chip sound ROM set for JD, the only ROMs that are different between L1 and L3 sound versions are U2 and U3. If you have EPROMS/masked ROMs in U4-U8 that are labeled L3, they are identical to the L1 version. The L1, L6 & L7 PinMAME ROM sets all contain identical L1 sound ROM images. In addition, U5 and U9 on the Planetary Pinball site are the same as what is found in the other L1 sets.
The difference between the L1 and L3 sound ROMs is the callout used with Deadworld. L1 is used with Deadworld as originally designed. When Deadworld is active, the callout will be "Dimensional lock # is lit." L3 is used with the production Deadworld that virtually locks the balls and only diverts ball 3 to Deadworld. When Deadworld is active in this version the callout will be "Dimensional phase # is lit."
*/
#define JD_SOUND_L3 \
DCS_SOUNDROM8x( "jdsu2_l3.bin",CRC(7a59ec18) SHA1(ee073d4bea198fd66de3508f67061b7d19f12edc), \
                "jdsu3_l3.bin",CRC(42f52faa) SHA1(3fac9d3ddfe21877929eaa4cb7101a690745b163), \
                "jdsnd_u4.bin",CRC(93f6ebc1) SHA1(5cb306afa693e60887069745588dfd5b930c5951), \
                "jdsnd_u5.bin",CRC(c9f28ba6) SHA1(8447372428e3b9fc86a98286c05f95a13abe26b0), \
                "jdsnd_u6.bin",CRC(ef0bf094) SHA1(c0860cecd436d352fe2c2208533ff6dc71bfced1), \
                "jdsnd_u7.bin",CRC(aebab88b) SHA1(d3f1be60a6840d9d085e22b43aafea1354771980), \
                "jdsnd_u8.bin",CRC(77604893) SHA1(a9a4a66412096edd88ee7adfd960eef6f5d16476), \
                "jdsnd_u9.bin",CRC(885b7c70) SHA1(be3bb42aeda3020a72c527f52c5330d0bafa9966))

WPC_ROMSTART(jd,l7,"jdrd_l7.rom",0x80000,CRC(87b2a5c3) SHA1(e487e9ff78353ee96d5fb5f036b1a6cef586f5b4)) JD_SOUND_L3 WPC_ROMEND
WPC_ROMSTART(jd,d7,"jdrd_d7.rom",0x80000,CRC(75d71d08) SHA1(10e63b8eb57a800fe0eeb89b175d01576d79ee1a)) JD_SOUND_L3 WPC_ROMEND
WPC_ROMSTART(jd,l1,"jd_l1.u6",   0x80000,CRC(09a4b1d8) SHA1(9f941bbeb6e58d918d374694c7ff2a67f1084cc0)) JD_SOUND_L1 WPC_ROMEND
WPC_ROMSTART(jd,d1,"jd_d1.u6",   0x80000,CRC(307fdfa0) SHA1(0ad083cf1e35334caa0854375406e06672bf587d)) JD_SOUND_L1 WPC_ROMEND
WPC_ROMSTART(jd,l1at,"jd_l1at.u6",0x80000,CRC(7af2ca76) SHA1(67c5241d6080e4c2bd81aefc61a1220e4c49d25b)) JD_SOUND_L1 WPC_ROMEND
//older: WPC_ROMSTART(jd,l1d,"jd_l1d.u6", 0x80000,CRC(ad0352de) SHA1(b099437d0c91094e0d259af02f470cce3e866b9d)) JD_SOUND_L1 WPC_ROMEND
WPC_ROMSTART(jd,l1d,"jd_l1d.u6", 0x80000,CRC(c37d8fed) SHA1(05d85c9c6a59866de4a7a5bb2258b69a1964efa3)) JD_SOUND_L1 WPC_ROMEND
WPC_ROMSTART(jd,l4,"jd_l4.u6",   0x80000,CRC(cc6f1068) SHA1(aef2a2eeb9110074eebff91318179ce97aba14ba)) JD_SOUND_L3 WPC_ROMEND
WPC_ROMSTART(jd,d4,"jd_d4.u6",   0x80000,CRC(4b7b350f) SHA1(5c827532ffa1e3b102cc6e2ec9446f2d1fc2ef84)) JD_SOUND_L3 WPC_ROMEND
WPC_ROMSTART(jd,l5,"jd_l5.u6",   0x80000,CRC(879b091e) SHA1(eaf1c86c0e72e8cdfa9ac942fc54ef4f70a65175)) JD_SOUND_L3 WPC_ROMEND
WPC_ROMSTART(jd,d5,"jd_d5.u6",   0x80000,CRC(4a04b45a) SHA1(84d20fa3beff412862e07a7092407159cc0567b5)) JD_SOUND_L3 WPC_ROMEND
WPC_ROMSTART(jd,l6,"jd_l6.u6",   0x80000,CRC(0a74cba4) SHA1(1872fd86bbfa772eac9cc2ef2634a90b72b3d5e2)) JD_SOUND_L3 WPC_ROMEND
WPC_ROMSTART(jd,d6,"jd_d6.u6",   0x80000,CRC(fa17dd22) SHA1(e71c9c0f504a793d4e9c76aaad85f71c4e41a15e)) JD_SOUND_L3 WPC_ROMEND

/*--------------
/  Game drivers
/---------------*/
CORE_GAMEDEF(jd,l7,"Judge Dredd (L-7)",1993,"Bally",wpc_mDCSS,0)
CORE_CLONEDEF(jd,d7,l7,"Judge Dredd (D-7 LED Ghost Fix)",1993,"Bally",wpc_mDCSS,0)
CORE_CLONEDEF(jd,l1,l7,"Judge Dredd (L-1)",1993,"Bally",wpc_mDCSS,0)
CORE_CLONEDEF(jd,d1,l7,"Judge Dredd (D-1 LED Ghost Fix)",1993,"Bally",wpc_mDCSS,0)
CORE_CLONEDEF(jd,l1at,l7,"Judge Dredd (L-1AT MOD)",1993,"Bally",wpc_mDCSS,0) // additional MOD for the aftermarket Deadworld HW-MOD
CORE_CLONEDEF(jd,l1d,l7,"Judge Dredd (L-1D MOD)",1993,"Bally",wpc_mDCSS,0) // MOD of L-1AT by KoP
CORE_CLONEDEF(jd,l4,l7,"Judge Dredd (L-4)",1993,"Bally",wpc_mDCSS,0)
CORE_CLONEDEF(jd,d4,l7,"Judge Dredd (D-4 LED Ghost Fix)",1993,"Bally",wpc_mDCSS,0)
CORE_CLONEDEF(jd,l5,l7,"Judge Dredd (L-5)",1993,"Bally",wpc_mDCSS,0)
CORE_CLONEDEF(jd,d5,l7,"Judge Dredd (D-5 LED Ghost Fix)",1993,"Bally",wpc_mDCSS,0)
CORE_CLONEDEF(jd,l6,l7,"Judge Dredd (L-6)",1993,"Bally",wpc_mDCSS,0)
CORE_CLONEDEF(jd,d6,l7,"Judge Dredd (D-6 LED Ghost Fix)",1993,"Bally",wpc_mDCSS,0)

/*-----------------------
/ Simulation Definitions
/-----------------------*/
static sim_tSimData jdSimData = {
  2,						/* 2 game specific input ports */
  jd_stateDef,				/* Definition of all states */
  jd_inportData,			/* Keyboard Entries */
  { stTrough1, stTrough2, stTrough3, stTrough4, stTrough5, stTrough6, stDrain },
  NULL,						/* no init */
  jd_handleBallState,		/*Function to handle ball state changes*/
  jd_drawStatic,			/*Function to handle mechanical state changes*/
  FALSE,					/* Do not simulate manual shooter */
  jd_keyCond				/* advanced key conditions */
};

/*----------------------
/ Game Data Information
/----------------------*/
static core_tGameData jdGameData = {
  GEN_WPCDCS, wpc_dispDMD,
  {
    FLIP_SW(FLIP_L | FLIP_U) | FLIP_SOL(FLIP_L | FLIP_U),
    0,0,1,0,0,0,0,
    jd_getSol, jd_handleMech, jd_getMech, jd_drawMech,
    NULL, NULL
  },
  &jdSimData,
  {
    {0}, /* sNO */
    /*Coin    1     2     3     4     5     6     7     8     9    10   Cab.  Cust */
    { 0x00, 0x00, 0x00, 0x02, 0x00, 0xf8, 0x6e, 0x3e, 0x7f, 0x00, 0x00, 0x00 },
    /*Start    Tilt    SlamTilt    CoinDoor    Shooter */
    { swStart, swTilt, swSlamTilt, swCoinDoor, swRFire},
  }
};


/*---------------
/  Game handling
/----------------*/
static void init_jd(void){
  core_gameData = &jdGameData;
}

/*-- return status of custom solenoids --*/
static int jd_getSol(int solNo) {
 /* Arm Magnet Must be Off for solenoid to fire! */
 if (solNo == sFakeSol1)
  return (core_getSol(sArmMagnet)==0);
 return 0;
}

static void jd_handleMech(int mech)
{
  /*Spin Globe*/
  if (mech & 0x01) {
    if (core_getSol(sGlobeMotor))
      locals.globePos++;
    if (locals.globePos>100)
      locals.globePos=0;
    /*Ball ok to lift switch set when in desired position*/
    core_setSw(swGlobe2,(locals.globePos>=0 && locals.globePos<=10));
  }

  /*Move Arm*/
  if (mech & 0x02) {
    if (core_getSol(sGlobeArm))
      locals.armPos++;
    if (locals.armPos>100)
      locals.armPos=0;
    /*ARM FAR RIGHT is set when at desired position*/
    core_setSw(swArmFR,(locals.armPos>=0 && locals.armPos<=10));
  }

  /*Handle Drop Targets*/
  /*WPCMAME: I don't get this. Why do we need all this drop target handling? */
  //Drop Target Solenoid Raises ALL 5 DTS*/
  if (mech & 0x04) {
    if (core_getSol(sDropTarget))
      locals.jdtPos = locals.udtPos = locals.ddtPos = locals.gdtPos = locals.edtPos = DT_UP;
    else {
      /*Switch hit pops the target down!*/
      if (locals.jdtPos == DT_UP && core_getSw(sw_Judge))
     	locals.jdtPos = DT_DOWN;
      if (locals.udtPos == DT_UP && core_getSw(swJ_udge))
     	locals.udtPos = DT_DOWN;
      if (locals.ddtPos == DT_UP && core_getSw(swJu_dge))
     	locals.ddtPos = DT_DOWN;
      if (locals.gdtPos == DT_UP && core_getSw(swJud_ge))
     	locals.gdtPos = DT_DOWN;
      if (locals.edtPos == DT_UP && core_getSw(swJudg_e))
     	locals.edtPos = DT_DOWN;
    }
    /*If TripDrop Pull D Back Down! */
    if (core_getSol(sTripDropTarget))
      locals.ddtPos = DT_DOWN;

    /*All drop target switches must be on, while target is down!*/
    core_setSw(sw_Judge,locals.jdtPos == DT_DOWN);
    core_setSw(swJ_udge,locals.udtPos == DT_DOWN);
    core_setSw(swJu_dge,locals.ddtPos == DT_DOWN);
    core_setSw(swJud_ge,locals.gdtPos == DT_DOWN);
    core_setSw(swJudg_e,locals.edtPos == DT_DOWN);
  }
}
static int jd_getMech(int mechNo) {
  if (mechNo == 0) return locals.globePos;
  if (mechNo == 1) return locals.armPos;
  return 0;
}
static char * DispDT()
{
static char buf[100];
sprintf(buf,"%c%c%c%c%c",
		     (locals.jdtPos==DT_UP)?'J':'_',
		     (locals.udtPos==DT_UP)?'U':'_',
		     (locals.ddtPos==DT_UP)?'D':'_',
		     (locals.gdtPos==DT_UP)?'G':'_',
		     (locals.edtPos==DT_UP)?'E':'_'
       );
return buf;
}

static char * DispPlanet()
{
static char buf[100];
sprintf(buf,"%s%-3s",(core_getSol(sGlobeMotor))?"Spinning":"Not Moving",
		   ((locals.globePos>=0 && locals.globePos<=10))?"(*)":"   "
       );
return buf;
}

static char * DispClaw()
{
static char buf[100];
sprintf(buf,"%s%-13s",(core_getSol(sGlobeArm))?"Moving":"Not Moving",
		   ((locals.armPos>=0 && locals.armPos<=10))?"(Over Planet)":"(Over PF)"
       );
return buf;
}
