rem ----------------------------------------------------
rem
rem                 BlackKnight 2000
rem         (C) 1989 Williams Electronics Inc
rem     Original design & concept: Steve Ritchie
rem           Original software: Ed Boon
rem
rem  Ported to Visual Pinball by Chris Leathley (black)
rem         Release: Beta 5 (22 December 2001)
rem       Script: Version 5.0 (22 December 2001)
rem
rem      This table cannot be modified without the
rem        express permission of Chris Leathley
rem           this includes so called 'mods'
rem
rem       Display & High Score Functions also by
rem       Chris Leathley and can be used in other
rem       tables providing credit is given
rem
rem       Thanks to 'Dorsola' for the magnet script
rem  and many thanks to 'Marcel Gonzalez' for the sounds
rem
rem  Commendations to PE#668 for his excellent conversion
rem  of the Original Black Knight and to AJ for his the
rem  great vpinMame port of Black Knight 2000.
rem
rem ----------------------------------------------------

Option Explicit             ' Force explicit variable declaration.

' include function from the Black Display Driver
ExecuteGlobal CreateObject("Scripting.FileSystemObject").OpenTextFile("BlackDisplayDriver_v2_bk.vbs", 1).ReadAll

' define any constants
Const constBallsPerGame = 3 ' number of balls per game

Dim LastKeyCode

' define global variables
Dim Score                   ' dah
Dim Bonus
Dim BonusMultiplier
Dim BallsRemaining          ' balls remaining to play (inclusive)
Dim BallsInGame             ' number of balls on playfield (multiball exclusive)
Dim BallsInLock             ' number of balls in multi-ball lock
Dim ExtraBallsAwards        ' number of EB's out-standing
Dim HurryUpBonus            ' bonus for completing hurry up
Dim LoopsThisBall
Dim UTurnsThisBall
Dim MaxLoopsThisGame

' define game flags
Dim bGameInPlay             ' game started flag
Dim bMultiBallMode          ' in 3 ball multiball
Dim bChallengeMode          ' in 2 ball (knight challenge) multiball
Dim bRansomGoSickMode       ' in ransom mode (20 seconds of complete mayhem ;-)
Dim bKickbackAvail          ' is the kickback avail
Dim bMagnaSaveAvail         ' is magna-save available
Dim bTilted                 ' game not tilted
Dim bChallengeSpinEject     ' eject the ball from the spin lane in challenge mode and not the challenge lane
Dim bJackpotWonThisGame     ' has the jackpot already been won this game
Dim bBallInPlungerLane      ' is there a ball in the plunger lane
Dim bBallInChallengeKicker  ' is there a ball in the knights challenge kicker
Dim bDoBonusNewBall         '

' define game control variables
Dim LastSwitchHit           ' id of last switch hit
Dim BlackValue              ' number of black lights lit
Dim KnightValue             ' number of Knight Targets down
Dim UTurnValue              ' bonus for doing a u-turn
Dim LightningWheelAward     ' lightning wheel light/bonus to award (0 - 15)
Dim UTurnSuccessiveLoops    ' Successive U-Turns (must not touch any other switch/target
Dim LoopSuccessiveLoops     ' Successive Loops (top playfield) (must not touch any other switch/target)
Dim RansomLettersLit        ' number of RANSOM letters lit on backboard
Dim WheelSlowDownSpeed
Dim WheelSlowDownSpeedLog
Dim WheelLightThatIsLit
Dim HurryUpBonusLevel       ' next hurry-up bonus award
Dim LoopsForExtraBall       ' successive loops to light extra ball
Dim HurryUpTime
Dim RansomRemainingMs       ' # of milli-seconds remaining in RANSOM

' define light arrays (easy access to lots of lights)
dim LightningWheelLights(16)
dim	BonusLights(4)
dim	BlackLights(5)
dim	KnightLights(6)
dim	WinLights(3)
dim	WarLights(3)
dim	DrawBridgeLights(3)
dim	DarkLights(7)

' define points array for lightning wheel
dim LightningWheelPoints(16)
dim LightningWheelText(16)

' any attract mode / misc variables
Dim LastWheelAttractMode
Dim CurrentMusicPlaying
Dim MagnaSaveMagnet

' and define the game play parameters (would be saved
' in battery backed up ram in a real pinball
dim BallsPerGame
dim	gpMagnaSaveOnTimer
dim	gpMagnaSaveAtStart
dim	gpWarMemory
dim	gpFreeSpins
dim	gpRansomSpotFrequency
dim	gpMultiballSpotFrequency
dim	gpMultiballDifficulty
dim	gpPercentSpecial
dim	gpLoopChampAward
dim	gpExtraBallTimer
dim	gpUTurnTimer
dim	gpKnightTargetTime
dim	gpRansomTimer
dim	gpLowerLockTimer
dim	gpJackpotTimer
dim	gpRansomBoltTimer
dim	gpJackpotAdvance
dim gpReplayStart
dim gpTiltWarnings
dim gpFreePlay

' my own local game values
dim gvTimerSpeedSlice
dim	gvKickbackSafeTime
dim	gvWheelSpinLitTimer
dim	gvWheelSpinTimerStart
dim	gvWheelSpinTimerEnd
dim gvHurryUpTimer
dim gvHurryUpStaticTimer
dim gvTiltLevel
dim gpTiltWarningsGiven
dim gvReplayAwarded

' The game stats/scores (get written to disk)
dim gsHighScore1			' top high score
dim gsHighScore1Name
dim gsHighScore2			' second
dim gsHighScore2Name
dim gsHighScore3			' third
dim gsHighScore3Name
dim gsHighScore4			' and fourth
dim gsHighScore4Name
dim gsLoopChamp				' loop champ
dim gsLoopChampName
dim gsRansomLettersLit		' number of RANSOM letters lit on backboard
dim gsJackpot         ' value of jackpot
dim	gsGamesPlayed



rem --------------------------------------------------
rem
rem 					Start of Script
rem
rem --------------------------------------------------

rem This function gets call once when the main table gets
rem created. it will set up all the light arrays and ensure that any flags
rem are set for attract mode (no auto start of game)
rem
Sub Table_Init()
	' seed the randomiser (rnd(1) function)
	Randomize

  ' display the script version
  TextBoxBeta.Text = "BETA 5"
  TextBoxVersion.Text = "Script v5.0"

	' create a hidden ball to stop any attract mode speedups/slowdowns due
	' to a current bug in VP where is does wierd things when there is no ball
	' on the table
	KickerFudge.CreateBall

	' set up game stats if battery backed up ram is corrupt
	gsHighScore1		= 5000000		' top high score
	gsHighScore1Name	= "BLK"
	gsHighScore2		= 4500000		' second
  gsHighScore2Name  = "RLD"
	gsHighScore3		= 4000000		' third
	gsHighScore3Name	= "ILA"
	gsHighScore4		= 3500000		' and fourth
  gsHighScore4Name  = "ROD"
	gsLoopChamp			= 4				' loop champ
	gsLoopChampName		= "BLK"
	gsRansomLettersLit	= 0				' number of RANSOM letters lit on backboard
	gsJackpot			= 1000000		' jackpot starts at 1M
	gsGamesPlayed		= 0

	' load the game stats from disk (will over write the above game stats if the file exists
  LoadGameStats()
' gsRansomLettersLit	= 3				' number of RANSOM letters lit on backboard
	' update the ransom letters on the backboard
	DrawBackboardRansom()
  ' set the game counter to the number games played
  GameCounterReel.SetValue(gsGamesPlayed)

  ' initalise the display driver (20ms update)
  DisplayInit 20,5,2
  ' and the high score entry
  hsbModeActive = False

	' set up the game parameters which are stored in battery backed up ram
	' These are the 'Factory Default Values'
	gpReplayStart			= 2500000	' (02)
  BallsPerGame      = constBallsPerGame     ' (09) number of balls per game
  gpTiltWarnings      = 2     ' (10)
	gpFreePlay				= True
	gpMagnaSaveOnTimer		= 5000		' (31) MagnaSave On Duration
	gpMagnaSaveAtStart  	= True		' (32) MagnaSave enabled at start
	gpWarMemory				= False		' (33) War Target memory between balls
	gpFreeSpins				= True		' (34)
	gpRansomSpotFrequency	= 100		' (35) games
	gpMultiballSpotFrequency = 20		' (36) games
	gpMultiballDifficulty	= 0			' (37)
	gpPercentSpecial		= 4			' (38)
	gpLoopChampAward		= 0			' (39) 'extra ball'
	gpExtraBallTimer		= 8000		' (40) time to get an extra ball when lit
	gpUTurnTimer			= 10000		' (41) time to complete next u-turn
	gpKnightTargetTime  	= 13000		' (42) time to knock down all targets
	gpRansomTimer			= 25000		' (43)
	gpLowerLockTimer		= 20000		' (44)
	gpJackpotTimer			= 12000		' (45)
	gpRansomBoltTimer		= 12000		' (46)
	gpJackpotAdvance		= 5000		' (47)

	' and any of my own local game values
	gvKickbackSafeTime  	= 3000		' time kickback is enabled after being first triggered
	gvWheelSpinLitTimer		= 3000		' time spin is lit after going though the left in-lane
	gvWheelSpinTimerStart   = 10
  gvWheelSpinTimerEnd     = 65    '80
	gvHurryUpStaticTimer	= 1000		' time hurry-up bonus remains static
	gvHurryUpTimer			= 7000 		' time for hurry-up bonus to reduct from value to 0
	gvTimerSpeedSlice		= 11		' number of slices to split timers
  										' into for faster flash rates (hurry up effect)

	' set up light arrays
	set LightningWheelLights(0)  = LightSpin1	' lightning wheel
		LightningWheelPoints(0)  = 0			' extra ball
		LightningWheelText(0)	 = "   EXTRA BALL   "
	set LightningWheelLights(1)  = LightSpin2
		LightningWheelPoints(1)  = 50000		' 50,000
		LightningWheelText(1)	 = "     5À000      "
	set LightningWheelLights(2)  = LightSpin3
		LightningWheelPoints(2)  = 1			' magna-save
		LightningWheelText(2)	 = "   MAGNA-SAVE   "
	set LightningWheelLights(3)  = LightSpin4
		LightningWheelPoints(3)  = 10000		' 10,000
		LightningWheelText(3)	 = "     1À000      "
	set LightningWheelLights(4)  = LightSpin5
    LightningWheelPoints(4)  = 2      ' Multi-Ball
		LightningWheelText(4)	 = "   MULTI-BALL   "
	set LightningWheelLights(5)  = LightSpin6
		LightningWheelPoints(5)  = 100000		' 100,000
		LightningWheelText(5)	 = "     10À000     "
	set LightningWheelLights(6)  = LightSpin7
		LightningWheelPoints(6)  = 3			' ransom letter
		LightningWheelText(6)	 = "  RANSOM LETTER "
	set LightningWheelLights(7)  = LightSpin8
		LightningWheelPoints(7)  = 200000		' 200,000
		LightningWheelText(7)	 = "     20À000     "
	set LightningWheelLights(8)  = LightSpin9
		LightningWheelPoints(8)  = 0			' special (extra ball)
		LightningWheelText(8)	 = "    SPECIAL     "
	set LightningWheelLights(9)  = LightSpin10
		LightningWheelPoints(9)  = 20000		' 20,000
		LightningWheelText(9)	 = "     2À000      "
	set LightningWheelLights(10) = LightSpin11
		LightningWheelPoints(10) = 4			' Kickback
		LightningWheelText(10)	 = "    KICKBACK    "
	set LightningWheelLights(11) = LightSpin12
		LightningWheelPoints(11) = 150000		' 150,000
		LightningWheelText(11)	 = "     15À000     "
	set LightningWheelLights(12) = LightSpin13
		LightningWheelPoints(12) = 5			' Draw bridge
		LightningWheelText(12)	 = "   DRAWBRIDGE   "
	set LightningWheelLights(13) = LightSpin14
		LightningWheelPoints(13) = 75000		' 75,000
		LightningWheelText(13)	 = "     7Å000      "
	set LightningWheelLights(14) = LightSpin15
		LightningWheelPoints(14) = 6			' Hurry-Up
		LightningWheelText(14)	 = "    HURRY-UP    "
	set LightningWheelLights(15) = LightSpin16
		LightningWheelPoints(15) = 250000 		' 250,000
		LightningWheelText(15)	 = "     25À000     "

	set BonusLights(0) = Light2X				' bonus lights
	set BonusLights(1) = Light3X
	set BonusLights(2) = Light4X
	set BonusLights(3) = Light5X

	set BlackLights(0) = Light_BlackB 			' black (orange) lights
	set BlackLights(1) = Light_BlackL
	set BlackLights(2) = Light_BlackA
	set BlackLights(3) = Light_BlackC
	set BlackLights(4) = Light_BlackK

	set KnightLights(0) = Light_KnightK			' knight lights
	set KnightLights(1) = Light_KnightN
	set KnightLights(2) = Light_KnightI
	set KnightLights(3) = Light_KnightG
	set KnightLights(4) = Light_KnightH
	set KnightLights(5) = Light_KnightT

	set WinLights(0) = Light_WinW				' win lights
	set WinLights(1) = Light_WinI
	set WinLights(2) = Light_WinN

	set WarLights(0) = Light_WarW				' war lights
	set WarLights(1) = Light_WarA
	set WarLights(2) = Light_WarR

	set DrawBridgeLights(0) = Light_Drawbridge1	' drawbridge lights
	set DrawBridgeLights(1) = Light_Drawbridge2
	set DrawBridgeLights(2) = Light_Drawbridge3

	set DarkLights(0) = LightDark1				' dark lights
	set DarkLights(1) = LightDark2
	set DarkLights(2) = LightDark3
	set DarkLights(3) = LightDark4
	set DarkLights(4) = LightDark5
	set DarkLights(5) = LightDark6
	set DarkLights(6) = LightDark7

	' set the instructions
	TextboxInstructions.Text = ""
  TextboxInstructions.Text = TextboxInstructions.Text + "Game Keys" & vbNewLine & vbNewLine
  TextboxInstructions.Text = TextboxInstructions.Text + "Start Button : 1" & vbNewLine
  TextboxInstructions.Text = TextboxInstructions.Text + "Left Flipper : Left Shift" & vbNewLine
  TextboxInstructions.Text = TextboxInstructions.Text + "Right Flipper : Right Shift" & vbNewLine
  TextboxInstructions.Text = TextboxInstructions.Text + "Pull Plunger : Enter" & vbNewLine
  TextboxInstructions.Text = TextboxInstructions.Text + "Magna-Save : '" & vbNewLine
  TextboxInstructions.Text = TextboxInstructions.Text + "Forward Nudge : Space" & vbNewLine
  TextboxInstructions.Text = TextboxInstructions.Text + "Left Nudge : Z" & vbNewLine
  TextboxInstructions.Text = TextboxInstructions.Text + "Right Nudge : /" & vbNewLine
  TextboxInstructions.Text = TextboxInstructions.Text + "High Score Entry : Enter" & vbNewLine
  TextboxInstructions.Text = TextboxInstructions.Text + "Pause/Exit : ESC" & vbNewLine & vbNewLine
  TextboxInstructions.Text = TextboxInstructions.Text + "Hold Down Flipper Button for Status Report during game"

	' set any game variables
	bGameInPlay	= False 							' game started flag
	Score		= 0

  ' set up magnasave
  Set MagnaSaveMagnet = New cvpmMagnet
  MagnaSaveMagnet.InitMagnet TriggerMagnaSave, 7

	' any attract mode variables
	LastWheelAttractMode = -1
	CurrentMusicPlaying  = -1

  TimerTiltReduce.Interval = 100
  TimerTiltReduce.Enabled = True

	' play a very familiar sound ;-)
	playsound "WilliamsBong"

	' ensure anything else is reset
	EndOfGame()
End Sub


rem When this timer is running it processes any balls on the magnet
rem
Sub TimerMagnet_Timer()
    MagnaSaveMagnet.ProcessBalls
End Sub

Sub TriggerMagnaSave_Hit()
  MagnaSaveMagnet.AddBall ActiveBall
End Sub

Sub TriggerMagnaSave_UnHit()
  MagnaSaveMagnet.RemoveBall ActiveBall
End Sub


rem --------------------------------------------------
rem	    		User Interface functions
rem --------------------------------------------------

rem A key (on the computer keyboard, not playfield) has been pressed down
rem
Sub Table_KeyDown(ByVal keycode)
	Dim TempState
	Dim RndNudge

  LastKeyCode = keycode

	' is a game in progress?
	If (bGameInPlay = True) Then

		If keycode = PlungerKey Then
			Plunger.PullBack
		End If

    If (keycode = LeftFlipperKey) and (bTilted = False) Then
			LeftFlipper.RotateToEnd
      PlaySound "LFlipper"
			' rotate the WIN lights to the left
			TempState = Light_WinW.State
			Light_WinW.State = Light_WinI.State
			Light_WinI.State = Light_WinN.State
			Light_WinN.State = TempState
			' rotate the WAR lights to the left
			TempState = Light_WarW.State
			Light_WarW.State = Light_WarA.State
			Light_WarA.State = Light_WarR.State
			Light_WarR.State = TempState
      ' start status display timer
      TimerStatusDisplay.Enabled = True
		End If

    If (keycode = RightFlipperKey) and (bTilted = False) Then
			RightFlipper.RotateToEnd
			RightFlipperTop.RotateToEnd
      PlaySound "RFlipper"
			' rotate the WIN lights to the right
			TempState = Light_WinN.State
			Light_WinN.State = Light_WinI.State
			Light_WinI.State = Light_WinW.State
			Light_WinW.State = TempState
			' rotate the WAR lights to the right
			TempState = Light_WarR.State
			Light_WarR.State = Light_WarA.State
			Light_WarA.State = Light_WarW.State
			Light_WarW.State = TempState
      ' start status display timer
      TimerStatusDisplay.Enabled = True
		End If

    If (keycode = LeftTiltKey) and (bTilted = False)  Then
			RndNudge = Rnd(1) / 2	' random number between .0 and .49
      RndNudge = RndNudge + 2.25 ' make it between 2.25 and 2.749
			Nudge 75, RndNudge
      AddToTilt(RndNudge)
		End If

		If keycode = RightTiltKey Then
			RndNudge = Rnd(1) / 2
      RndNudge = RndNudge + 2.25
			Nudge 285, RndNudge
      AddToTilt(RndNudge)
		End If

		If keycode = CenterTiltKey Then
			RndNudge = Rnd(1) / 2
      RndNudge = RndNudge + 2.25
			Nudge 0, RndNudge
      AddToTilt(RndNudge)
		End If

      If keycode = 40 Then ' "'" (next to enter) Magna-Save
			' if the light is on (not flashing) then enable the magnasave magnet which
			' will hopefully catch a ball
      If (BumperMagnaSave.State = LightStateOn) then
				TurnOnMagnaSaveMagnet()
			end If
    End if

		' DIAGNOSTIC TEST KEYS FOR DEVELOPEMT
'    If keycode = 16 Then 'Q
'      LightHurryUpLight()
'    End if

'    If keycode = 17 Then 'W     ' open the draw bridge
'      OpenDrawbridge()
'    End if

'    If keycode = 18 Then 'E     ' add another ransom letter
'      AwardRansomLetter()
'    End If

'    If keycode = 19 Then 'R     ' increase the score
'      AddScore(gsJackpot)
'    End If

 Else 'bGameInPlay
		' nope, are in attract mode or high score entry mode
		if (hsbModeActive = True) then
			' process the high score entry functions
			HighScoreProcessKey(keycode)
		else
			' wait for the start key to be pressed and start a new game
      If (keycode = StartGameKey) Then    '1
				if (BallsInGame = 0) and (BallsInLock = 0) then
					bGameInPlay = True
					ResetForNewGame()
				else
					PlaySound "BK2k-GiveMoney"
				end if
		 	End if

      If (keycode = AddCreditKey) Then    '5
        PlaySound "Credit01"
      End if

      If keycode = PlungerKey Then
        Plunger.PullBack
      End If
 	 	End if
 	End if
End Sub

rem A key (on the computer keyboard, not playfield) has been released
rem
Sub Table_KeyUp(ByVal keycode)

  ' are in attract mode or high score entry mode?
  If (hsbModeActive = False) then
    If keycode = PlungerKey Then
      Plunger.Fire
    End If
  End If

	' is a game in progress?
	If bGameInPlay = True then

    If keycode = LeftFlipperKey Then
			LeftFlipper.RotateToStart
      ' stop status display timer
      TimerStatusDisplay.Enabled = False
		End If

		If keycode = RightFlipperKey Then
			RightFlipper.RotateToStart
			RightFlipperTop.RotateToStart
      ' stop status display timer
      TimerStatusDisplay.Enabled = False
		End If

	End if
End Sub



rem --------------------------------------------------
rem
rem	    local functions used through-out the game
rem
rem --------------------------------------------------

rem Initialise the variables/table for a new game
rem
Sub ResetForNewGame()
	' update game stats
  gsGamesPlayed = gsGamesPlayed + 1
  SaveValue "BlackKnight2000", "GamesPlayed", gsGamesPlayed
  GameCounterReel.AddValue(1)

  Score                   = 0
  BallsRemaining          = BallsPerGame  ' balls remaining to play (inclusive)
  BallsInLock             = 0             ' no balls in lock
  BlackValue              = 0             ' number of black lights lit
  KnightValue             = 0             ' number of Knight Targets down
  ExtraBallsAwards        = 0             ' no EBs
  bMultiBallMode          = False         ' not in any multiball mode
  bChallengeMode          = False
  bChallengeSpinEject     = False
  bRansomGoSickMode       = False
  bJackpotWonThisGame     = False
  bBallInPlungerLane      = False
	bBallInChallengeKicker	= False
  LoopsForExtraBall       = 2             ' start off having to do 2 loops for extra-ball
  HurryUpBonus            = 0             ' reset huury up
  HurryUpBonusLevel       = 0
  MaxLoopsThisGame        = 0

  bTilted                 = False         ' not tilted and no warnings given
  gpTiltWarningsGiven     = 0             ' (note then plumb might still be moving as I don't reset it)
  gvReplayAwarded         = False

	' turn off all the lights
	SetAllLightsToState(LightStateOff)

	' reset the display queue and display the current score
	DisplayFlushQueue()

  ' play I am the black knight Sound (also flashes knight helmet)
  PlayKnightSound 4, True

  ' set up the lightning effect & sound for first ball
  DisplayQueueScreen "        0       ", "                ", eNone, eNone, 0, 2000,  TRUE, ""
  DisplayQueueScreen "-"               , "                ", eNone, eNone, 0, 40,  TRUE, "Lightning bolt"
  DisplayQueueScreen "-"               , "-               ", eNone, eNone, 0, 40,  TRUE, "Lightning bolt"
  DisplayQueueScreen "-"               , "--              ", eNone, eNone, 0, 40,  TRUE, "Lightning bolt"
  DisplayQueueScreen "-"               , "----            ", eNone, eNone, 0, 40,  TRUE, ""
  DisplayQueueScreen "-"               , "----/           ", eNone, eNone, 0, 40,  TRUE, ""
  DisplayQueueScreen "-"               , " ---/_          ", eNone, eNone, 0, 40,  TRUE, ""
  DisplayQueueScreen "-"               , "  --/__         ", eNone, eNone, 0, 40,  TRUE, ""
  DisplayQueueScreen "-"               , "   -/___        ", eNone, eNone, 0, 40,  TRUE, ""
  DisplayQueueScreen "-"               , "    /____       ", eNone, eNone, 0, 40,  TRUE, ""
  DisplayQueueScreen "-"               , "     ___*B      ", eNone, eNone, 0, 40,  TRUE, ""
  DisplayQueueScreen "-"               , "      __*BA     ", eNone, eNone, 0, 40,  TRUE, ""
  DisplayQueueScreen "-"               , "       _*BAL    ", eNone, eNone, 0, 40,  TRUE, ""
  DisplayQueueScreen "-"               , "        *BALL   ", eNone, eNone, 0, 40,  TRUE, ""
  DisplayQueueScreen "-"               , "         BALL "&Chr((BallsRemaining+1)+48)&" ", eNone, eNone, 0, 40,  TRUE, ""

  ' set up the start delay to handle the start of game attract sequence
  TimerFirstBallDelay.Interval = 2800
  TimerFirstBallDelay.Enabled = True
End Sub

rem The start of game delay timer has expired so start the show
rem
Sub TimerFirstBallDelay_Timer()
  ' stop the timer
  TimerFirstBallDelay.Enabled = False

	' kickback and magnasave (maybe) are enabled for the first ball
	EnableKickback()
	if (gpMagnaSaveAtStart = True) then
		EnableMagnaSave()
	end if

  ' reset Knight targets (also starts flashing the targets)
  ResetKnightTargets()

	' if we are to default to a free spin of the wheel
	if (gpFreeSpins = True) then
		LightLightningWheel(0)		' permantly on (dosn't expire)
	end if

  ' reset the table for a new ball
  ResetForNewBall()

  ' create a new ball
  CreateNewBall()
End Sub

rem Initialise the variables/table for a new ball
rem
Sub ResetForNewBall()
  BallsInGame = 0         ' no ball on the playfield yet (excluding locked balls)
	bTilted		= False
  gvTiltLevel = 0
	Bonus 		= 0
  HurryUpBonusLevel = 0   ' back to 200K bonus for hurry-up
	LoopSuccessiveLoops = 0	' reset the loop counter
  LoopsThisBall = 1       ' game gives 1 u-turn and 1 loops as a bonus
  UTurnsThisBall = 1

  bTilted                 = False         ' not tilted and no warnings given
  gpTiltWarningsGiven     = 0             ' (note then plumb might still be moving as I don't reset it)

  ' start the wheel animations
	PickRandomWheelAttractMode()

	' do we hold the multiplier?
	if (LightBonusHold.State <> LightStateOff) then
		' yep, but turn of the hold light
		LightBonusHold.State = LightStateOff
	else
		' no, reset to 1X
		SetBonusMultiplier(1)	' no bonus multiplier (or 1X)
	end if

	' the spin lane is not protected (against multiple balls)
	WallSpinProtect.IsDropped = True
	' and challenge lane
	WallChallengeProtect.IsDropped = True

	' ensure the multi-ball protect is UP
	WallMultiballProtect.IsDropped = False
  ' raise the loop wall to allow the ball to fall into the WIN lanes
  LoopWall.IsDropped = False

	' close the drawbridge
	CloseDrawbridge()

	' reset the war lane between balls if the option says to do so.
	if (gpWarMemory = False) then
		ResetWarLights()
	end if
	' reset the win lights
	ResetWinLights()
	' reset the u-turn timer/start value
	ResetUTurn()
	' reset ransom light and timers (not ransom value, this carries on from
	' game to game (how nice of it :P )
	ResetRansom()
	' reset Extra Ball
	ResetExtraBallLight()
	' reset hurry-up bonus
	ResetHurryUpLight()
	' reset Jackpot
	ResetJackpotBolt()
	' turn off knights challenge
	LightChallenge.State = LightStateOff

	' reset the display queue and display the current score
	DisplayFlushQueue()
	DisplayScore()

  ' start ball in plunger music
  PlayGameMusic(9)
End Sub

rem This frunction is called at the end of the game, it will reset all
rem the drop targets, and eject any 'held' balls
rem
Sub EndOfGame()
	' reset KNIGHT drop targets
	ResetKnightTargets()

	' kill the last switch
	set LastSwitchHit = TriggerDummy

	' kill any active timers
  TimerKNIGHT.Enabled             = False
  TimerBlackFlash.Enabled         = False
  TimerKickbackLight.Enabled      = False
  TimerRansom.Enabled             = False
  TimerRansomFlash.Enabled        = False
  TimerJackpot.Enabled            = False
  TimerJackpotFlash.Enabled       = False
  TimerHurryUpFlash.Enabled       = False
	TimerHurryUpScoreReduce.Enabled = False
  TimerExtraBall.Enabled          = False
  TimerExtraBallFlash.Enabled     = False
  TimerLightSpinWheel.Enabled     = False
  TimerUTurn.Enabled              = False
  TimerUTurnFlash.Enabled         = False
  TimerMagnaSave.Enabled          = False
  TimerLightningWheel.Enabled     = False
	TimerMultiballRelease.Enabled 	= False
  TimerWheelAttract.Enabled       = False
  TimerRansomMode.Enabled         = False
  TimerRansomBallEject.Enabled    = False
  TimerDark.Enabled               = False
  TimerLoop.Enabled               = False
  TimerStatusDisplay.Enabled      = False
  TimerFirstBallDelay.Enabled     = False
  TimerMagnet.Enabled             = False
  TimerBallSave.Enabled           = False
  TimerWheelIntro.Enabled         = False
  TimerSpare1.Enabled             = False

  ' release the flippers (just incase somebody held them up during game over)
	LeftFlipper.RotateToStart
	RightFlipper.RotateToStart
	RightFlipperTop.RotateToStart

	' if any balls are in lock, release them
	If (BallsInLock <> 0) Then
    ReleaseLockedMultiBalls(500)
	End If

	' start blinking the lights again ;-)
	SetAllLightsForAttractMode()

	' has the player beaten any of the high scores or made loop champion?
	if (Score > gsHighScore4) or (MaxLoopsThisGame > gsLoopChamp) then
		' 'you are champion'
		PlayKnightSound 6, True
		' yep, get them to enter their name
		HighScoreEntryInit()
	else
		' back to standard attract mode	displays
		StartAttractModeDisplays()
		' save the game back to disk
    SaveGameStats()
	end if
End sub



rem **************************************************
rem **************************************************
rem	    		Lower Playfield Functions
rem **************************************************
rem **************************************************

rem --------------------------------------------------
rem	    			Handle the Slingshots
rem --------------------------------------------------

rem The ball has hit the left slingshot, make a noise and add a few points
rem
Sub LeftSlingshot_Slingshot()
	' check what we are in play, just incase a ball being ejected from the
	' multiball lock at the end of the game. we don't want to change the display
  if (bTilted = False) then
    If (bGameInPlay = True) then
      AddScore(10)
      AddJackpot(gpJackpotAdvance)
    End If
    PlaySound "LSling"
    ' forget the last switch
  end if
  set LastSwitchHit = TriggerDummy
End Sub

rem The ball has hit the right slingshot, make a noise and add a few points
rem
Sub RightSlingshot_Slingshot()
  if (bTilted = False) then
    If (bGameInPlay = True) then
      AddScore(10)
      AddJackpot(gpJackpotAdvance)
    End If
    PlaySound "RSling"
    ' forget the last switch
    set LastSwitchHit = TriggerDummy
  end if
End Sub



rem --------------------------------------------------
rem	    Handle the Black/Knight lights/targets
rem --------------------------------------------------

rem The K Knight targer has been hit, drop it, turn on the K light, make
rem a little noise and add a few points
Sub Drop_K_Hit()
	Drop_K.IsDropped = True
	Light_KnightK.state = LightStateOn
  PlaySound "Target down01"
	CheckKnightTargets()
End Sub

rem As above but for the N target
rem
Sub Drop_N_Hit()
	Drop_N.IsDropped = True
	Light_KnightN.state = LightStateOn
  PlaySound "Target down02"
	CheckKnightTargets()
End Sub

rem As above but for the I target
rem
Sub Drop_I_Hit()
	Drop_I.IsDropped = True
	Light_KnightI.state = LightStateOn
  PlaySound "Target down03"
	CheckKnightTargets()
End Sub

rem As above but for the G target
rem
Sub Drop_G_Hit()
	Drop_G.IsDropped = True
	Light_KnightG.state = LightStateOn
  PlaySound "Target down04"
	CheckKnightTargets()
End Sub

rem As above but for the H target
rem
Sub Drop_H_Hit()
	Drop_H.IsDropped = True
	Light_KnightH.state = LightStateOn
  PlaySound "Target down05"
	CheckKnightTargets()
End Sub

rem As above but for the T target
rem
Sub Drop_T_Hit()
	Drop_T.IsDropped = True
	Light_KnightT.state = LightStateOn
  PlaySound "Target down06"
	CheckKnightTargets()
End Sub

rem This function checks to see if all the knight targets have been knocked
rem and if so then moved to the next black light (after making the current
rem one permantly on.  if all black lights are lit then ensable the skyway
rem bonus
rem
Sub CheckKnightTargets()
	dim i
	dim Adjust

	' another one bites the dust
	KnightValue = KnightValue + 1

	' points awarded
	AddScore(5000)
	AddJackpot(20000)

	' stop the timers
	TimerKNIGHT.Enabled = False
	TimerBlackFlash.Enabled = False

	' are all of them down ?
	If (KnightValue = 6) then
		' knocking all of them down enables kickback and magnasave
		if (LightKickback.State = LightStateOff) then
			DisplayQueueScreen "  KNIGHT SPELT  ", "KICKBACK ENABLED", 1, 1, 4, 1400, TRUE, ""
		end if
		EnableKickback()
		EnableMagnaSave()

		' turn the current black light permantly on
		BlackLights(BlackValue).State = LightStateOn
		' move to the next one
		BlackValue = BlackValue + 1
		' reset the knight targets
		ResetKnightTargets()
		' have all of them been lit?
		If (BlackValue = 5) then
			' light the skyway for a 1M bonus
			LightSkyway.State = LightStateOn
			DisplayFlushQueue()
      DisplayQueueScreen "   SKYWAY LIT   ", " FOR 1 MILLION  ", eBlink, eBlink, 0, 1500, TRUE, "WilliamsError"
			' and reset the black lights
			For i = 0 to 4
				BlackLights(i).State = LightStateOff
			Next
			BlackValue = 0
		Else
			DisplayQueueScreen "  BLACK LETTER  ", "    AWARDED     ", 1, 1, 0, 1500, TRUE, ""
		End If
	Else
		' as soon as we hit one target (any one) then start blinking
		' the current black target
		if (BlackLights(BlackValue).State = LightStateOff) then
			BlackLights(BlackValue).State = LightStateBlinking
			BlackLights(BlackValue).BlinkPattern = "10"
		end if
		BlackLights(BlackValue).BlinkInterval = 125

		' start the master timer (gets faster depending on how many black lights are lit
		Adjust = BlackValue * 1000

		TimerKNIGHT.Interval = gpKnightTargetTime - Adjust
		TimerKNIGHT.Enabled = True

		' start the black flash timer (gets called many times to make the
		' current black light flash faster as the master timer gets closer
		' to running out (occurs n times during the master timer)
		TimerBlackFlash.Interval = (gpKnightTargetTime - Adjust) / gvTimerSpeedSlice
		TimerBlackFlash.Enabled = True
	End if

	' this is a target and not a trigger but we want to ensure any
	' other game code knows something has been else has been hit
	set LastSwitchHit = TriggerDummy
End Sub

rem The timer which causes the current black light to blink faster
rem has expired, so make it blink even faster
rem
Sub TimerBlackFlash_Timer()
	TimerBlackFlash.Enabled = False
	' make the current black light blink faster
	BlackLights(BlackValue).BlinkInterval = BlackLights(BlackValue).BlinkInterval - 7
	TimerBlackFlash.Enabled = True
End Sub

rem The KNIGHT timer has expired, reset the drop knight targets and
rem their associated lights
rem
Sub TimerKNIGHT_Timer()
	ResetKnightTargets()
	' turn off the currently blinking black light
	BlackLights(BlackValue).State = LightStateOff
End Sub

rem this function resets the knight drop targets and lights
rem
Sub ResetKnightTargets()
	dim i

	' stop the timers
	TimerKNIGHT.Enabled = False
	TimerBlackFlash.Enabled = False

	' reset the targets and lights
	Drop_K.IsDropped = False
	Drop_N.IsDropped = False
	Drop_I.IsDropped = False
	Drop_G.IsDropped = False
	Drop_H.IsDropped = False
	Drop_T.IsDropped = False

	' if any targets are down then make a noise then they pop back up
	if (KnightValue <> 0) then
    PlaySound "AllTargetUp"
	end if
	KnightValue = 0					' number of Knight Targets down

	For i = 0 to 5
    KnightLights(i).State = LightStateOff
	Next
  ' Knight Lights blink towards the skyway ramp
  Light_KnightK.BlinkPattern = "100"
  Light_KnightN.BlinkPattern = "010"
  Light_KnightI.BlinkPattern = "001"
  Light_KnightG.BlinkPattern = "001"
  Light_KnightH.BlinkPattern = "010"
  Light_KnightT.BlinkPattern = "100"
	For i = 0 to 5
    KnightLights(i).State = LightStateBlinking
	Next

End Sub



rem --------------------------------------------------
rem	    	Handle the left drain Kickback
rem --------------------------------------------------

rem called to enable the kickback
rem
Sub EnableKickback()
	' set the game flag
	bKickbackAvail = True
	' turn on the light
	LightKickback.State = LightStateOn
	' and enable the kicker
	KickerKickback.Enabled = True
	' and disable the kickback light timer (just in case we re-enable
	' a kickback while the bickback is in it's 2 second safe mode
	TimerKickbackLight.Enabled = False
End Sub

rem ball has hit the kickback kicker so flick it back into the playfield
rem and start the kickbacklight timer which flashes the light for a second
rem or so (kickback is still enabled during this time period) to act as
rem a safe mode for the punter (how nice of the game)
rem
Sub KickerKickback_Hit()
	Dim Angle
	Dim Power

	' kick the ball back out into the playfield.  make the power slightly random so the ball
	' dosn't always hit the same GHT target
    Power = Rnd(1) * 16		' pick a random number between 0.0 and 15.0 (well 14.99999 etc)
	Power = Power + 25		' make it between 25.0 and 40.0 (39.99999 etc)

	KickerKickback.Kick 0, Power
   	PlaySound "WilliamsSolenoid"

	' enable kickback timer (if it is not enabled)
	If (TimerKickbackLight.Enabled = False) Then
		TimerKickbackLight.Enabled = True
		TimerKickbackLight.Interval = gvKickbackSafeTime
		LightKickback.State = LightStateBlinking
		LightKickback.BlinkPattern = "10"
		LightKickback.BlinkInterval = 100
	End If

	' although this is not a trigger we want to ensure any
	' other game code knows something has been else has been hit
	set LastSwitchHit = TriggerDummy
End Sub

rem the kickback timer has expired, turn off the light and kicker
rem
Sub TimerKickbackLight_Timer()
	' turn of the timer
	TimerKickbackLight.Enabled = False
	' set the game flag
	bKickbackAvail = False
	' turn off the light
	LightKickback.State = LightStateOff
	' and disable the kicker
	KickerKickback.Enabled = False
End Sub



rem --------------------------------------------------
rem	    			Handle Magna-Save
rem --------------------------------------------------

rem called to enable the magnasave
rem
Sub EnableMagnaSave()
	' set the game flag
	bMagnaSaveAvail = True
	' turn on the light
  BumperMagnaSave.State = LightStateOn
End Sub

rem called to start the magna-save magnet
rem (not implemented yet)
rem
Sub	TurnOnMagnaSaveMagnet()
	' play the magnet sound
	PlaySound "BK2k-MagnaSave"
	' make the light flash
  BumperMagnaSave.BlinkPattern = "10"
  BumperMagnaSave.BlinkInterval = 75
  BumperMagnaSave.State = LightStateBlinking
	' and start the timer, which turns off the magnet and light in 5 seconds
	TimerMagnaSave.Interval = 5700
	TimerMagnaSave.Enabled  = True
  TimerMagnet.Enabled     = True

End Sub

rem the magna-save time has run out, turn off the magnet and light
rem
Sub TimerMagnaSave_Timer()
	TimerMagnaSave.Enabled = False
  TimerMagnet.Enabled    = False
  BumperMagnaSave.State  = LightStateOff
End Sub

rem When this timer is running it processes any balls on the magnet
rem
Sub TimerMagnet_Timer()
    MagnaSaveMagnet.ProcessBalls
End Sub

Sub TriggerMagnaSave_Hit()
  MagnaSaveMagnet.AddBall ActiveBall
End Sub

Sub TriggerMagnaSave_UnHit()
  MagnaSaveMagnet.RemoveBall ActiveBall
End Sub



rem --------------------------------------------------
rem	    			Handle the Skyway
rem --------------------------------------------------

rem the lower skyway switch has been hit, remember the switch id
rem
Sub TriggerSkyWayRamp1_Hit()
	AddJackpot(gpJackpotAdvance)
	set LastSwitchHit = TriggerSkyWayRamp1
End Sub

rem the upper skyway switch has been hit.  now if the last switch
rem hit was the lower skyway switch then the ball has gone up the
rem ramp so check if anything is lit in the skyway ramp.
rem
Sub TriggerSkyWayRamp2_Hit()
	if (LastSwitchHit.Name = "TriggerSkyWayRamp1") then
		' is the skyway bonus lit (or flashing)
		'
		if (LightSkyway.State <> LightStateOff) then
			' yep, award the skyway 1 million bonus
			AddScore (1000000)
			DisplayFlushQueue()
			DisplayQueueScreen "  SKYWAY BONUS  ", "   1 MILLION    ", 2, 1, 0, 2000, TRUE, ""

			' turn the light off
			LightSkyway.State = LightStateOff
			' if not in ransom mode then play a little jingle
			if (bRansomGoSickMode <> True) then
				PlaySound "BK2k-BlackAward"
			end if
		end if

		' is hurry up lit (or flashing)
		'
		if (LightHurryUp.State <> LightStateOff) then
			' add the hurry up bonus (what ever is left of it) to the score
			AddScore(HurryUpBonus)
			' move to the next level of hurry-up bonus
			if (HurryUpBonusLevel < 4) then
				HurryUpBonusLevel = HurryUpBonusLevel + 1
			end if
			' turn the light off
			ResetHurryUpLight()
			' revert back to the standard score screen
      HurryUpBonus = 0
			AddScore(0)
			' play the hurry-up award music
			PlayGameMusic(5)
		end if

		' is extra ball lit (or flashing)
		if (LightExtraBall.State <> LightStateOff) then
			' if the light is blinking, then increment the loops required for the next
			' extra ball light to be lit (can only blink by doing loops)
      if (LightExtraBall.State = LightStateBlinking) then
				LoopsForExtraBall = LoopsForExtraBall + 1
			end if
			' turn the light off
			ResetExtraBallLight()
			' award and extra ball to the player
      AwardExtraBall(False)
      DisplayQueueScreen "   EXTRA BALL   ", "   EXTRA BALL   ", eBlink, eBlink, 0, 2000, TRUE, ""
		end if
	end if
  ' drop the loop wall
  LoopWall.IsDropped = True

	LoopSuccessiveLoops = 0	' reset the loop counter
	set LastSwitchHit = TriggerSkyWayRamp2
End Sub

rem the ball has gone up to the top playfield (via the skyway ramp) but
rem as there isn't a hole in the top playfield for it to go thru (I'm using
rem a bug in the game which allows a ramp/ball to go though a surface ;-)
rem (upwards only thank god) There is a chance that it can make the top
rem playfield height but not though the gate, if it does then it rolls
rem back on the top playfield under the ramp and this kicks it back in.
rem punter knows nothing ;-)
rem
Sub KickerPanic_Hit()
	KickerPanic.Kick 45, 12
End Sub

rem ------- HANDLE EXTRA BALL (PART OF SKYWAY) -------

Sub LightExtraBallLight(Timer)
	' stop the timers
	TimerExtraBall.Enabled = False
	TimerBlackFlash.Enabled = False

	' if a timer has been specified then enable it (light blinks for timer)
	if (Timer <> 0) then
		LightExtraBall.State = LightStateBlinking
		LightExtraBall.BlinkPattern  = "10"
		LightExtraBall.BlinkInterval = 125
		' set the master timer
		TimerExtraBall.Interval = Timer
		TimerExtraBall.Enabled  = True

		' start the flash timer (gets called many times to make the
		' light flash faster as the master timer gets closer
		' to running out (occurs n times during the master timer)
		TimerExtraBallFlash.Interval = Timer / gvTimerSpeedSlice
		TimerExtraBallFlash.Enabled = True
	else
		' else just turn on the light
		LightExtraBall.State = LightStateOn
	end if
End Sub

rem The timer which causes the light to blink faster
rem has expired, so make it blink even faster
rem
Sub TimerExtraBallFlash_Timer()
	TimerExtraBallFlash.Enabled = False
	LightExtraBall.BlinkInterval = LightExtraBall.BlinkInterval - 7
	TimerExtraBallFlash.Enabled = True
End Sub

rem The master timer has expired, turn off extra-ball
rem
Sub	TimerExtraBall_Timer()
	ResetExtraBallLight()
	' revert back to the standard score screen
	AddScore(0)
End Sub

rem stop the timers and turn off the light
rem
Sub ResetExtraBallLight()
	LightExtraBall.State = LightStateOff
	TimerExtraBall.Enabled = False
	TimerExtraBallFlash.Enabled = False
End Sub

rem -------- HANDLE HURRY-UP (PART OF SKYWAY) --------

rem enable hurry-up mode which sets up the bonus which decrements by 10k rapidly
rem
Sub LightHurryUpLight()
	Dim Temp

	' turn on the light
	LightHurryUp.State = LightStateBlinking
	LightHurryUp.BlinkPattern  = "10"
	LightHurryUp.BlinkInterval = 125

	' play the hurry-up music
	PlayGameMusic(4)

	' set the bonus level
	select case (HurryUpBonusLevel)
		case 0:
			HurryUpBonus = 200000		' start at 200K
		case 1:
			HurryUpBonus = 500000		' then 500K
		case 2:
			HurryUpBonus = 750000		' 750K
		case 3:
			HurryUpBonus = 1000000		' 1M
		case 4:
			HurryUpBonus = 1500000		' 1.5M
	end select

	' work out the interval of the score reduce timer (reduces by 10K everytime)
	' it starts in 2 seconds, then reduces the score every n ms

	' get the number of times we have to reduce the hurry up bonus by 10K
	Temp = HurryUpBonus / 10000
	' now divide the total reduce time by this value to give the timer interval
	HurryUpTime = gvHurryUpTimer / Temp	' time for hurry-up bonus to reduct from value to 0

	' set the flash timer (don't start it yet)
	TimerHurryUpFlash.Interval = gvHurryUpTimer / gvTimerSpeedSlice
	TimerHurryUpFlash.Enabled = True

	' display the hurry up bonus
	DisplayHurryUp()

	' the hurry-up bonus remains static for a while before counting down
	TimerHurryUpScoreReduce.Interval = gvHurryUpStaticTimer
	TimerHurryUpScoreReduce.Enabled = True
End Sub

Sub TimerHurryUpScoreReduce_Timer()
	TimerHurryUpScoreReduce.Enabled = False

	' set the interval
	TimerHurryUpScoreReduce.Interval = HurryUpTime
	' Ensure the flash timer is running
	TimerHurryUpFlash.Enabled = True
	' reduce the bonus by 10K
	HurryUpBonus = HurryUpBonus - 10000
	' if out of bonus
	if (HurryUpBonus = 0) then
		' then kill the light and timers
		ResetHurryUpLight()
		' ensure back to normal score display
    DisplayFlushQueue()
    HurryUpBonus = 0
		AddScore(0)
    ' taunt the player ;-)
    PlaySound "BK2k-Laugh"
    ' and play the game music
    if (bChallengeMode = True) then
      PlayGameMusic(2)
    else
      PlayGameMusic(1)
    end if
	else
		' display the remaining bonus on the screen
		DisplayHurryUp()
		' restart the timer
		TimerHurryUpScoreReduce.Enabled = True
	end if
End Sub

rem the timer that makes the light flash faster has expired so make the
rem light flash even faster and restart the timer
rem
Sub	TimerHurryUpFlash_Timer()
	TimerHurryUpFlash.Enabled = False
	LightHurryUp.BlinkInterval = LightHurryUp.BlinkInterval - 7
	TimerHurryUpFlash.Enabled = True
End Sub

rem stop the timers and turn off the light
rem
Sub ResetHurryUpLight()
	HurryUpBonus = 0
	LightHurryUp.State = LightStateOff
	TimerHurryUpFlash.Enabled = False
	TimerHurryUpScoreReduce.Enabled = False
End Sub

rem Display the Hurry-Up screen on the display
rem
Sub DisplayHurryUp()
	' kill off any other displays
	DisplayFlushQueue()
  DisplayQueueScreen " ** HURRY UP ** ", "  "&FormatScore(HurryUpBonus)&"     ", eBlinkFast, eNone, 0, 1100, TRUE, ""
End Sub


rem --------------------------------------------------
rem	    		Handle the Challenge Lane
rem --------------------------------------------------

rem the ball has landed in the challenge kicker (ball popper).
rem start the time for this kicker if the challenge light isn't
rem lit, else go into challenge mode
rem
Sub KickerChallenge_Hit()
	bBallInChallengeKicker = True
	WallChallengeProtect.IsDropped = False

	AddJackpot(gpJackpotAdvance)

	if (LightChallenge.State = LightStateOn) then
    ' go into challenge mode
    StartKnightsChallenge()
		' set the game flag so it knows what ball to eject when the first playfield switch
		' is hit (either the top gate or W.I.N - nothing else)
		bChallengeSpinEject = False
		' kill off any active spin
		TimerLightSpinWheel.Enabled = False
		LightSpinWheel.State = LightStateOff
	else
		' if in multiball mode then lock the ball for 10 seconds
		if (bChallengeMode = True) or (bMultiBallMode = True) or (bRansomGoSickMode = True) then
			KickerChallenge.TimerInterval = 10000
		else
			' else eject a second later
			KickerChallenge.TimerInterval = 1000
			' play the no-way sound
			PlayKnightSound 2, True
			' if the the display queue is empty then
			if (DisplayGetQueueSize() = 0) then
				' quickly scroll a message on the screen (dosn't stop), leaves score on display
				DisplayQueueScreen "-", "  ** NO WAY **  ", 1, 1, 0, 15, FALSE, ""
				DisplayScoreQueue 1, 1
			end if
		end if
		KickerChallenge.TimerEnabled = True
	end if
	' while	the ball is held, blink the light
	LightChallenge.State = LightStateBlinking
	LightChallenge.BlinkPattern = "10"
	LightChallenge.BlinkInterval = 100

	' remember this switch (of kicker)
	set LastSwitchHit = TriggerDummy
End Sub

rem the timer of the challenger kicker has expired, get rid of the ball
rem
Sub KickerChallenge_Timer()
	EjectChallengeBall()
End Sub

rem Eject The Challenge Ball
rem
Sub EjectChallengeBall()
	' check to see if we don't have to eject the ball in the spin kicker (if multi-ball
	' was awarded on the wheel
	if (bChallengeSpinEject = True) and (bChallengeMode = True) then
		bChallengeSpinEject = False
		EjectBallFromSpinLane()
	else
		WallChallengeProtect.IsDropped = True
		LightChallenge.State = LightStateOff
		KickerChallenge.TimerEnabled = False
		KickerChallenge.Kick 185, 10
    PlaySound "WilliamsSolenoid"
		bBallInChallengeKicker = False
	end if
end sub

rem set the game up to run in double knights challenge mode (2 ball multi-ball)
rem
Sub StartKnightsChallenge()
  ' display something
  DisplayFlushQueue()
  DisplayQueueScreen " DOUBLE KNIGHTS ", "    CHALLENGE   ", eNone, eNone, 0, 2000,  FALSE, "knightschallengebell"
  DisplayQueueScreen "-", "  WAR = MILLION ", eNone, eScrollLeft, 0, 20,  FALSE, ""
  DisplayQueueScreen "-", "  WAR = MILLION ", eNone, eBlinkFast, 0, 1000000, TRUE, ""
  ' highlight the war lanes
  if (Light_WarW.State = LightStateOff) then
    Light_WarW.State = LightStateOff
    Light_WarW.State = LightStateBlinking
  end if
  if (Light_WarA.State = LightStateOff) then
    Light_WarA.State = LightStateOff
    Light_WarA.State = LightStateBlinking
  end if
  if (Light_WarR.State = LightStateOff) then
    Light_WarR.State = LightStateOff
    Light_WarR.State = LightStateBlinking
  end if
  ' go into challenge mode
  bChallengeMode = True
  ' close the draw bridge
  CloseDrawbridge()
  ' play the 2 ball multi-ball music
  PlayGameMusic(2)
  ' create and new ball in the plunger lane
  CreateNewBall()
End Sub

rem return from 2 ball multi-ball back to single ball
rem
Sub EndKnightsChallenge()
  bChallengeMode = False  ' not in any kind of multiball at the moment
  PlayGameMusic(1)        ' back to 1 ball music
  ' un-highlight the war lanes
  if (Light_WarW.State = LightStateBlinking) then
    Light_WarW.State = LightStateOff
  end if
  if (Light_WarA.State = LightStateBlinking) then
    Light_WarA.State = LightStateOff
  end if
  if (Light_WarR.State = LightStateBlinking) then
    Light_WarR.State = LightStateOff
  end if
End Sub


rem --------------------------------------------------
rem	    	Handle the Lightning Wheel lane
rem --------------------------------------------------

rem A Ball has gone up the spin lane
rem
Sub TriggerSpin_Hit()
	AddJackpot(gpJackpotAdvance)
	' remember this switch
	set LastSwitchHit = TriggerSpin
End Sub

rem enable the lightning wheel spin light (for a user specified time)
rem
Sub LightLightningWheel(Timer)
  ' if a timer has been specified then enable it (light blinks for timer)
	if (Timer <> 0) then
		TimerLightSpinWheel.Interval = Timer
		TimerLightSpinWheel.Enabled  = True
    LightSpinWheel.State = LightStateBlinking
    LightSpinWheel.BlinkPattern  = "10"
    LightSpinWheel.BlinkInterval = 100
  else
    LightSpinWheel.State = LightStateOn
  end if
End Sub

rem the lightning wheel spin light timer has expired, turn off the light
rem
Sub TimerLightSpinWheel_Timer()
	TimerLightSpinWheel.Enabled = False
	LightSpinWheel.State = LightStateOff
End Sub

rem the ball has gone up the lightning wheel spin run, check to see if
rem we have to spin the wheel (if so do so) and then pop the ball up to
rem the top playfield (like magic ;-)
rem
Sub KickerLightningFrom_Hit()
	Dim i
	Dim WheelAward

	' if the spin light is lite, then spin the wheel
	if (LightSpinWheel.State <> LightStateOff) then
		' get an random number between 0 and 15
		WheelAward = int( rnd(1) * 16 )
		' now check for the exceptions

		' can't spot the last ransom letter on the wheel
		if (gsRansomLettersLit = 5) and (WheelAward = 6)then
			WheelAward = 10					' award 20K instead (mean of me ;-)
		end if

		' if give multiball if 2 (or more) balls are in lock
 		if (WheelAward = 4) and (BallsInLock >= 2) then
			WheelAward = 10					' award 20K instead (mean of me ;-)
		end if

		' set this as the one to award
		LightningWheelAward = WheelAward

		' initialise the wheel for a spin

		' stop the attract timer
		TimerWheelAttract.Enabled = False

		' turn on all the wheen lights and light the first one
		For i = 0 to 15
			LightningWheelLights(i).State = LightStateOff
		Next
		WheelLightThatIsLit = 0
		LightningWheelLights(WheelLightThatIsLit).State = LightStateOn

    ' stop all music
    PlayGameMusic(0)

    ' set up the lightning effect & sound
		DisplayFlushQueue()
    DisplayQueueScreen "-              -", "                ", eNone, eNone, 0, 40, TRUE, "Lightning bolt"
    DisplayQueueScreen "--            --", "-"               , eNone, eNone, 0, 40, TRUE, "Lightning bolt"
    DisplayQueueScreen "---          ---", "-"               , eNone, eNone, 0, 40, TRUE, ""
    DisplayQueueScreen "---/        \---", "-"               , eNone, eNone, 0, 40, TRUE, ""
    DisplayQueueScreen " --/_      _\-- ", "-"               , eNone, eNone, 0, 40, TRUE, ""
    DisplayQueueScreen "  -/__    __\-  ", "-"               , eNone, eNone, 0, 40, TRUE, ""
    DisplayQueueScreen "   /___  ___\   ", "-"               , eNone, eNone, 0, 40, TRUE, ""
    DisplayQueueScreen "     __**__     ", "-"               , eNone, eNone, 0, 40, TRUE, ""
    DisplayQueueScreen "      _**_      ", "-"               , eNone, eNone, 0, 40, TRUE, ""
    DisplayQueueScreen "       **       ", "-"               , eNone, eNone, 0, 40, TRUE, ""

    ' start the wheel spin intro timer
    TimerWheelIntro.Interval = 10*60
    TimerWheelIntro.Enabled  = True

    ' raise the spin kicker protect wall.  this saves having to deal with another ball hitting the
		' spin kicker which a wheel spin is in progress (or while a ball is in the poper)
		WallSpinProtect.IsDropped = False
	else
		' no wheel to spin, eject the ball
		EjectBallFromSpinLane()
		' points awarded
		AddScore(5000)
	end if
End Sub

rem When this timer expires (which waits for the wheel spin intro to finish) then
rem start the actual wheel spin
rem
Sub TimerWheelIntro_Timer()
  TimerWheelIntro.Enabled = False

  ' enable the wheel spin timer
  WheelSlowDownSpeed    = gvWheelSpinTimerStart
  WheelSlowDownSpeedLog = 0
  TimerLightningWheel.Interval = WheelSlowDownSpeed
  TimerLightningWheel.Enabled  = True

  ' play the lightning wheel spin music/sounds
  PlayGameMusic(10)

  ' make the spin light blink while the wheel is spinning
  LightLightningWheel(10000)
End Sub

rem this function is called very rapidly to cycle the wheel lights around for a while,
rem gradually slowing down and stopping on the light picked by the random function above
rem
Sub TimerLightningWheel_Timer()
	Dim i
	Dim PreviousLight
	Dim Speed

	TimerLightningWheel.Enabled = False

  ' if tilted then bomb out of the wheel spin
  if (bTilted = True) then
    EjectBallFromSpinLane()
    Exit Sub
  end if

	' make a little noise
  'PlaySound "Trigger"

	' move to the next light (handle the wrap around (light 15 back to light 0))
	WheelLightThatIsLit = WheelLightThatIsLit + 1
	if (WheelLightThatIsLit > 15) then
		WheelLightThatIsLit = 0
	end if

	' get the prvious light
	PreviousLight = WheelLightThatIsLit - 1
	' if we are at light 0, previous is -1 so adjust it to light 15
	if (PreviousLight < 0) then
		PreviousLight = 15
	end if

	' turn on the current light
	LightningWheelLights(WheelLightThatIsLit).State = LightStateOn
	' turn off the previous light
	LightningWheelLights(PreviousLight).State = LightStateOff
	' put the wheel text on the display
	DisplayFlushQueue()
  DisplayQueueScreen "LIGHTNING  WHEEL", LightningWheelText(WheelLightThatIsLit), 0, 0, 0, 1000, TRUE, ""

	' increment the slow down speed time
	' have a log element to it to give a better look)
	WheelSlowDownSpeedLog = WheelSlowDownSpeedLog + .1
	WheelSlowDownSpeed    = WheelSlowDownSpeed + .3 + WheelSlowDownSpeedLog
	' get the timer speed (if below the start value, then keep it above)
	Speed = int(WheelSlowDownSpeed)
	if (Speed < gvWheelSpinTimerStart) then
		Speed = gvWheelSpinTimerStart
	end if
	' set the next timer interval
	TimerLightningWheel.Interval = Speed

	' if we are getting towards the end of the spin
	if (WheelSlowDownSpeed >= gvWheelSpinTimerEnd) then
		' check that we are on the light that we want?
		if (WheelLightThatIsLit = LightningWheelAward) then
			TimerLightningWheel.Enabled = False
			' award the bonus and eject the ball (if not multiball)
			AwardWheelBonus()
			' restart the attract timer in a few seconds to allow the current
			' light to be lit for a bit
			LastWheelAttractMode = -1
			TimerWheelAttract.Interval = 3000
			TimerWheelAttract.Enabled  = True
		else
			' if not then keep going until we are
			TimerLightningWheel.Enabled = True
		end if
	else
		' if not then keep going until we are
		TimerLightningWheel.Enabled = True
	end if
End Sub

rem award the player the reward fromthe wheel
rem
Sub AwardWheelBonus()
	Dim	Item

	DisplayFlushQueue()
	DisplayQueueScreen "  WHEEL  AWARD  ", LightningWheelText(LightningWheelAward), 3, 3, 0, 3000, TRUE, ""

	if (LightningWheelPoints(LightningWheelAward) < 100) then
		Item = LightningWheelPoints(LightningWheelAward)
		select case (item)
			case 0:	' check for extra ball
          AwardExtraBall(False)

			case 1:	' check for magna-save
					EnableMagnaSave()
'          PlaySound "BK2k-BlackAward"

			case 2:	' check for multi-ball (knights challenge)
          StartKnightsChallenge()
					' set the game flag so it knows what ball to eject when the first playfield switch
					' is hit (either the top gate or W.I.N - nothing else)
					bChallengeSpinEject = True

			case 3:	' check for ransom letter
					AwardRansomLetter()

			case 4:	' check for kick back
					EnableKickback()
'          PlaySound "BK2k-BlackAward"

			case 5:	' check for Drawbridge
					OpenDrawbridge()
'          PlaySound "BK2k-BlackAward"

			case 6:	' check for hurry-up
					LightHurryUpLight()
		end select

		' if not multi-ball then eject the ball
		if (Item <> 2) then
			EjectBallFromSpinLane()
		end if
	else
		' just points, add them to the score and eject the ball
'    PlaySound "BK2k-BlackAward"
		AddScore(LightningWheelPoints(LightningWheelAward))
		EjectBallFromSpinLane()
	end if
End Sub

rem eject the ball from the spin lane to the top playfield
rem
Sub EjectBallFromSpinLane()
	' turn off the spin light and timer (might not be running, but it also might be running)
	TimerLightSpinWheel.Enabled = False
	LightSpinWheel.State = LightStateOff

	' lower the protect wall
	if (WallSpinProtect.IsDropped = False) then
		WallSpinProtect.IsDropped = True
	end if

	' create a new ball on the top playfield and kick it into play
	KickerLightningFrom.DestroyBall
	KickerLightningTo.CreateBall
  KickerLightningTo.Kick 225, 12    '236,15
  PlaySound "WilliamsSolenoid"
End Sub



rem --------------------------------------------------
rem	    			Handle the U-Turn
rem --------------------------------------------------

rem the ball has hit the inner right u-turn switch
rem
Sub TriggerUTurnR2_Hit()
	AddJackpot(gpJackpotAdvance)
	' remember this switch
	set LastSwitchHit = TriggerUTurnR2
End Sub

rem A ball has run over the first U-turn target, test for a U-turn
rem
Sub TriggerUTurnR1_Hit()
	AddJackpot(gpJackpotAdvance)
	' if done 2 successive u-turns then award knights challenge
	if (LightUTurn1.State <> LightStateOff) then
		if (LastSwitchHit.Name = "TriggerUTurnL1") or (LastSwitchHit.Name = "TriggerUTurnR1") then
			' can't award challenge mode is 2 (or more) balls are in lock
			' (after all there is only 3 balls in the machine)
			if (BallsInLock < 2) and (bMultiBallMode = False) and (bChallengeMode = False) and (bRansomGoSickMode = False) then
			' if challenge mode off (ie not already on or ball locked in it)
				if (LightChallenge.State = LightStateOff) then
					' then award it
					LightChallenge.State = LightStateOn
					DisplayFlushQueue()
					DisplayQueueScreen  "    KNIGHTS     ", "CHALLENGE IS LIT", 3, 3, 0, 1500, TRUE, "WilliamsError"
				end if
			end if
		end if
	end if

	' was the last switch the other right u-turn??
	' (ie doing a u-turn comming in from the left)
	if (LastSwitchHit.Name = "TriggerUTurnR2") then
		ProcessUTurn()
	end if
	' remember this switch
	set LastSwitchHit = TriggerUTurnR1
End Sub

rem the ball has hit the inner left u-turn switch
rem
Sub TriggerUTurnL2_Hit()
	AddJackpot(gpJackpotAdvance)
	' remember this switch
	set LastSwitchHit = TriggerUTurnL2
End Sub

rem A ball has run over the second U-turn target, test for a U-turn
rem
Sub TriggerUTurnL1_Hit()
	AddJackpot(gpJackpotAdvance)
	' if done 2 successive u-turns then award knights challenge
	if (LightUTurn1.State <> LightStateOff) then
		if (LastSwitchHit.Name = "TriggerUTurnR1") or (LastSwitchHit.Name = "TriggerUTurnL1") then
			' can't award challenge mode is 2 (or more) balls are in lock
			' (after all there is only 3 balls in the machine)
			if (BallsInLock < 2) and (bMultiBallMode = False) and (bChallengeMode = False) and (bRansomGoSickMode = False) then
			' if challenge mode off (ie not already on or ball locked in it)
				if (LightChallenge.State = LightStateOff) then
					' then award it
					LightChallenge.State = LightStateOn
					DisplayFlushQueue()
					DisplayQueueScreen  "    KNIGHTS     ", "CHALLENGE IS LIT", 3, 3, 0, 1500, TRUE, "WilliamsError"
				end if
			end if
		end if
	end if

	' was the last switch the other left u-turn??
	' (ie doing a u-turn comming in from the right)
	if (LastSwitchHit.Name = "TriggerUTurnL2") then
		ProcessUTurn()
	end if
	' remember this switch
	set LastSwitchHit = TriggerUTurnL1
End Sub

rem the ball has performed as u-turn, turn on the blinking lights and award and incrementing bonus
rem
Sub ProcessUTurn()
	Dim	Award
  Dim UturnSound

	' if the u-turn lights are not blinking then make em blink
	if (LightUTurn1.State = LightStateOff) then			' LightUTurn2 will be in the same state
		LightUTurn1.State 		 = LightStateBlinking
		LightUTurn1.BlinkPattern = "10"
		LightUTurn2.State 		 = LightStateBlinking
		LightUTurn2.BlinkPattern = "01"
	end if
	' even if the light is already blinking reset the interval
	LightUTurn1.BlinkInterval = 125
	LightUTurn2.BlinkInterval = 125

	' stop the timers
	TimerUTurn.Enabled = False
	TimerUTurnFlash.Enabled = False

	' start the master timer
	TimerUTurn.Interval = gpUTurnTimer
	TimerUTurn.Enabled = True

	' start the uturn flash timer (gets called many times to make the
	' u-turn lights flash faster as the master timer gets closer
	' to running out (occurs n times during the master timer)
	TimerUTurnFlash.Interval = gpUTurnTimer / gvTimerSpeedSlice
	TimerUTurnFlash.Enabled = True

	if (bRansomGoSickMode = True) then
		Award = 250000				' 250K for doing a uturn in ransom mode
	else
		Award = UTurnValue			' else the current uturn value
	end if

	' quickly scroll a message on the screen
  DisplayQueueScreen "     @@@@@@     ", "     @@@@@@     ", eScrollLeft, eScrollRight, 0, 10, TRUE, ""
'  DisplayQueueScreen "                ", "                ", eScrollLeft, eScrollRight, 0, 20, TRUE, ""
  DisplayQueueScreen "     U-TURN     ", "     "&FormatScore1M(Award)&"     ", eScrollLeft, eScrollRight, 0, 500, TRUE, ""

  ' spin the wheel for a bit
  if (UTurnValue >= 75000) then
    UturnSound = "U-Turn04"
  else
    if (UTurnValue >= 50000) then
      UturnSound = "U-Turn02"
    else
      UturnSound = "U-Turn01"
    end if
  end if
  playSound UturnSound

  SpinWheelForUTurn()

	' give the current bonus to the player
	AddScore(Award)
	' increment the uturn bonus in increments of 25k until 250k
	if (UTurnValue < 250000) then
		UTurnValue = UTurnValue + 25000
	end if

	' keep track of the # of uturns as this is used for the bonus system
	UTurnsThisBall = UTurnsThisBall + 1
End Sub

rem The master u-turn timer has expired, reset everything
rem
Sub TimerUTurn_Timer()
	' reset the u-turn bonus award, light timer etc..
	ResetUTurn()
End Sub

rem The timer which causes the u-turn lights to blink faster
rem has expired, so make it blink even faster
rem
Sub TimerUTurnFlash_Timer()
	' make the U-turn lights blink faster
	LightUTurn1.BlinkInterval = LightUTurn1.BlinkInterval - 7
	LightUTurn2.BlinkInterval = LightUTurn2.BlinkInterval - 7
End Sub

rem reset the u-turn timers, bonus and lights
rem
Sub ResetUTurn()
	' Stop the U-Turn timers
	TimerUTurn.Enabled = False
	TimerUTurnFlash.Enabled = False

	' reset the u-turn bonus award
	UTurnValue = 25000		' first U-Turn awards 25k

	' and the lights
	LightUTurn1.State = LightStateOff
	LightUTurn2.State = LightStateOff
End Sub

rem Spin the wheel when a player makes a u-turn
rem
Sub SpinWheelForUTurn()
	Dim i

  ' stop the current wheel timer
	TimerWheelAttract.Enabled = False
  ' forget the current attract mode
  LastWheelAttractMode = -1
  ' 4 lights (grouped together) spin around to the left
  LightSpin1.BlinkPattern  = "1111000000000000"
  LightSpin2.BlinkPattern  = "1110000000000001"
  LightSpin3.BlinkPattern  = "1100000000000011"
  LightSpin4.BlinkPattern  = "1000000000000111"
  LightSpin5.BlinkPattern  = "0000000000001111"
  LightSpin6.BlinkPattern  = "0000000000011110"
  LightSpin7.BlinkPattern  = "0000000000111100"
  LightSpin8.BlinkPattern  = "0000000001111000"
  LightSpin9.BlinkPattern  = "0000000011110000"
  LightSpin10.BlinkPattern = "0000000111100000"
  LightSpin11.BlinkPattern = "0000001111000000"
  LightSpin12.BlinkPattern = "0000011110000000"
  LightSpin13.BlinkPattern = "0000111100000000"
  LightSpin14.BlinkPattern = "0001111000000000"
  LightSpin15.BlinkPattern = "0011110000000000"
  LightSpin16.BlinkPattern = "0111100000000000"

  ' set all the lights to blinking
  LightningWheelLights(0).State         = LightStateBlinking
  LightningWheelLights(0).BlinkInterval = 15
  For i = 1 to 15
    LightningWheelLights(i).State       = LightStateOff
    LightningWheelLights(i).State       = LightStateBlinking
    LightningWheelLights(i).BlinkInterval = 15
  Next

  ' each cycle takes 1600ms to run (16 x 100) so use
	' that value to ensure a smooth transition of lights
  TimerWheelAttract.Interval = 1 * 1600
	TimerWheelAttract.Enabled = True
End Sub



rem --------------------------------------------------
rem	    			Handle the In-Lanes
rem --------------------------------------------------

rem going down the left inlane enables the spin light for a few seconds
rem
Sub LeftInlane_Hit()
	' if not in multi-ball mode (either 3 or 3) then enable the spin light
	if (bChallengeMode <> True) and (bMultiBallMode <> True) then
		' enable lightning wheel spin light (if it is not permantly on)
		if (LightSpinWheel.State <> LightStateOn) then
			DisplayQueueScreen "LIGHTNING WHEEL ", "    SPIN LIT    ", 3, 3, 0, 1500, TRUE, ""
			LightLightningWheel(gvWheelSpinLitTimer)
		end if
	end if
	' points awarded
	AddScore(5000)
	AddJackpot(gpJackpotAdvance)
	' make a switch sound
  PlaySound "Return lane"
	' I purposly don't remember this switch
End Sub

rem ball hit right inlane switch
rem
Sub RightInlane_Hit()
	' points awarded
	AddScore(5000)
	AddJackpot(gpJackpotAdvance)
	' make a switch sound
  PlaySound "Return lane"
	' remember last switch hit
	set LastSwitchHit = TriggerTrough
End Sub



rem --------------------------------------------------
rem	    			Handle the Out-Lanes
rem --------------------------------------------------

rem ball hit left outlane switch
rem
Sub LeftOutlane_Hit()
	' if kickback isn't enabled then we are about to lose a ball, boo hoo to the player ;-)
	' I check to see that we don't play the sound twice as it is possible that
	' the bounces off the lower wall and hit the switch again
	if (LightKickback.State = LightStateOff) and (BallsInGame = 1) and (LastSwitchHit.Name <> "LeftOutlane") then
		if (BallsRemaining > 0) then
			' if not on the last ball and we have made either a high score or loop champ then make a
			' nasty noise ;-)
			if (Score > gsHighScore4) or (MaxLoopsThisGame > gsLoopChamp) then
				' ok, made made a high score, if it the last ball and there isn't an extra ball to
				' be awarded then don't make a noise
				if (BallsRemaining = 1) and (ExtraBallsAwards = 0) then
				else
					PlayKnightNegComment()
				end if
			else
				PlayKnightNegComment()
			end if
		end if
	else
		' make a switch sound
		PlaySound "Trigger"
	end if
	' points awarded
	AddScore(10000)
	AddJackpot(gpJackpotAdvance)
	' remember last switch hit
	set LastSwitchHit = LeftOutlane
End Sub

rem ball hit right outlane switch (ball lost)
rem
Sub RightOutlane_Hit()
	if (BallsInGame = 1) and (LastSwitchHit.Name <> "RightOutlane") then
		if (BallsRemaining > 0) then
			' if not on the last ball and we have made either a high score or loop champ then make a
			' nasty noise ;-)
			if (Score > gsHighScore4) or (MaxLoopsThisGame > gsLoopChamp) then
				' ok, made made a high score, if it the last ball and there isn't an extra ball to
				' be awarded then don't make a noise
				if (BallsRemaining = 1) and (ExtraBallsAwards = 0) then
				else
					PlayKnightNegComment()
				end if
			else
				PlayKnightNegComment()
			end if
		end if
	end if
	' points awarded
	AddScore(10000)
	AddJackpot(gpJackpotAdvance)
	' remember last switch hit
	set LastSwitchHit = RightOutlane
End Sub



rem --------------------------------------------------
rem	    			Handle the Start Lane
rem --------------------------------------------------

rem create a new ball in the plunger lane
rem
Sub CreateNewBall()
	' if knights challenge is lit and there are 2 balls locked then turn it off
	if (LightChallenge.State = LightStateOn ) and (BallsInLock = 2) then
		LightChallenge.State = LightStateOff
	end if

	KickerShooter.CreateBall
	BallsInGame = BallsInGame + 1
	KickerShooter.Kick 90, 5
	PlaySound "Plunger"
	' mark a ball as being in the plunger lane
	bBallInPlungerLane = True
End Sub

rem set the last switch hit if this is the only ball on the playfield
rem
Sub TriggerShooter_Hit()
	AddJackpot(gpJackpotAdvance)
	set LastSwitchHit = TriggerShooter
End Sub

rem the ball has been shot from the plunger, now in the original game it loops
rem upto the top playfield but we cheat a little and using a to-from kicker
rem to transport the ball from the lower playfield to the top playfield and
rem into the start ball ramp
rem
Sub KickerStartFrom_Hit()
	KickerStartFrom.DestroyBall
	KickerStartTo.CreateBall
	KickerStartTo.Kick 180, 10
	' PlaySound "WilliamsSolenoid"
	' mark a ball as NOT being in the plunger lane
	bBallInPlungerLane = False
	if (bChallengeMode = True) then
		DisplayFlushQueue()
		AddScore(0)
	end if
End Sub



rem --------------------------------------------------
rem	    		Handle the Through/Drain
rem --------------------------------------------------

rem set the last switch hit if this is the only ball on the playfield.
rem if it is not then we have lost a ball in one of the 2 multi-ball games
rem
Sub TriggerTrough_Hit()
	' if last ball (in game, not left) and it has drained between the flippers then
	' play the lose ball sound
	if (LastSwitchHit.Name <> "LeftOutlane") and (LastSwitchHit.Name <> "RightOutlane") and (LastSwitchHit.Name <> "TriggerTrough") then
		AddJackpot(gpJackpotAdvance)
		' must be last ball
		if (BallsInGame = 1) and (BallsRemaining > 0) then
			' if not on the last ball and we have made either a high score or loop champ then make a
			' nasty noise ;-)
			if (Score > gsHighScore4) or (MaxLoopsThisGame > gsLoopChamp) then
				' ok, made made a high score, if it the last ball and there isn't an extra ball to
				' be awarded then don't make a noise
				if (BallsRemaining = 1) and (ExtraBallsAwards = 0) then
				else
					PlayKnightNegComment()
				end if
			else
				PlayKnightNegComment()
			end if
		end if
	end if
	' remember last switch hit
	set LastSwitchHit = TriggerTrough
End Sub

rem lost a ball ;-( check to see how many balls are on the playfield.
rem if only one then decrement the remaining count and test for end of game
rem if more than 1 ball (multi-ball) then kill of the ball but don't create
rem a new one
rem
Sub Drain_Hit()
	' kill the ball anyway
	Drain.DestroyBall
	BallsInGame = BallsInGame - 1

	' if in ransom mode do nothing (a new ball is created by the ransom ball timer
	if (bRansomGoSickMode <> True) then
		' on the last ball (ie lost all other balls)
		if (BallsInGame = 1) then
			' and in multi-ball
			if (bMultiBallMode = True) then
				' there are no ball still in the lock (ie. this ball drained immediatly)
				if (BallsInLock = 0) then
					' 2 balls of the 3 ball multiball have been lost
					' turn on last chance jackpot which lasts for 20 seconds
					bMultiBallMode = False
					EnableLastChanceJackpot()
				end if
			else
				' are we in knights challenge mode
				if (bChallengeMode = True) then
          EndKnightsChallenge() ' not in any kind of multiball at the moment
				end if
			end if

			' if we lose the last ball and there is one in the challenge kicker, then release it immediatly
			if (bBallInChallengeKicker = True) then
				EjectChallengeBall()
			end if
		end if

		' was that the last ball on the playfield (not including locked balls)
		if (BallsInGame = 0) then
			if (ExtraBallsAwards = 0) then
				BallsRemaining = BallsRemaining - 1
			end if

			' any more balls left?
			if (BallsRemaining <= 0) then
				' check for last chance??
				' this is only on the last ball and exactly 2 balls must be locked
				If (BallsInLock = 2) Then
          DisplayFlushQueue()
          DisplayQueueScreen  "  LAST CHANCE   ", "  LAST CHANCE   ", 3, 3, 0, 1500, TRUE, "WilliamsError"
					' release the balls (also increments 'BallsInGame')
          ReleaseLockedMultiBalls(500)
				Else
					' is the game already over? (a released lock ball hitting the drain)
					if (bGameInPlay <> False) then
						' nope, game over
						ResetHurryUpLight()
						DoBonusDisplay(False)
					end if
				End if
			else
				' has the player won an extra-ball ? (might be multiple outstanding)
				if (ExtraBallsAwards <> 0) then
					' yep got to give it to them
					ExtraBallsAwards = ExtraBallsAwards - 1
					' if no more EB's then turn off the shoot again light
					if (ExtraBallsAwards = 0) then
						LightShootAgain.State = LightStateOff
					End if
          ' display shoot again on the screen
					DisplayFlushQueue()
          DisplayQueueScreen  "   EXTRA BALL   ", "  SHOOT AGAIN   ", eNone, eNone, 0, 1500, TRUE, "Shoot Again"
          ' create a new ball.  nothing gets reset
					CreateNewBall()
				else
					' if on the second last ball and 2 balls are in lock then light the
					' second change lights
					if (BallsRemaining = 1) and (BallsInLock = 2) Then
						LightLastChanceL.State = LightStateOn
						LightLastChanceR.State = LightStateOn
					end if
					ResetHurryUpLight()
					DoBonusDisplay(True)
				end if
			end if
		end if
	end if
End Sub



rem **************************************************
rem **************************************************
rem	    		Top Playfield Functions
rem **************************************************
rem **************************************************

rem the ball has hit the trigger on the rightmost ramp from the
rem top playfield to the lower playfield
rem
Sub TriggerTop2LowerPlayfield_Hit()
	set LastSwitchHit = TriggerTop2LowerPlayfield
End Sub


rem --------------------------------------------------
rem	    			Handle the Red Bumpers
rem --------------------------------------------------

rem The ball has hit a red bumper, make a noise and add a few points
rem
Sub Bumper1_Hit()
	' points awarded
	AddScore(510)
	AddJackpot(2000)
	' make a noise
	SoundBumpber()
	' this is a bumper and not a trigger but we want to ensure any
	' other game code knows something has been else has been hit
	set LastSwitchHit = TriggerDummy
	' reset the loop counter
	LoopSuccessiveLoops = 0
End Sub

rem dito
rem
Sub Bumper2_Hit()
	AddScore(510)
	AddJackpot(2000)
	SoundBumpber()
	set LastSwitchHit = TriggerDummy
	LoopSuccessiveLoops = 0
End Sub

rem dito
rem
Sub Bumper3_Hit()
	AddScore(510)
	AddJackpot(20000)
	SoundBumpber()
	set LastSwitchHit = TriggerDummy
	LoopSuccessiveLoops = 0
End Sub



rem --------------------------------------------------
rem	    		Two Tribes go to WAR
rem --------------------------------------------------

rem ball has hit the lower kicker on the top WAR ramp.
rem 'transport' the ball to the right ramp as it dosn't
rem correctly roll from ramp to ramp
Sub Ramp3_Out_Hit()
  Ramp3_Out.DestroyBall
  Ramp4_in.CreateBall
  Ramp4_in.Kick 110, 3
End Sub

rem have hit the War W trigger
rem
Sub Trigger_WarW_Hit()
  if (Light_WarW.state <> LightStateOn) then
		Light_WarW.state = LightStateOn
    PlaySound "WarLaneHit"
    CheckWarLights()
  else
    PlaySound "WarLaneHitAgain"
	end if
	' points awarded
	AddScore(5000)
	AddJackpot(gpJackpotAdvance)
	' remember last switch hit
	set LastSwitchHit = Trigger_WarW
End Sub

rem have hit the War A trigger
rem
Sub Trigger_WarA_Hit()
  if (Light_WarA.state <> LightStateOn) then
		Light_WarA.state = LightStateOn
    PlaySound "WarLaneHit"
		CheckWarLights()
  else
    PlaySound "WarLaneHitAgain"
	end if
	' points awarded
	AddScore(5000)
	AddJackpot(gpJackpotAdvance)
	' remember last switch hit
	set LastSwitchHit = Trigger_WarA
End Sub

rem have hit the War R trigger
rem
Sub Trigger_WarR_Hit()
  if (Light_WarR.state <> LightStateOn) then
		Light_WarR.state = LightStateOn
    PlaySound "WarLaneHit"
		CheckWarLights()
  else
    PlaySound "WarLaneHitAgain"
  end if
	' points awarded
	AddScore(5000)
	AddJackpot(gpJackpotAdvance)
	' remember last switch hit
	set LastSwitchHit = Trigger_WarR
End Sub

rem check to see if all the WAR lights are lit and if so either away a hurry-up or a million points
rem
Sub CheckWarLights()
  if (Light_WarW.state = LightStateOn) And (Light_WarA.state = LightStateOn) And (Light_WarR.state = LightStateOn) Then
		' all the lights are on but is anybody home?
		' if in a multi-ball mode then award a million points
		if (bChallengeMode = True) or (bMultiBallMode = True) or (bRansomGoSickMode = True) then
			DisplayQueueScreen  "   WAR BONUS    ", "   1 MILLION    ", 3, 3, 0, 2000, TRUE, ""
			AddScore(1000000)
      ' make a nice noise if not is ransom mode
			if (bRansomGoSickMode <> True) then
				PlaySound "BK2k-BlackAward"
			end if
		else
			' else enable hurry-up mode
			LightHurryUpLight()
		end if

    ' if still in challenge mode then set them to all blink
    if (bChallengeMode = True) then
      Light_WarW.State = LightStateOff
      Light_WarW.state = LightStateBlinking
      Light_WarA.State = LightStateOff
      Light_WarA.state = LightStateBlinking
      Light_WarR.State = LightStateOff
      Light_WarR.state = LightStateBlinking
    else
      ' else turn em off.
      ResetWarLights()
    end if
	end if
End Sub

rem turn off the war lights
rem
Sub ResetWarLights()
	' turn em off.
	Light_WarW.state = LightStateOff
	Light_WarA.state = LightStateOff
	Light_WarR.state = LightStateOff
End Sub



rem --------------------------------------------------
rem	    		Handle the Win lights
rem --------------------------------------------------

rem have hit the Win W trigger
rem
Sub Trigger_WinW_Hit()
	if (Light_WinW.state = LightStateOff) then
		Light_WinW.state = LightStateOn
    CheckWinLights(1)
  else
    PlaySound "Top lane already lit"
  end if
	' points awarded
	AddScore(500)
	AddJackpot(gpJackpotAdvance)
	' remember last switch hit
	set LastSwitchHit = Trigger_WinW
  ' drop the loop wall
  LoopWall.IsDropped = True

  ' if in challenge mode, then released the lock ball on contact of the first playfield
	' switch is hit (either the top gate or W.I.N - nothing else)
	if (bChallengeMode = True) then
		EjectChallengeBall()
	end if
End Sub

rem have hit the Win I trigger
rem
Sub Trigger_WinI_Hit()
	if (Light_WinI.state = LightStateOff) then
		Light_WinI.state = LightStateOn
    CheckWinLights(2)
  else
    PlaySound "Top lane already lit"
	end if
	' points awarded
	AddScore(500)
	AddJackpot(gpJackpotAdvance)
	' play a switch noise
	PlaySound "Trigger"
	' remember last switch hit
	set LastSwitchHit = Trigger_WinI
  ' drop the loop wall
  LoopWall.IsDropped = True

	' if in challenge mode, then released the lock ball on contact of the first playfield
	' switch is hit (either the top gate or W.I.N - nothing else)
	if (bChallengeMode = True) then
		EjectChallengeBall()
	end if
End Sub

rem have hit the Win N trigger
rem
Sub Trigger_WinN_Hit()
	if (Light_WinN.state = LightStateOff) then
		Light_WinN.state = LightStateOn
    CheckWinLights(3)
  else
    PlaySound "Top lane already lit"
	end if
	' points awarded
	AddScore(500)
	AddJackpot(gpJackpotAdvance)
	' play a switch noise
	PlaySound "Trigger"
	' remember last switch hit
	set LastSwitchHit = Trigger_WinN
  ' drop the loop wall
  LoopWall.IsDropped = True

	' if in challenge mode, then released the lock ball on contact of the first playfield
	' switch is hit (either the top gate or W.I.N - nothing else)
	if (bChallengeMode = True) then
		EjectChallengeBall()
	end if
End Sub

rem check to see if all the WIN lights are lit and if so increase the bonus Multiplier
rem and light ransom bolt (drawbridge) for a few seconds
rem
Sub CheckWinLights(Lane)

	if (Light_WinW.state <> LightStateOff) And (Light_WinI.state <> LightStateOff) And (Light_WinN.state <> LightStateOff) Then
    PlaySound "Top lanes complete"
		if (bRansomGoSickMode = True) then
			' points awarded
			AddScore(20000)
		else
			' points awarded
			AddScore(20000)
			' increase the bonus level
			IncrementBonusMultiplier()
			' enable ransom for a bit
			LightRansomBolt()
			' screen display
      DisplayQueueScreen "   BONUS = "&Chr(BonusMultiplier+48)&"X   ", "   RANSOM LIT   ", 0, 0, 0, 2500, TRUE, ""
		end if
		' turn em off.
		ResetWinLights()
  else
    Select Case (Lane)
      case 1:
              PlaySound "Top lane01"
      case 2:
              PlaySound "Top lane02"
      case 3:
              PlaySound "Top lane03"
    End Select
	end if
End Sub

rem turn off the WIN lights
rem
Sub ResetWinLights()
	' turn em off.
	Light_WinW.state = LightStateOff
	Light_WinI.state = LightStateOff
	Light_WinN.state = LightStateOff
End Sub



rem --------------------------------------------------
rem	    Handle the Drawbridge (storm the castle)
rem --------------------------------------------------

rem the first draw bridge target has been hit
rem
Sub TargetDrawbridge1_Hit()
  if (Light_Drawbridge1.state <> LightStateOn) then
		Light_Drawbridge1.state = LightStateOn
    PlaySound "Drawbridge target01"
		CheckDrawbridge()
  else
    PlaySound "Target down06"
  end if

	AddJackpot(gpJackpotAdvance)
	' make a noise
'  PlaySound "FlipperDown"
	' reset the loop counter
	LoopSuccessiveLoops = 0
End Sub

rem the second draw bridge target has been hit
rem
Sub TargetDrawbridge2_Hit()
  if (Light_Drawbridge2.state <> LightStateOn) then
		Light_Drawbridge2.state = LightStateOn
    PlaySound "Drawbridge target02"
		CheckDrawbridge()
  else
    PlaySound "Target down06"
	end if
	AddJackpot(gpJackpotAdvance)
	' make a noise
'  PlaySound "FlipperDown"
	' reset the loop counter
	LoopSuccessiveLoops = 0
End Sub

rem the third draw bridge target has been hit
rem
Sub TargetDrawbridge3_Hit()
  if (Light_Drawbridge3.state <> LightStateOn) then
		Light_Drawbridge3.state = LightStateOn
    PlaySound "Drawbridge target03"
		CheckDrawbridge()
  else
    PlaySound "Target down06"
	end if
	AddJackpot(gpJackpotAdvance)
	' make a noise
'  PlaySound "FlipperDown"
	' reset the loop counter
	LoopSuccessiveLoops = 0
End Sub

rem check to see if the draw bridge needs to be lowered
rem
Sub CheckDrawbridge()
	' points awarded
	AddScore(5000)
	' the draw bridge will not open while in bChallengeMode
	if (bChallengeMode = False) then
		' check that all 3 targets have been hit (or all 3 lights are on)
    if (Light_Drawbridge1.state = LightStateOn) and (Light_Drawbridge2.state = LightStateOn) and (Light_Drawbridge3.state = LightStateOn) then
			' yep, open the draw bridge
			OpenDrawbridge()
		end if
	else
		' reset the lights
		Light_Drawbridge1.state = LightStateOff
		Light_Drawbridge2.state = LightStateOff
		Light_Drawbridge3.state = LightStateOff
    Light_Drawbridge1.BlinkPattern = "001"
    Light_Drawbridge2.BlinkPattern = "010"
    Light_Drawbridge3.BlinkPattern = "100"
    Light_Drawbridge1.state = LightStateBlinking
    Light_Drawbridge2.state = LightStateBlinking
    Light_Drawbridge3.state = LightStateBlinking
	end if

	' this is a target and not a trigger but we want to ensure any
	' other game code knows something has been else has been hit
	set LastSwitchHit = TriggerDummy
End Sub

rem open the drawbridge
rem
Sub OpenDrawbridge()
	' lower the bridge
	WallDrawbridge1.IsDropped   = True
	WallDrawbridge2.IsDropped   = True
	WallDrawbridge3.IsDropped   = True
	TargetDrawbridge1.IsDropped = True
	TargetDrawbridge2.IsDropped = True
	TargetDrawbridge3.IsDropped = True
  Light_Drawbridge1.state = LightStateOn
  Light_Drawbridge2.state = LightStateOn
  Light_Drawbridge3.state = LightStateOn
  PlaySound "Drawbridge down01"

	DisplayQueueScreen "  DRAW BRIDGE   ", "    IS OPEN     ", 1, 1, 0, 1500, FALSE, ""
	DisplayQueueScreen "   STORM THE    ", "     CASTLE     ", 1, 1, 0, 2000, TRUE, ""
End Sub

rem close the drawbridge
rem
Sub CloseDrawbridge()
	' turn of the lights
	Light_Drawbridge1.state = LightStateOff
	Light_Drawbridge2.state = LightStateOff
	Light_Drawbridge3.state = LightStateOff
  Light_Drawbridge1.BlinkPattern = "001"
  Light_Drawbridge2.BlinkPattern = "010"
  Light_Drawbridge3.BlinkPattern = "100"
  Light_Drawbridge1.state = LightStateBlinking
  Light_Drawbridge2.state = LightStateBlinking
  Light_Drawbridge3.state = LightStateBlinking

	' and raise the bridge
	WallDrawbridge1.IsDropped   = False
	WallDrawbridge2.IsDropped   = False
	WallDrawbridge3.IsDropped   = False
	TargetDrawbridge1.IsDropped = False
	TargetDrawbridge2.IsDropped = False
	TargetDrawbridge3.IsDropped = False
End Sub



rem --------------------------------------------------
rem 			Handle the 3 ball multi-ball
rem --------------------------------------------------

rem a ball has hit the hidden kicker at the start of the ramp.
rem this fires the ball off at a set speed so the fall off ramp bug is avoided
rem
Sub KickerSpeeder_Hit()
  KickerSpeeder.Kick 225, 15
End Sub

rem a ball has hit the hidden kicker at the end of the ramp.
rem This slows the ball down to a crawl.
rem
Sub KickerMultiBallCatch_Hit()
  KickerMultiBallCatch.Kick 180,1
End Sub

rem a ball has been ejected from lock, update the game variables
rem
Sub TriggerMultiballLower_Hit()
	' raise the exit wall
	WallMultiballProtect.IsDropped = False

	BallsInLock = BallsInLock - 1
	BallsInGame = BallsInGame + 1
End Sub

rem the first (lowest) multi-ball has landed, check for collection of of jackpot (can only
rem happen on this kicker
rem
Sub KickerMultiBall3_Hit()
	' a ball in the lock
	BallsInLock = BallsInLock + 1
	' and one less on the play field
	BallsInGame = BallsInGame - 1
	' close the draw bridge
	CloseDrawbridge()
	' points awarded
	AddScore(100000)
	AddJackpot(gpJackpotAdvance)

	' if ransom is lit then award another RANSOM letter
	if (LightRansom.State <> LightStateOff) then
		AwardRansomLetter()
	end if

	' if jackpot is lit then award it (can only happen in multi-ball mode) when you can't lock
	' a ball
	if (LightJackpot.State <> LightStateOff) then
		' turn on the Jackpot Bolt
		ResetJackpotBolt()
		' add it to the points
		AddScore(gsJackpot)
		' make the display do a little dance
		DisplayQueueScreen " J A C K P O T  ", "  "&FormatScore(gsJackpot)&"     ", 2, 1, 0, 25,   FALSE, ""
		DisplayQueueScreen " J A C K P O T  ", "  "&FormatScore(gsJackpot)&"     ", 3, 3, 0, 3000, TRUE, ""
		' play the jackpot award music
		PlayGameMusic(6)
		' reset the jackpot back to 1M
		gsJackpot = 1000000
		' we have won the jackpot for this game
		bJackpotWonThisGame = True
		' close the draw bridge
		CloseDrawbridge()
		' eject the ball if not in RANSOM mode, this will do it for us
		if (bRansomGoSickMode = False) then
      ReleaseLockedMultiBalls(500)
		end if
	end if

	' if we lock a ball in challenge mode then lock the ball and revert back to normal game mode
	if (bChallengeMode = True) then
    EndKnightsChallenge()
		KickerMultiBall2.Enabled = True	' turn on the next kicker
'    DisplayFlushQueue()
    DisplayQueueScreen " BALL 1 LOCKED  ", "                ", 1, 1, 0, 2000, TRUE, ""
	else
		' if not in RANSOM or multi-ball, then a normal ball lock, lock it and create another one
    if (bMultiBallMode = False) and (bRansomGoSickMode = False) then
'      DisplayFlushQueue()
      DisplayQueueScreen " BALL 1 LOCKED  ", "                ", 1, 1, 0, 2000, TRUE, ""
			' lock the ball and create a new ball in the plunger lane
			CreateNewBall()
			' turn on the next kicker
			KickerMultiBall2.Enabled = True
		end if
	end if
End Sub

rem the second multi-ball has landed
rem
Sub KickerMultiBall2_Hit()
	' a ball in the lock
	BallsInLock = BallsInLock + 1
	' and one less on the play field
	BallsInGame = BallsInGame - 1
	' points awarded
	AddScore(100000)
	AddJackpot(gpJackpotAdvance)
	' close the draw bridge
	CloseDrawbridge()
	' if ransom is lit then award another RANSOM letter
	if (LightRansom.State <> LightStateOff) then
		AwardRansomLetter()
	end if

	' if we lock a ball in challenge mode then lock the ball and revert back to normal game mode
	if (bChallengeMode = True) then
    EndKnightsChallenge()
		KickerMultiBall2.Enabled = True	' turn on the next kicker
'    DisplayFlushQueue()
    DisplayQueueScreen " BALL 2 LOCKED  ", "                ", 1, 1, 0, 2000, TRUE, ""
	else
		' if not in RANSOM mode, lock it and create another one
		if (bRansomGoSickMode = False) then
'      DisplayFlushQueue()
			DisplayQueueScreen " BALL 2 LOCKED  ", "                ", 1, 1, 0, 2000, TRUE, ""
			' create a new ball in the plunger lane
			CreateNewBall()
			' turn on the next kicker
			KickerMultiBall1.Enabled = True
		end if
	end if
End Sub

rem the last multi-ball has landed, go into MULTI-BALL Mode
rem
Sub KickerMultiBall1_Hit()
	' a ball in the lock
	BallsInLock = BallsInLock + 1
	' and one less on the play field
	BallsInGame = BallsInGame - 1
	' points awarded
	AddScore(100000)
	AddJackpot(gpJackpotAdvance)
	' is ransom is lit then award another RANSOM letter
	if (LightRansom.State <> LightStateOff) then
		AwardRansomLetter()
	end if

  ' go into Multiball mode
  bMultiBallMode = True
	' turn on the jackpot award
	LightJackpotBolt()

	' don't have to check that we are in ChallengeMode as it is impossible
	' to lock 3 balls and still be in it.

	' if not just been put into ransom mode, then play the multi-ball music and
	' release the balls.  (ransom mode will take care of the ball release)
	if (bRansomGoSickMode = False) then
		DisplayFlushQueue()
		DisplayQueueScreen "    STAND UP    ", "    AND FIGHT   ", 1, 2, 0, 3000, FALSE, ""
		DisplayQueueScreen "   GET READY    ", "   FOR BATTLE   ", 1, 2, 0, 3000, TRUE, ""
		' 'stand up and fight'
		PlayKnightSound 1, True
		PlayGameMusic(3)
    ReleaseLockedMultiBalls(6000)
	end if
End Sub

rem release the balls in the lock (this is done on a timer to make things nice and smooth
rem and to put a little delay in between each ball
rem
Sub ReleaseLockedMultiBalls(RelTime)
	if (BallsInLock <> 0) then
		TimerMultiballRelease.Interval = RelTime	' time to first ball release
		TimerMultiballRelease.Enabled  = True
	end if
	' turn off the second chance lights
	LightLastChanceL.State = LightStateOff
	LightLastChanceR.State = LightStateOff
End Sub

rem this timer will release the balls one at a time ensuring the kickers above the ball to
rem be release are turned off to make sure they don't re-catch that ball
rem
Sub TimerMultiballRelease_Timer()
	TimerMultiballRelease.Enabled = False
	TimerMultiballRelease.Interval = 500		' # of ms between release of each ball

	' lower the exit wall
	WallMultiballProtect.IsDropped = True

	if (BallsInLock = 3) then
       	PlaySound "WilliamsSolenoid"
		KickerMultiBall1.Kick 0, 13
		KickerMultiBall1.Enabled = False
		TimerMultiballRelease.Enabled = True
	else
		if (BallsInLock = 2) then
	       	PlaySound "WilliamsSolenoid"
			KickerMultiBall2.Kick 0, 14
			KickerMultiBall1.Enabled = False
			KickerMultiBall2.Enabled = False
			TimerMultiballRelease.Enabled = True
		else
			if (BallsInLock = 1) then
		       	PlaySound "WilliamsSolenoid"
				KickerMultiBall1.Enabled = False
				KickerMultiBall2.Enabled = False
				KickerMultiBall3.Kick 0, 15
				KickerMultiBall1.Enabled = False
				KickerMultiBall2.Enabled = False
				TimerMultiballRelease.Enabled = False
			else
				TimerMultiballRelease.Enabled = True
			end if
		end if
	end if

	PlaySound "Bumper"
End Sub



rem --------------------------------------------------
rem 					Handle JACKPOT
rem --------------------------------------------------

rem turn on the Jackpot light
rem
Sub LightJackpotBolt()
	LightJackpot.State = LightStateOn
End Sub

rem enable second chance jackpot which lasts for 20 seconds
rem
Sub EnableLastChanceJackpot()
	' turn on last chance jackpot which lasts for 20 seconds
	' start flashing the jackpot light
	LightJackpot.BlinkInterval = 125
	LightJackpot.BlinkPattern = "10"
	LightJackpot.State = LightStateBlinking
	' start the master timer
	TimerJackpot.Interval = gpJackpotTimer
	TimerJackpot.Enabled = True
	' start the jackpot flash timer
	TimerJackpotFlash.Interval = gpJackpotTimer / gvTimerSpeedSlice
	TimerJackpotFlash.Enabled = True
	' pre-jackpot music
	PlayGameMusic(8)
End Sub

rem The master Jackpot timer has expired, reset everything
rem
Sub TimerJackpot_Timer()
	ResetJackpotBolt()
End Sub

rem The timer which causes the jackpot light to blink faster
rem has expired, so make it blink even faster
rem
Sub TimerJackpotFlash_Timer()
	TimerJackpotFlash.Enabled = False
	LightJackpot.BlinkInterval = LightJackpot.BlinkInterval - 7
	TimerJackpotFlash.Enabled = True
End Sub

rem reset the jackpot bolt and timers
rem
Sub ResetJackpotBolt()
	' turn the light off
	LightJackpot.State = LightStateOff
	' and stop the timers
	TimerJackpot.Enabled = False
	TimerJackpotFlash.Enabled = False
End Sub



rem --------------------------------------------------
rem 					Handle RANSOM
rem --------------------------------------------------

rem this will light the ransom bolt on the drawbridge
rem
Sub LightRansomBolt()
	' can only light the ransom bolt if NOT in ransom mode
	if (bRansomGoSickMode = False) then
		' if the ransom lights are not blinking then make em blink
		if (LightRansom.State = LightStateOff) then
			LightRansom.State 		 = LightStateBlinking
			LightRansom.BlinkPattern = "10"
		end if
		' even if the light is already blinking reset the interval
		LightRansom.BlinkInterval = 125
		' stop the timers
		TimerRansom.Enabled = False
		TimerRansomFlash.Enabled = False

		' start the master timer
		TimerRansom.Interval = gpRansomBoltTimer
		TimerRansom.Enabled = True

		' start the flash timer (gets called many times to make the
		' u-turn lights flash faster as the master timer gets closer
		' to running out (occurs n times during the master timer)
		TimerRansomFlash.Interval = gpRansomBoltTimer / gvTimerSpeedSlice
		TimerRansomFlash.Enabled = True
	end if
End Sub

rem The master Ransom timer has expired, reset everything
rem
Sub TimerRansom_Timer()
	ResetRansom()
End Sub

rem The timer which causes the ransom light to blink faster
rem has expired, so make it blink even faster
rem
Sub TimerRansomFlash_Timer()
	TimerRansomFlash.Enabled = False
	LightRansom.BlinkInterval = LightRansom.BlinkInterval - 7
	TimerRansomFlash.Enabled = True
End Sub

rem reset the ransom timers and light
rem
Sub ResetRansom()
	' Stop the Ransom timers
	TimerRansom.Enabled = False
	TimerRansomFlash.Enabled = False
	' and the light
	LightRansom.State = LightStateOff
End Sub

rem increment the ransom letters obtained and update the back board
rem check to see if we have to go into ransom mode
rem
Sub AwardRansomLetter()
	' turn off the light/timers
	ResetRansom()
	' add another letter
	gsRansomLettersLit = gsRansomLettersLit + 1
	' update the backboard
	DrawBackboardRansom()

	' check for RANSOM ;-)
	if (gsRansomLettersLit = 6) then
		' got ransom, go absolutly sick ;-) 20 seconds of mayhem
		bRansomGoSickMode = True
		bMultiBallMode = True
		' Reset Win, Uturns and Hurry-Up (if in progress)
		ResetWinLights()
		ResetUTurn()
		ResetHurryUpLight()
		' set the multipler to 5
		SetBonusMultiplier(5)
		' and hold it
		LightBonusHold.State = LightStateOn
		' permantly light extra ball
		LightExtraBallLight(0)
		' turn on the skyway
		LightSkyway.State = LightStateOn
		' turn on the jackpot award
		LightJackpotBolt()
		' set the master, ball eject timers
		TimerRansomMode.Interval		= gpRansomTimer + 29500 ' start in n seconds
		RansomRemainingMs				= gpRansomTimer
		TimerRansomBallEject.Interval 	= 29500		' start in n seconds
		TimerRansomMode.Enabled 	 	= True
		TimerRansomBallEject.Enabled	= True
		' play the RANSOM music
		PlayGameMusic(7)
		' queue up the displays
		DisplayFlushQueue()
		DisplayQueueScreen "  R             ", "  R             ", 0, 0, 0, 500, FALSE, ""		' 0ms
		DisplayQueueScreen "  R A           ", "  R A           ", 0, 0, 0, 500, FALSE, ""		' 500ms
		DisplayQueueScreen "  R A N         ", "  R A N         ", 0, 0, 0, 450, FALSE, ""		' 950ms
		DisplayQueueScreen "  R A N S       ", "  R A N S       ", 0, 0, 0, 450, FALSE, ""		' 1400ms
		DisplayQueueScreen "  R A N S O     ", "  R A N S O     ", 0, 0, 0, 450, FALSE, ""		' 1850ms
		DisplayQueueScreen "  R A N S O M   ", "  R A N S O M   ", 0, 0, 0, 400, FALSE, ""		' 2250ms
		DisplayQueueScreen "THE KINGS RANSOM", "THE KINGS RANSOM", 0, 0, 0, 9800, FALSE, ""		' 2700ms
		DisplayQueueScreen "-",                "   BONUS = 5X   ", 0, 0, 0, 2500, FALSE, ""		' 12500ms
		DisplayQueueScreen "-",                " WAR = MILLION  ", 0, 0, 0, 2500, FALSE, ""		' 15000ms
		DisplayQueueScreen "-",                " JACKPOT IS LIT ", 0, 0, 0, 2000, FALSE, ""		' 17500ms
		DisplayQueueScreen "-",                " SKYWAY IS LIT  ", 0, 0, 0, 2500, FALSE, ""		' 19500ms
		DisplayQueueScreen "   EVERYTHING   ", "     IS LIT     ", 3, 3, 0, 7500, TRUE, ""		' 22000ms
 																								' 29500ms ball release
	else
		' display advance ransom on the display
		DisplayFlushQueue()
    DisplayQueueScreen " ADVANCE RANSOM ", " ADVANCE RANSOM ", eblinkFast, eblinkFast, 0, 3000, TRUE, "BK2k-AddRansom"
    DisplayQueueScreen "                ", "                ", eScrollOut, eScrollOut, 0, 20, TRUE, ""
	end if
End Sub

rem RANSOM mode has ended, revert back to something a little more sane
rem
Sub TimerRansomMode_Timer()
	' clear the mode flag
	bRansomGoSickMode = False
	bMultiBallMode = False
	' stop the RANSOM timers
	TimerRansomBallEject.Enabled = False
	TimerRansomMode.Enabled 	 = False
	' turn off the jackpot light
	LightJackpot.State = LightStateOff
	' and the skyway light
	LightSkyway.State = LightStateOff
	' no more RANSOM letters
	gsRansomLettersLit = 0
	' update the backboard
	DrawBackboardRansom()
	DisplayScore()

	' turn on last chance jackpot which lasts for 20 seconds
	EnableLastChanceJackpot()
End Sub

rem This timer runs n times a second to check that there is always 3 balls on the playfield at any one
rem time during ransom mode (the exception to this is that there might be a ball in the shooter lane.
rem have to wait to it is gone before making another ball
rem
Sub TimerRansomBallEject_Timer()
	TimerRansomBallEject.Enabled  = False
	TimerRansomBallEject.Interval = 250
	' if on a even second then update the score board
	if ((RansomRemainingMs MOD 1000) = 0) then
		DisplayScore()
	end if
	' reduce by timer interval
	RansomRemainingMs = RansomRemainingMs - 250

	' if there are some balls in lock then eject them
	if (BallsInLock <> 0) then
    ReleaseLockedMultiBalls(10)
	else
		' else if there is a ball in the plunger lane then there is nothing we can do
		if (bBallInPlungerLane <> True) then
			' if not 3 balls in game (none in lock) then create a new ball
			if (BallsInGame <> 3) Then
				CreateNewBall()
			end if
		end if
	end if

	TimerRansomBallEject.Enabled = True
End Sub


rem --------------------------------------------------
rem 					Handle Loop
rem --------------------------------------------------

rem the ball has hit the 1st loop switch
rem
Sub TriggerLoop1_Hit()
	' remember the last hit switch
	set LastSwitchHit = TriggerLoop1
End Sub

rem the ball has hit the 2nd loop switch
rem
Sub TriggerLoop2_Hit()
  ' drop the loop wall
  LoopWall.IsDropped = True
	AddJackpot(gpJackpotAdvance)
	' remember the last hit switch
	set LastSwitchHit = TriggerLoop2
End Sub

rem the ball has hit the 3rd loop switch (under the gate)
rem
Sub TriggerLoop3_Hit()
  Dim LoopSound

	AddJackpot(gpJackpotAdvance)
	' if the last switch hit was the other loop then player has done a loop
	if (LastSwitchHit.Name = "TriggerLoop2") then
		LoopsThisBall = LoopsThisBall + 1
		LoopSuccessiveLoops = LoopSuccessiveLoops + 1
		' keep track of the most successive loops
		if (LoopSuccessiveLoops > MaxLoopsThisGame) then
			MaxLoopsThisGame = LoopSuccessiveLoops
		end if
		' have we done the required amount to light the extra ball light?
		if (LoopSuccessiveLoops = LoopsForExtraBall) then
			' yep, lit it (for a while)
			LightExtraBallLight(gpExtraBallTimer)
			' award some points (25k, 50k, 75k etc...)
			AddScore(25000 * LoopSuccessiveLoops)
			' check for loop champion
			DisplayFlushQueue()
			DisplayQueueScreen  "   EXTRA BALL   ", "     IS LIT     ", 3, 3, 0, 1500, TRUE, "WilliamsError"
		else
      if (LoopSuccessiveLoops >= 3) then
        LoopSound = "ramp loop03"
      else
        if (LoopSuccessiveLoops = 2) then
          LoopSound = "ramp loop02"
        else
          LoopSound = "ramp loop01"
        end if
      end if
			' quickly scroll a message on the screen (dosn't stop)
			DisplayFlushQueue()
      DisplayQueueScreen "   SKYWAY LOOP  ", "   SKYWAY LOOP  ", 1, 2, 0, 15, FALSE, LoopSound
			DisplayScoreQueue 1, 2
		end if
		' flash the loop light for a bit
		TimerLoop.Enabled = False
		LightLoop.BlinkPattern		 = "10"
		LightSkywayRed.BlinkPattern	 = "01"
		LightLoop.BlinkInterval		 = 125
		LightSkywayRed.BlinkInterval = 125
		LightLoop.State = LightStateBlinking
		LightSkywayRed.State = LightStateBlinking
		TimerLoop.Interval = 750	' 125 * 6
		TimerLoop.Enabled = True
	else
		LoopSuccessiveLoops = 0	' reset the loop counter
	end if

	' remember the last hit switch
	set LastSwitchHit = TriggerLoop3

	' if in challenge mode, then released the lock ball on contact of the first playfield
	' switch is hit (either the top gate or W.I.N - nothing else)
	if (bChallengeMode = True) then
		EjectChallengeBall()
	end if
End Sub

rem the timer for the loop light flash has expired so turn it off and the lights
rem
Sub TimerLoop_Timer()
	' stop the timers
	TimerLoop.Enabled = False
	' and turn off the loop lights
	LightLoop.State = LightStateOff
	LightSkywayRed.State = LightStateOff
End Sub



rem **************************************************
rem **************************************************
rem	    			Misc Game Functions
rem **************************************************
rem **************************************************

rem add points to the score and update the score board
rem
Sub AddScore(points)
  if (bTilted = False) then
    Score = Score + points
    DisplayScore()
  end if
  ' check to see if the player is to be awarded a special (extra ball)
  if (gvReplayAwarded = False) then
    if (Score >= gpReplayStart) then
			' award and extra ball to the player
      AwardExtraBall(True)
      ' on one replay per game
      gvReplayAwarded = True
    end if
  end if
End Sub

rem Add points to the jackpot.  checks the mode of play and the max limit of the jackpot
rem
Sub AddJackpot(points)
  ' jackpot only increments in multiball mode and not tilted
  if (bTilted = False) then
    if (bMultiBallMode = True) then
      gsJackpot = gsJackpot + points
      ' check we havn't excedded the jackpot limit (4M)
      if (gsJackpot >= 4000000) then
        gsJackpot = 4000000
      end if
    end if
  end if
End Sub

rem Will increment the Bonus Multiplier to the next level
rem
Sub IncrementBonusMultiplier()
	Dim NewBonusLevel

	' if not at the maximum bonus level
	if (BonusMultiplier < 5) then
		' then set it the next next one and set the lights
		NewBonusLevel = BonusMultiplier + 1
		SetBonusMultiplier(NewBonusLevel)
	end if
End Sub

rem Set the Bonus Multiplier to the specified level and set the lights accordingly
rem
Sub SetBonusMultiplier(Level)
	Dim i
	' set the multiplier to the specified level
	BonusMultiplier = Level

  ' if the multiplier is 1 then turn off all the bonus lights
	if (BonusMultiplier = 1) then
		For i = 0 to 3
			BonusLights(i).State = LightStateOff
		Next
	else
		' there is a bonus, turn on all the lights upto the current level
		if (BonusMultiplier >= 2) then
			Light2X.State = LightStateOn
		end if
		if (BonusMultiplier >= 3) then
			Light3X.State = LightStateOn
		end if
		if (BonusMultiplier >= 4) then
			Light4X.State = LightStateOn
		end if
		if (BonusMultiplier >= 5) then
			Light5X.State = LightStateOn
		end if
	end if
End Sub

rem the player and won and extra ball
rem
Sub AwardExtraBall(Replay)
	' give it to 'em
	ExtraBallsAwards = ExtraBallsAwards + 1
	' and light the light it not already on
	if (LightShootAgain.State = LightStateOff) then
		LightShootAgain.State = LightStateOn
	End if
  if (Replay = True) then
    PlaySound "WilliamsKnocker"
  else
    PlaySound "Yea"
  end if
End Sub

rem build up the displays which handle the bonus screens when a ball is lost
rem
Sub DoBonusDisplay(bNewBall)
  Dim BonusTime
  Dim UTurnsStatusText
  Dim LoopsStatusText
  Dim CalcBonus
  Dim BonusSound

	' ensure the timer is stopped
	TimerBonusDisplay.Enabled = False
  BonusTime = 0

  bDoBonusNewBall = bNewBall

  ' stop any current music
  PlayGameMusic(0)

  ' must not be tilted to award the bonus
  if (bTilted = False) then
    ' work out the bonus
    Bonus = UTurnsThisBall + LoopsThisBall
    Bonus = Bonus * 3000
    CalcBonus = Bonus

    Select Case (BonusMultiplier)
      case 1:
              BonusSound = "Bonus multiplier 1X"
      case 2:
              BonusSound = "Bonus multiplier 2X"
      case 3:
              BonusSound = "Bonus multiplier 3X"
      case 4:
              BonusSound = "Bonus multiplier 4X"
      case 5:
              BonusSound = "Bonus multiplier 5X"
    End Select

    DisplayFlushQueue()
    DisplayQueueScreen  "                ", "                ", eNone, eNone, 0, 400, TRUE, ""
    BonusTime = BonusTime + 400

'   "1234123412341234"
'   "   ..# LOOPS    "  top line
'   "  ..# U-TURNS   "  bottom
    if (UTurnsThisBall = 1) then
      UTurnsStatusText = "  "+FormatScore1K(UTurnsThisBall,False,False)+" U-TURN    "
    else
      UTurnsStatusText = "  "+FormatScore1K(UTurnsThisBall,False,False)+" U-TURNS   "
    end if
    if (LoopsThisBall = 1) then
      LoopsStatusText = "   "+FormatScore1K(LoopsThisBall,False,False)+" LOOP     "
    else
      LoopsStatusText = "   "+FormatScore1K(LoopsThisBall,False,False)+" LOOPS    "
    end if
    DisplayQueueScreen UTurnsStatusText, LoopsStatusText, eScrollLeft, eScrollLeft, 16, 1000, TRUE, ""
    BonusTime = BonusTime + 2640

'   "       #X       "  top line
'   "     ######     "  bottom

    ' must have at least 1 multiplier
    DisplayQueueScreen "       1X       ", "    "+FormatScore1M(Bonus)+"      ", eNone,  eNone, 0, 10,  TRUE, ""
    DisplayQueueScreen "1              X", "-", eScrollOut, eNone, 0, 10,  TRUE, ""
    DisplayQueueScreen "       1X       ", "-", eScrollIn,  eNone, 0, 10,  TRUE, ""
    BonusTime = BonusTime + 340

    if (BonusMultiplier >= 2) then
      Bonus = Bonus + CalcBonus
      DisplayQueueScreen "       2X       ", "    "+FormatScore1M(Bonus)+"      ", eScrollIn, eNone, 0, 20, TRUE, ""
      BonusTime = BonusTime + 160
    end if

    if (BonusMultiplier >= 3) then
      Bonus = Bonus + CalcBonus
      DisplayQueueScreen "       3X       ", "    "+FormatScore1M(Bonus)+"      ", eScrollIn, eNone, 0, 20, TRUE, ""
      BonusTime = BonusTime + 160
    end if

    if (BonusMultiplier >= 4) then
      Bonus = Bonus + CalcBonus
      DisplayQueueScreen "       4X       ", "    "+FormatScore1M(Bonus)+"      ", eScrollIn, eNone, 0, 20, TRUE, ""
      BonusTime = BonusTime + 160
    end if

    if (BonusMultiplier >= 5) then
      Bonus = Bonus + CalcBonus
      DisplayQueueScreen "       5X       ", "    "+FormatScore1M(Bonus)+"      ", eScrollIn, eNone, 0, 20, TRUE, ""
      BonusTime = BonusTime + 160
    end if

    ' hold last screen for 1 second
    DisplayQueueScreen  "-", "-", eNone, eNone, 0, 1000, TRUE, ""
    BonusTime = BonusTime + 1000

    AddScore(Bonus)

    if (bNewBall = False) then
      DisplayQueueScreen "    GAME OVER   ", "    GAME OVER   ", eScrollOut, eScrollOut, 0, 20, TRUE, "Drain"
      DisplayQueueScreen "    GAME OVER   ", "    GAME OVER   ", eBlinkFast, eBlinkFast, 0, 1500, TRUE, ""
      BonusTime = BonusTime + 1900
    end if
  else
    ' else tilted.  if last ball then display game over
    if (bNewBall = False) then
      DisplayQueueScreen "    GAME OVER   ", "    GAME OVER   ", eScrollOut, eScrollOut, 0, 20, TRUE, "Drain"
      DisplayQueueScreen "    GAME OVER   ", "    GAME OVER   ", eBlinkFast, eBlinkFast, 0, 1500, TRUE, ""
      BonusTime = BonusTime + 1900
    else
      BonusTime = BonusTime + 20
    end if
  end if
	' start the bonus timer
  TimerBonusDisplay.Interval = BonusTime
	TimerBonusDisplay.Enabled  = True
  PlaySound BonusSound
End Sub

rem The bonus timer has expired, either end the game or create a new
rem ball depending on the bDoBonusNewBall flag
rem
Sub TimerBonusDisplay_Timer()
	TimerBonusDisplay.Enabled = False
	if (bDoBonusNewBall = True) then
		' create a new ball
		ResetForNewBall()
		CreateNewBall()
	else
		bGameInPlay = False
		EndOfGame()
	end if
End Sub

rem this timer is used to wait the defined period for when the status screen is displayed
rem
Sub TimerStatusDisplay_Timer()
  TimerStatusDisplay.Enabled = False
  StatusReport()
End Sub

rem Queue up all the status screen displays to the display driver
rem
Sub StatusReport()
  Dim UTurnsStatusText
  Dim LoopsStatusText

	DisplayFlushQueue()
  DisplayQueueScreen "   FREE PLAY    ", "                ", eNone, eNone, 0, 2000, TRUE, ""
  DisplayQueueScreen "                ", "                ", eNone, eNone, 0, 500, TRUE, ""
 ' if on free play, then EXTRA BALL AT, else it is REPLAY AT
  if (gvReplayAwarded = False) then
    if (gpFreePlay = True) then
      DisplayQueueScreen " EXTRA BALL AT  ", "  "&FormatScore(gpReplayStart)&"     ", eNone, eNone, 0, 2000, TRUE, ""
    else
      DisplayQueueScreen "   REPLAY AT    ", "  "&FormatScore(gpReplayStart)&"     ", eNone, eNone, 0, 2000, TRUE, ""
    end if
    DisplayQueueScreen "                ", "                ", eNone, eNone, 0, 500, TRUE, ""
  end if

  if (UTurnsThisBall = 1) then
    UTurnsStatusText = "  "+FormatScore1K(UTurnsThisBall,False,False)+" U-TURN    "
  else
    UTurnsStatusText = "  "+FormatScore1K(UTurnsThisBall,False,False)+" U-TURNS   "
  end if
  if (LoopsThisBall = 1) then
    LoopsStatusText = "   "+FormatScore1K(LoopsThisBall,False,False)+" LOOP     "
  else
    LoopsStatusText = "   "+FormatScore1K(LoopsThisBall,False,False)+" LOOPS    "
  end if
  DisplayQueueScreen UTurnsStatusText, LoopsStatusText, eNone, eNone, 0, 2000, TRUE, ""
  DisplayQueueScreen "                ", "                ", eNone, eNone, 0, 500, TRUE, ""

  DisplayQueueScreen " LOOP CHAMPION  ", "* "&gsLoopChampName&" *"&FormatScore1K(gsLoopChamp,False,False)&" LOOPS", eNone, eNone, 0, 2000, TRUE, ""
  DisplayQueueScreen "                ", "                ", eNone, eNone, 0, 500, TRUE, ""
  DisplayQueueScreen "GREATEST HEREOES", "                ", eNone, eNone, 0, 500, TRUE, ""
  DisplayQueueScreen "-"               , "1> "&gsHighScore1Name&" "&FormatScore(gsHighScore1), eNone, eNone, 0, 2000, TRUE, ""
  DisplayQueueScreen "-"               , "                ", eNone, eNone, 0, 500, TRUE, ""
  DisplayQueueScreen "-"               , "2> "&gsHighScore2Name&" "&FormatScore(gsHighScore2), eNone, eNone, 0, 2000, TRUE, ""
  DisplayQueueScreen "-"               , "                ", eNone, eNone, 0, 500, TRUE, ""
  DisplayQueueScreen "-"               , "3> "&gsHighScore3Name&" "&FormatScore(gsHighScore3), eNone, eNone, 0, 2000, TRUE, ""
  DisplayQueueScreen "-"               , "                ", eNone, eNone, 0, 500, TRUE, ""
  DisplayQueueScreen "-"               , "4> "&gsHighScore4Name&" "&FormatScore(gsHighScore4), eNone, eNone, 0, 2000, TRUE, ""
End Sub

rem This function gets called every time the user nudges the table.
rem It checks the current tilt value (or pendulum swing) and
rem gives a warning to the user or tilts the table
rem
Sub AddToTilt(byVal Power)
  gvTiltLevel = gvTiltLevel + 125

  if (gvTiltLevel > 250) and (bTilted = False) then
    ' are we at full tilt or just give a warning?
    DisplayFlushQueue()
    if (gpTiltWarningsGiven = gpTiltWarnings) then
      ' tilted
      DisplayQueueScreen "      TILT      ", "                ", eBlinkFast, eNone, 0, 2000000, FALSE, "Tilt"
      bTilted = True
      ' turn off all music
      PlayMusic(0)
      ' reset the flippers
      LeftFlipper.RotateToStart
			RightFlipper.RotateToStart
			RightFlipperTop.RotateToStart
    else
      ' give a warning
      gpTiltWarningsGiven = gpTiltWarningsGiven + 1
      if (gpTiltWarningsGiven = 1) then
        DisplayQueueScreen "   * DANGER *   ", "                ", eBlinkFast, eBlinkFast, 0, 2000, TRUE, "Tilt"
      else
        DisplayQueueScreen "   * DANGER *   ", "   * DANGER *   ", eBlinkFast, eBlinkFast, 0, 2000, TRUE, "Tilt"
      end if
    end if
  end if
End Sub

rem This timer gets called 10 times a second to reduce the tilt level
rem
rem the level reduces at .05% each time which is more relistic on a pendulum slowing down
rem at get gets rid of the heavy swing quickly and takes a long time to setting right down
rem
Sub TimerTiltReduce_Timer()
  if (gvTiltLevel > 0) then
    gvTiltLevel = gvTiltLevel - (gvTiltLevel * .05)
    if (gvTiltLevel < 0) then
      gvTiltLevel = 0
    end if
  end if
End Sub



rem **************************************************
rem **************************************************
rem	    			Sound Functions
rem **************************************************
rem **************************************************

rem Play the background music
rem
rem		0 = no music (stops current tune)
rem 	1 = 1 ball music (chant)
rem 	2 = 2 ball music (knights challenge)
rem 	3 = 3 ball music (multi-ball)
rem   4 = Hurry-Up Music
rem 	5 = Hurry-Up Music (award)
rem 	6 = Jackpot Award Music
rem 	7 = Ransom (Go baby go!)
rem 	8 = Pre-Jackpot Music
rem   9 = pre-ball on playfield music
rem  10 = lightning spin music/effects
rem
Sub PlayGameMusic(Theme)
  ' if we are trying to play the music already playing then ignore it as
  ' we want to let it go and not restart it
  if (Theme <> CurrentMusicPlaying) then
    ' stop current music playing
    EndMusic
    ' play the tune specified
    Select Case (Theme)
      case 1:                   ' main game music
        PlayMusic "BK2k-1.mp3"
      case 2:                   ' 2 ball music (knights challenge)
        PlayMusic "BK2k-2.mp3"
      case 3:                   ' 3 ball music (multi-ball)
        PlayMusic "BK2k-3.mp3"
      case 4:                   ' hurry up active
        PlayMusic "BK2k-HurryUp.mp3"
      case 5:                   ' won the hurry-up bonus
        PlayMusic "BK2k-HurryUpAward.mp3"
      case 6:                   ' awarded jackpot
        PlayMusic "BK2k-Jackpot.mp3"
      case 7:                   ' start of ransom mode
        PlayMusic "BK2k-Ransom.mp3"
      case 8:                   ' get jackpot
        PlayMusic "BK2k-PreJackpot.mp3"
     case 9:                    ' pre-game music (ball in trough)
        PlayMusic "BK2k-0.mp3"
     case 10:                   ' lightning wheel spin
        PlayMusic "BK2k-LightningWheelMusic.mp3"
    End Select
    CurrentMusicPlaying = Theme
  end if
End Sub

rem the current music has stoped. restart the appropriate tune for the one that has stoped
rem
Sub Table_MusicDone()
  Dim CurrentMusic

  ' get current music playing
  CurrentMusic = CurrentMusicPlaying
  ' force a restart
  CurrentMusicPlaying = 0
  ' knights challenge, 3 ball multiball and hurry-up music repeats until told otherwise
  If (CurrentMusic >= 2) and (CurrentMusic <= 4) then
    PlayGameMusic(CurrentMusic)
  Else
    if (CurrentMusic = 9) and (bBallInPlungerLane = True) then
      PlayGameMusic(CurrentMusic)
    else
      PlayGameMusic(1)                ' else restart the main tune
    end if
  End If
End Sub

rem plays one of the negative knight chants
rem
Sub PlayKnightNegComment()
	if (rnd(1) >= .5) then
		PlayKnightSound 3, True
	else
		PlayKnightSound 1, True
	end if
End Sub

rem The Function plays one of the Black Knight voice overs and flashes the
rem knights helmet while the sound plays
rem
rem		1 = 'Stand Up and Fight'
rem		2 = 'No Way'
rem		3 = 'Laugh'
rem		4 = 'I Am the Black Knight'
rem		5 = 'Give Me You Money'
rem		6 = 'You Are Champion'
rem
Sub PlayKnightSound(Sound, bPlaySound)
	Dim SndName
	Dim Pattern
	Dim	SndLength

	Select Case(Sound)
		case 1:
			SndName   = "BK2k-SUAF"
			SndLength = 1350
			Pattern   = "01010100010000"
		case 2:
			SndName   = "BK2k-NoWay"
			SndLength = 980
      Pattern   = "0101000000"
		case 3:
			SndName   = "BK2k-Laugh"
			SndLength = 2530
			Pattern   = "01010101010101010101110000"
		case 4:
			SndName	  = "BK2k-Iatbk"
			SndLength = 1850
			Pattern   = "1001001001000010000"
		case 5:
			SndName   = "BK2k-GiveMoney"
			SndLength = 950
			Pattern   = "1010101000"
		case 6:
			SndName   = "BK2k-Champion"
			SndLength = 1450
			Pattern   = "100001001010000"
	End Select
	' set the light pattern which sort of follows the speach
	SetDarkBlinkPat(Pattern)
	' start the dark timer which stops the helmet flash
	TimerDark.Enabled = False
	TimerDark.Interval = SndLength
	TimerDark.Enabled = True
	' if we want to play the sound then do so
	if (bPlaySound = True) then
		PlaySound SndName
	end if
End Sub

rem this functions sets all the helmet lights to flash at the specified pattern
rem
Sub SetDarkBlinkPat(Pattern)
	Dim i
	For i = 0 to 6
		DarkLights(i).State = LightStateOn
		DarkLights(i).BlinkPattern = Pattern
		DarkLights(i).BlinkInterval = 100
		DarkLights(i).State = LightStateBlinking
	Next
End Sub

rem the dark helmet (sounds like spaceballs ;-) timer has expired
rem
Sub TimerDark_Timer()
	Dim i
	' stop the timer
	TimerDark.Enabled = False
	' turn off all the helmet lights
	For i = 0 to 6
		DarkLights(i).State = LightStateOff
	Next
End Sub

rem Play randomly one of the 3 different bumper sounds
rem
Sub SoundBumpber()
	Dim RndSound

	RndSound = Rnd(1) * 3		' pick a random number between 0 and 2

    Select Case (Int(RndSound))
    	Case 0:
        	PlaySound "Bumper"
    	Case 1:
        	PlaySound "Bumper1"
    	Case 2:
        	PlaySound "Bumper2"
	End Select
End Sub



rem **************************************************
rem **************************************************
rem	    			Backboard Functions
rem **************************************************
rem **************************************************

rem light the correct amount of RANSOM letters on the backboard
rem
Sub DrawBackboardRansom()
	select case (gsRansomLettersLit)
		case 0:
      LightRansomR.state = LightStateOff
      LightRansomA.state = LightStateOff
      LightRansomN.state = LightStateOff
      LightRansomS.state = LightStateOff
      LightRansomO.state = LightStateOff
      LightRansomM.state = LightStateOff
		case 1:
      LightRansomR.state = LightStateOn
      LightRansomA.state = LightStateOff
      LightRansomN.state = LightStateOff
      LightRansomS.state = LightStateOff
      LightRansomO.state = LightStateOff
      LightRansomM.state = LightStateOff
		case 2:
      LightRansomR.state = LightStateOn
      LightRansomA.state = LightStateOn
      LightRansomN.state = LightStateOff
      LightRansomS.state = LightStateOff
      LightRansomO.state = LightStateOff
      LightRansomM.state = LightStateOff
		case 3:
      LightRansomR.state = LightStateOn
      LightRansomA.state = LightStateOn
      LightRansomN.state = LightStateOn
      LightRansomS.state = LightStateOff
      LightRansomO.state = LightStateOff
      LightRansomM.state = LightStateOff
		case 4:
      LightRansomR.state = LightStateOn
      LightRansomA.state = LightStateOn
      LightRansomN.state = LightStateOn
      LightRansomS.state = LightStateOn
      LightRansomO.state = LightStateOff
      LightRansomM.state = LightStateOff
		case 5:
      LightRansomR.state = LightStateOn
      LightRansomA.state = LightStateOn
      LightRansomN.state = LightStateOn
      LightRansomS.state = LightStateOn
      LightRansomO.state = LightStateOn
      LightRansomM.state = LightStateOff
		case 6:
      LightRansomR.state = LightStateOn
      LightRansomA.state = LightStateOn
      LightRansomN.state = LightStateOn
      LightRansomS.state = LightStateOn
      LightRansomO.state = LightStateOn
      LightRansomM.state = LightStateOn
	end select
End Sub

rem called by 'TimerDiags' which puts up diagnostic information (for development)
rem
Sub TimerDiags_Timer()
	TimerDiags.Enabled = False

	TextDiags.Text = ""
  TextDiags.Text = TextDiags.Text & "Score: " & FormatNumber(Score, 0, -1, 0, -1) & vbNewLine
  TextDiags.Text = TextDiags.Text & "Bonus:  " & FormatNumber(UTurnsThisBall, 0, -1, 0, -1) & " - " & FormatNumber(LoopsThisBall, 0, -1, 0, -1) & " (MAX " & FormatNumber(MaxLoopsThisGame, 0, -1, 0, -1) & ")" & vbNewLine
  TextDiags.Text = TextDiags.Text & "Jackpot:  " & FormatNumber(gsJackpot, 0, -1, 0, -1) & vbNewLine
  TextDiags.Text = TextDiags.Text & "Balls In Game:  " & FormatNumber(BallsInGame, 0, -1, 0, -1) & vbNewLine
  TextDiags.Text = TextDiags.Text & "Balls In Lock:  " & FormatNumber(BallsInLock, 0, -1, 0, -1) & vbNewLine
  TextDiags.Text = TextDiags.Text & "Balls Remaining:  " & FormatNumber(BallsRemaining, 0, -1, 0, -1) & vbNewLine
  TextDiags.Text = TextDiags.Text & "Extra Balls:  " & FormatNumber(ExtraBallsAwards, 0, -1, 0, -1) & vbNewLine
  TextDiags.Text = TextDiags.Text & "bChallengeMode:  " & FormatBool(bChallengeMode) & vbNewLine
  TextDiags.Text = TextDiags.Text & "bMultiBallMode:  " & FormatBool(bMultiBallMode) & vbNewLine
  TextDiags.Text = TextDiags.Text & "bRansomMode:  " & FormatBool(bRansomGoSickMode) & vbNewLine
  TextDiags.Text = TextDiags.Text & "Display Driver: H(" & FormatNumber(DispQueueHead, 0, -1, 0, -1) & ") T(" & FormatNumber(DispQueueTail, 0, -1, 0, -1) & ")" & vbNewLine
  TextDiags.Text = TextDiags.Text & "Last Switch Hit:" & vbNewLine & "-> " & LastSwitchHit.Name & vbNewLine
  TextDiags.Text = TextDiags.Text & "Music Playing:  " & FormatNumber(CurrentMusicPlaying, 0, -1, 0, -1) & vbNewLine
  TextDiags.Text = TextDiags.Text & "Last Key Pressed:  " & FormatNumber(LastKeyCode, 0, -1, 0, -1) & vbNewLine
  TextDiags.Text = TextDiags.Text & "Tilt Level:  " & FormatNumber(gvTiltLevel, 0, -1, 0, -1) & ",  Tilted: " & FormatBool(bTilted)& vbNewLine
  TextDiags.Text = TextDiags.Text & "Lightning Wheel:  " & LightningWheelText(LightningWheelAward) & vbNewLine
  TextDiags.Text = TextDiags.Text & "Successive Loops:  " & FormatNumber(LoopSuccessiveLoops, 0, -1, 0, -1) & " (" & FormatNumber(LoopsForExtraBall, 0, -1, 0, -1) & ")" & vbNewLine
  TextDiags.Text = TextDiags.Text & "Hurry-Up:  " & FormatNumber(HurryUpBonus, 0, -1, 0, -1) & " (" & FormatNumber(HurryUpBonusLevel, 0, -1, 0, -1) & ")" & vbNewLine

	TimerDiags.Enabled = True
End Sub



rem **************************************************
rem **************************************************
rem	   			Attract Mode Functions
rem **************************************************
rem **************************************************

Sub SetAllLightsForAttractMode()
	Light_BlackB.BlinkPattern = "11100000000111"
	Light_BlackL.BlinkPattern = "01110000001110"
	Light_BlackA.BlinkPattern = "00111000011100"
	Light_BlackC.BlinkPattern = "00011100111000"
	Light_BlackK.BlinkPattern = "00001111110000"

	Light_KnightK.BlinkPattern = "100000"
	Light_KnightN.BlinkPattern = "010000"
	Light_KnightI.BlinkPattern = "001000"
	Light_KnightG.BlinkPattern = "000100"
	Light_KnightH.BlinkPattern = "000010"
	Light_KnightT.BlinkPattern = "000001"

	Light_Drawbridge3.BlinkPattern = "100"
	Light_Drawbridge2.BlinkPattern = "010"
	Light_Drawbridge1.BlinkPattern = "001"

	Light_WinW.BlinkPattern = "100"
	Light_WinI.BlinkPattern = "010"
	Light_WinN.BlinkPattern = "001"

	Light_WarW.BlinkPattern = "100"
	Light_WarA.BlinkPattern = "010"
	Light_WarR.BlinkPattern = "001"

	LightSkyway.BlinkPattern 	= "100"
	LightHurryUp.BlinkPattern 	= "010"
	LightExtraBall.BlinkPattern = "001"

	LightLoop.BlinkPattern 		= "100"
	LightSkywayRed.BlinkPattern = "010"

	LightUTurn1.BlinkPattern 	= "10000001"
	LightUTurn2.BlinkPattern 	= "01000010"
	LightSpinWheel.BlinkPattern = "00100100"
	LightChallenge.BlinkPattern = "00011000"

	LightRansom.BlinkPattern 	= "1000"
	LightJackpot.BlinkPattern 	= "0100"

	LightLastChanceL.BlinkPattern 	= "1100"
	LightLastChanceR.BlinkPattern 	= "0011"

	LightKickback.BlinkPattern 	 = "10"
	LightShootAgain.BlinkPattern = "01"

  BumperMagnaSave.BlinkPattern = "1100"

	LightDark1.BlinkPattern = "1110000"
	LightDark2.BlinkPattern = "1110000"
	LightDark3.BlinkPattern = "1110000"
	LightDark4.BlinkPattern = "1110000"
	LightDark5.BlinkPattern = "1110000"
	LightDark6.BlinkPattern = "1110000"
	LightDark7.BlinkPattern = "1110000"

	' and the 3 bumpers
	Bumper1.BlinkPattern = "11100"
	Bumper2.BlinkPattern = "01110"
	Bumper3.BlinkPattern = "00111"


	' reset the interval and set all lights to blink
	SetAllLightsToState(LightStateOff)
	SetAllLightsToState(LightStateBlinking)
	' get the wheel moving (so to speak)
	PickRandomWheelAttractMode()
End Sub

rem Set all the playfield lights to the specified state
rem
Sub SetAllLightsToState(state)
	Dim Count

	' stop the wheel attract timer
	TimerWheelAttract.Enabled = False

	For Count = 0 to 15
		LightningWheelLights(Count).State = State
	Next
	For Count = 0 to 6
		DarkLights(Count).State = State
		DarkLights(Count).BlinkInterval = 125
	Next
	For Count = 0 to 5
		KnightLights(Count).State = State
		KnightLights(Count).BlinkInterval = 125
	Next
	For Count = 0 to 4
		BlackLights(Count).State = State
		BlackLights(Count).BlinkInterval = 125
	Next
	For Count = 0 to 3
		BonusLights(Count).State = State
		BonusLights(Count).BlinkInterval = 125
	Next
	For Count = 0 to 2
		WinLights(Count).State = State
		WinLights(Count).BlinkInterval = 125
		WarLights(Count).State = State
		WarLights(Count).BlinkInterval = 125
		DrawBridgeLights(Count).State = State
		DrawBridgeLights(Count).BlinkInterval = 125
	Next

	' now for the individual lights
	LightShootAgain.State = State
	LightShootAgain.BlinkInterval = 125
	LightBonusHold.State = State
	LightBonusHold.BlinkInterval = 125
	LightKickback.State = State
	LightKickback.BlinkInterval = 125
	LightLastChanceL.State = State
	LightLastChanceL.BlinkInterval = 125
	LightLastChanceR.State = State
	LightLastChanceR.BlinkInterval = 125
	LightChallenge.State = State
	LightChallenge.BlinkInterval = 125
  BumperMagnaSave.State = State
  BumperMagnaSave.BlinkInterval = 125
	LightSpinWheel.State = State
	LightSpinWheel.BlinkInterval = 125
	LightUTurn1.State = State
	LightUTurn1.BlinkInterval = 125
	LightUTurn2.State = State
	LightUTurn2.BlinkInterval = 125
	LightSkyway.State = State
	LightSkyway.BlinkInterval = 125
	LightHurryUp.State = State
	LightHurryUp.BlinkInterval = 125
	LightExtraBall.State = State
	LightExtraBall.BlinkInterval = 125
	LightRansom.State = State
	LightRansom.BlinkInterval = 125
	LightJackpot.State = State
	LightJackpot.BlinkInterval = 125
	LightLoop.State = State
	LightLoop.BlinkInterval = 125
	Light_Drawbridge1.State = State
	Light_Drawbridge1.BlinkInterval = 125
	Light_Drawbridge2.State = State
	Light_Drawbridge2.BlinkInterval = 125
	Light_Drawbridge3.State = State
	Light_Drawbridge3.BlinkInterval = 125
	LightSkywayRed.State = State
	LightSkywayRed.BlinkInterval = 125
	' and the 3 bumpers
	Bumper1.State = State
	Bumper2.State = State
	Bumper3.State = State
End Sub

rem the timer which controls the wheel light animation has expired.  pick
rem a new animation (randomly)
rem
Sub TimerWheelAttract_Timer()
	PickRandomWheelAttractMode()
End Sub

rem picks a random light wheel animation and runs it for upto 10 seconds
rem
Sub PickRandomWheelAttractMode()
	Dim i
	Dim Mode
	Dim Timer

	' stop the wheel timer
	TimerWheelAttract.Enabled = False

	' pick a random attract mode of the wheel
  Mode = int( rnd(1) * 13)
	' set it up	(ensure the first spin light is always lit first) */
    Select Case (Mode)
		Case 0:
			' 4 lights spin around to the right
			LightSpin1.BlinkPattern  = "1000100010001000"
			LightSpin2.BlinkPattern  = "0100010001000100"
			LightSpin3.BlinkPattern  = "0010001000100010"
			LightSpin4.BlinkPattern  = "0001000100010001"
			LightSpin5.BlinkPattern  = "1000100010001000"
			LightSpin6.BlinkPattern  = "0100010001000100"
			LightSpin7.BlinkPattern  = "0010001000100010"
			LightSpin8.BlinkPattern  = "0001000100010001"
			LightSpin9.BlinkPattern  = "1000100010001000"
			LightSpin10.BlinkPattern = "0100010001000100"
			LightSpin11.BlinkPattern = "0010001000100010"
			LightSpin12.BlinkPattern = "0001000100010001"
			LightSpin13.BlinkPattern = "1000100010001000"
			LightSpin14.BlinkPattern = "0100010001000100"
			LightSpin15.BlinkPattern = "0010001000100010"
			LightSpin16.BlinkPattern = "0001000100010001"

		Case 1:
			' 4 lights spin around to the left
			LightSpin1.BlinkPattern  = "1000100010001000"
			LightSpin2.BlinkPattern  = "0001000100010001"
			LightSpin3.BlinkPattern  = "0010001000100010"
			LightSpin4.BlinkPattern  = "0100010001000100"
			LightSpin5.BlinkPattern  = "1000100010001000"
			LightSpin6.BlinkPattern  = "0001000100010001"
			LightSpin7.BlinkPattern  = "0010001000100010"
			LightSpin8.BlinkPattern  = "0100010001000100"
			LightSpin9.BlinkPattern  = "1000100010001000"
			LightSpin10.BlinkPattern = "0001000100010001"
			LightSpin11.BlinkPattern = "0010001000100010"
			LightSpin12.BlinkPattern = "0100010001000100"
			LightSpin13.BlinkPattern = "1000100010001000"
			LightSpin14.BlinkPattern = "0001000100010001"
			LightSpin15.BlinkPattern = "0010001000100010"
			LightSpin16.BlinkPattern = "0100010001000100"

		Case 2:
			' 2 lights spin around to the right
			LightSpin1.BlinkPattern  = "1000000010000000"
			LightSpin2.BlinkPattern  = "0100000001000000"
			LightSpin3.BlinkPattern  = "0010000000100000"
			LightSpin4.BlinkPattern  = "0001000000010000"
			LightSpin5.BlinkPattern  = "0000100000001000"
			LightSpin6.BlinkPattern  = "0000010000000100"
			LightSpin7.BlinkPattern  = "0000001000000010"
			LightSpin8.BlinkPattern  = "0000000100000001"
			LightSpin9.BlinkPattern  = "1000000010000000"
			LightSpin10.BlinkPattern = "0100000001000000"
			LightSpin11.BlinkPattern = "0010000000100000"
			LightSpin12.BlinkPattern = "0001000000010000"
			LightSpin13.BlinkPattern = "0000100000001000"
			LightSpin14.BlinkPattern = "0000010000000100"
			LightSpin15.BlinkPattern = "0000001000000010"
			LightSpin16.BlinkPattern = "0000000100000001"

		Case 3:
			' 2 lights spin around to the left
			LightSpin1.BlinkPattern  = "1000000010000000"
			LightSpin2.BlinkPattern  = "0000000100000001"
			LightSpin3.BlinkPattern  = "0000001000000010"
			LightSpin4.BlinkPattern  = "0000010000000100"
			LightSpin5.BlinkPattern  = "0000100000001000"
			LightSpin6.BlinkPattern  = "0001000000010000"
			LightSpin7.BlinkPattern  = "0010000000100000"
			LightSpin8.BlinkPattern  = "0100000001000000"
			LightSpin9.BlinkPattern  = "1000000010000000"
			LightSpin10.BlinkPattern = "0000000100000001"
			LightSpin11.BlinkPattern = "0000001000000010"
			LightSpin12.BlinkPattern = "0000010000000100"
			LightSpin13.BlinkPattern = "0000100000001000"
			LightSpin14.BlinkPattern = "0001000000010000"
			LightSpin15.BlinkPattern = "0010000000100000"
			LightSpin16.BlinkPattern = "0100000001000000"

		Case 4:
			' 1 light spin around to the right
			LightSpin1.BlinkPattern  = "1000000000000000"
			LightSpin2.BlinkPattern  = "0100000000000000"
			LightSpin3.BlinkPattern  = "0010000000000000"
			LightSpin4.BlinkPattern  = "0001000000000000"
			LightSpin5.BlinkPattern  = "0000100000000000"
			LightSpin6.BlinkPattern  = "0000010000000000"
			LightSpin7.BlinkPattern  = "0000001000000000"
			LightSpin8.BlinkPattern  = "0000000100000000"
			LightSpin9.BlinkPattern  = "0000000010000000"
			LightSpin10.BlinkPattern = "0000000001000000"
			LightSpin11.BlinkPattern = "0000000000100000"
			LightSpin12.BlinkPattern = "0000000000010000"
			LightSpin13.BlinkPattern = "0000000000001000"
			LightSpin14.BlinkPattern = "0000000000000100"
			LightSpin15.BlinkPattern = "0000000000000010"
			LightSpin16.BlinkPattern = "0000000000000001"

		Case 5:
			' 1 light spin around to the left
			LightSpin1.BlinkPattern  = "1000000000000000"
			LightSpin2.BlinkPattern  = "0000000000000001"
			LightSpin3.BlinkPattern  = "0000000000000010"
			LightSpin4.BlinkPattern  = "0000000000000100"
			LightSpin5.BlinkPattern  = "0000000000001000"
			LightSpin6.BlinkPattern  = "0000000000010000"
			LightSpin7.BlinkPattern  = "0000000000100000"
			LightSpin8.BlinkPattern  = "0000000001000000"
			LightSpin9.BlinkPattern  = "0000000010000000"
			LightSpin10.BlinkPattern = "0000000100000000"
			LightSpin11.BlinkPattern = "0000001000000000"
			LightSpin12.BlinkPattern = "0000010000000000"
			LightSpin13.BlinkPattern = "0000100000000000"
			LightSpin14.BlinkPattern = "0001000000000000"
			LightSpin15.BlinkPattern = "0010000000000000"
			LightSpin16.BlinkPattern = "0100000000000000"

    Case 6:
			' 2 lights which spin in different directions crossing over themselves
			LightSpin1.BlinkPattern  = "1000000000000000"
			LightSpin2.BlinkPattern  = "0100000000000001"
			LightSpin3.BlinkPattern  = "0010000000000010"
			LightSpin4.BlinkPattern  = "0001000000000100"
			LightSpin5.BlinkPattern  = "0000100000001000"
			LightSpin6.BlinkPattern  = "0000010000010000"
			LightSpin7.BlinkPattern  = "0000001000100000"
			LightSpin8.BlinkPattern  = "0000000101000000"
			LightSpin9.BlinkPattern  = "0000000010000000"
			LightSpin10.BlinkPattern = "0000000101000000"
			LightSpin11.BlinkPattern = "0000001000100000"
			LightSpin12.BlinkPattern = "0000010000010000"
			LightSpin13.BlinkPattern = "0000100000001000"
			LightSpin14.BlinkPattern = "0001000000000100"
			LightSpin15.BlinkPattern = "0010000000000010"
			LightSpin16.BlinkPattern = "0100000000000001"

    Case 7:
			' half the circle is lit and spins to the right
			LightSpin1.BlinkPattern  = "1111111100000000"
			LightSpin2.BlinkPattern  = "0111111110000000"
			LightSpin3.BlinkPattern  = "0011111111000000"
			LightSpin4.BlinkPattern  = "0001111111100000"
			LightSpin5.BlinkPattern  = "0000111111110000"
			LightSpin6.BlinkPattern  = "0000011111111000"
			LightSpin7.BlinkPattern  = "0000001111111100"
			LightSpin8.BlinkPattern  = "0000000111111110"
			LightSpin9.BlinkPattern  = "0000000011111111"
			LightSpin10.BlinkPattern = "1000000001111111"
			LightSpin11.BlinkPattern = "1100000000111111"
			LightSpin12.BlinkPattern = "1110000000011111"
			LightSpin13.BlinkPattern = "1111000000001111"
			LightSpin14.BlinkPattern = "1111100000000111"
			LightSpin15.BlinkPattern = "1111110000000011"
			LightSpin16.BlinkPattern = "1111111000000001"

    Case 8:
			' half the circle is lit and spins to the left
			LightSpin1.BlinkPattern  = "1111111100000000"
			LightSpin2.BlinkPattern  = "1111111000000001"
			LightSpin3.BlinkPattern  = "1111110000000011"
			LightSpin4.BlinkPattern  = "1111100000000111"
			LightSpin5.BlinkPattern  = "1111000000001111"
			LightSpin6.BlinkPattern  = "1110000000011111"
			LightSpin7.BlinkPattern  = "1100000000111111"
			LightSpin8.BlinkPattern  = "1000000001111111"
			LightSpin9.BlinkPattern  = "0000000011111111"
			LightSpin10.BlinkPattern = "0000000111111110"
			LightSpin11.BlinkPattern = "0000001111111100"
			LightSpin12.BlinkPattern = "0000011111111000"
			LightSpin13.BlinkPattern = "0000111111110000"
			LightSpin14.BlinkPattern = "0001111111100000"
			LightSpin15.BlinkPattern = "0011111111000000"
			LightSpin16.BlinkPattern = "0111111110000000"

    Case 9:
      ' entire wheel blinks on an off
      LightSpin1.BlinkPattern  = "1100"
      LightSpin2.BlinkPattern  = "1100"
      LightSpin3.BlinkPattern  = "1100"
      LightSpin4.BlinkPattern  = "1100"
      LightSpin5.BlinkPattern  = "1100"
      LightSpin6.BlinkPattern  = "1100"
      LightSpin7.BlinkPattern  = "1100"
      LightSpin8.BlinkPattern  = "1100"
      LightSpin9.BlinkPattern  = "1100"
      LightSpin10.BlinkPattern = "1100"
      LightSpin11.BlinkPattern = "1100"
      LightSpin12.BlinkPattern = "1100"
      LightSpin13.BlinkPattern = "1100"
      LightSpin14.BlinkPattern = "1100"
      LightSpin15.BlinkPattern = "1100"
      LightSpin16.BlinkPattern = "1100"

    Case 10:
      ' every second light alternates
      LightSpin1.BlinkPattern  = "1001"
      LightSpin2.BlinkPattern  = "0110"
      LightSpin3.BlinkPattern  = "1001"
      LightSpin4.BlinkPattern  = "0110"
      LightSpin5.BlinkPattern  = "1001"
      LightSpin6.BlinkPattern  = "0110"
      LightSpin7.BlinkPattern  = "1001"
      LightSpin8.BlinkPattern  = "0110"
      LightSpin9.BlinkPattern  = "1001"
      LightSpin10.BlinkPattern = "0110"
      LightSpin11.BlinkPattern = "1001"
      LightSpin12.BlinkPattern = "0110"
      LightSpin13.BlinkPattern = "1001"
      LightSpin14.BlinkPattern = "0110"
      LightSpin15.BlinkPattern = "1001"
      LightSpin16.BlinkPattern = "0110"

    Case 11:
      ' 4 lights (grouped together) spin around to the right
      LightSpin1.BlinkPattern  = "1111000011110000"
      LightSpin2.BlinkPattern  = "0111100001111000"
      LightSpin3.BlinkPattern  = "0011110000111100"
      LightSpin4.BlinkPattern  = "0001111000011110"
      LightSpin5.BlinkPattern  = "0000111100001111"
      LightSpin6.BlinkPattern  = "1000011110000111"
      LightSpin7.BlinkPattern  = "1100001111000011"
      LightSpin8.BlinkPattern  = "1110000111100001"
      LightSpin9.BlinkPattern  = "1111000011110000"
      LightSpin10.BlinkPattern = "0111100001111000"
      LightSpin11.BlinkPattern = "0011110000111100"
      LightSpin12.BlinkPattern = "0001111000011110"
      LightSpin13.BlinkPattern = "0000111100001111"
      LightSpin14.BlinkPattern = "1000011110000111"
      LightSpin15.BlinkPattern = "1100001111000011"
      LightSpin16.BlinkPattern = "1110000111100001"

    Case 12:
      ' 4 lights (grouped together) spin around to the left
      LightSpin1.BlinkPattern  = "1111000011110000"
      LightSpin2.BlinkPattern  = "1110000111100001"
      LightSpin3.BlinkPattern  = "1100001111000011"
      LightSpin4.BlinkPattern  = "1000011110000111"
      LightSpin5.BlinkPattern  = "0000111100001111"
      LightSpin6.BlinkPattern  = "0001111000011110"
      LightSpin7.BlinkPattern  = "0011110000111100"
      LightSpin8.BlinkPattern  = "0111100001111000"
      LightSpin9.BlinkPattern  = "1111000011110000"
      LightSpin10.BlinkPattern = "1110000111100001"
      LightSpin11.BlinkPattern = "1100001111000011"
      LightSpin12.BlinkPattern = "1000011110000111"
      LightSpin13.BlinkPattern = "0000111100001111"
      LightSpin14.BlinkPattern = "0001111000011110"
      LightSpin15.BlinkPattern = "0011110000111100"
      LightSpin16.BlinkPattern = "0111100001111000"
  End Select

	' if current attract mode is not equal to last attract mode the reset the lights
	' this makes it a LOT smoother if the same mode is picked again. no jitter
	if (Mode <> LastWheelAttractMode) then
		' set all the lights to blinking
    LightningWheelLights(0).State         = LightStateBlinking
    LightningWheelLights(0).BlinkInterval = 60
		For i = 1 to 15
			LightningWheelLights(i).State 		  = LightStateOff
			LightningWheelLights(i).State 		  = LightStateBlinking
      LightningWheelLights(i).BlinkInterval = 60
		Next
	end if

	' set last attract mode
	LastWheelAttractMode = Mode

	' make this attract mode run between 5 and 10 seconds
	Timer = int( rnd(1) * 5000 )
	Timer = Timer + 5000
  ' if it one of the entire wheel flash then only run it for half the time to stop anoying the punters
  if (Mode = 9) or (Mode = 10) then
    Timer = int(Timer / 2)
  end if

	' each cycle takes 1600ms to run (16 x 100) so round off to
	' that value to ensure a smooth transition of lights
	Timer = int(Timer / 1600)
	Timer = Timer * 1600
	TimerWheelAttract.Interval = Timer
	TimerWheelAttract.Enabled = True
End Sub

rem this function queues up all the displays used in attract mode
rem
Sub StartAttractModeDisplays()
	' re-init the attract screen (who made it, high scores, loop champ, etc..)
	DisplayFlushQueue()
'						1234567890123456	1234567890123456
  DisplayQueueScreen "                ", "                ", eNone, eNone, 0, 500,  FALSE, ""
  DisplayQueueScreen "  BLACK KNIGHT  ", "      2000      ", eScrollOut, eScrollOut, 0, 2000, FALSE, ""
  DisplayQueueScreen FormatScore(Score)&"       ", "                ", eNone, eNone, 0, 2000, FALSE, ""
' if on free play then display free play else show coinage options
	if (gpFreePlay = True) then
    DisplayQueueScreen "   FREE PLAY    ", "  PRESS START   ", eNone, eBlink, 0, 2000, FALSE, ""
	else
	end if
  DisplayQueueScreen "GREATEST HEREOES", "                ", eScrollLeft, eScrollLeft, 0, 20, FALSE, ""
  DisplayQueueScreen "GREATEST HEREOES", "-"               , eBlinkFast, eNone, 0, 1000, FALSE, ""
  DisplayQueueScreen "1> "&gsHighScore1Name&" "&FormatScore(gsHighScore1), "2> "&gsHighScore2Name&" "&FormatScore(gsHighScore2), eScrollLeft, eScrollLeft, 6, 2000, FALSE, ""
  DisplayQueueScreen "                ", "                ", eScrollLeft, eScrollLeft, 6, 20, FALSE, ""
  DisplayQueueScreen "3> "&gsHighScore3Name&" "&FormatScore(gsHighScore3), "4> "&gsHighScore4Name&" "&FormatScore(gsHighScore4), eScrollLeft, eScrollLeft, 6, 2000, FALSE, ""
  DisplayQueueScreen "                ", "                ", eScrollLeft, eScrollLeft, 6, 20, FALSE, ""
  DisplayQueueScreen " LOOP CHAMPION  ", "* "&gsLoopChampName&" *"&FormatScore1K(gsLoopChamp,False,False)&" LOOPS", eScrollIn, eScrollIn, 0, 10, FALSE, ""
  DisplayQueueScreen "-", "* "&gsLoopChampName&" *         ", eNone, eBlinkMaskFast, 0, 2000, FALSE, ""
  DisplayQueueScreen "                ", "                ", eScrollIn, eScrollIn, 0, 20, FALSE, ""
  DisplayQueueScreen "    JACKPOT     ", "  "&FormatScore(gsJackpot)&"     ", eScrollIn, eScrollIn, 0, 20, FALSE, ""
  DisplayQueueScreen "-"               , "  "&FormatScore(gsJackpot)&"     ", eNone, eBlinkFast, 0, 2000, FALSE, ""
  DisplayQueueScreen "   FREE PLAY    ", "  PRESS START   ", eNone, eBlink, 0, 2000, FALSE, ""
' if on free play, then EXTRA BALL AT, else it is REPLAY AT
	if (gpFreePlay = True) then
    DisplayQueueScreen " EXTRA BALL AT  ", "  "&FormatScore(gpReplayStart)&"     ", eNone, eBlinkFast, 0, 2000, FALSE, ""
	else
    DisplayQueueScreen "   REPLAY AT    ", "  "&FormatScore(gpReplayStart)&"     ", eNone, eBlinkFast, 0, 2000, FALSE, ""
	end if
' display the custom message
  DisplayQueueScreen "WILLIAMS PINBALL", "    PRESENTS    ", eScrollOut, eScrollOut, 0, 2000, FALSE, ""
' end of custom message
  DisplayQueueScreen "  BLACK KNIGHT  ", "      2000      ", eScrollOut, eScrollOut, 0, 2000, FALSE, ""
' if on free play then display free play else show coinage options
	if (gpFreePlay = True) then
    DisplayQueueScreen "   FREE PLAY    ", "  PRESS START   ", eNone, eBlink, 0, 2000, FALSE, ""
	else
	end if
  DisplayQueueScreen FormatScore(Score)&"       ", "                ", eNone, eNone, 0, 2000, FALSE, ""
  DisplayQueueScreen "ORDER YOUR BLACK", " KNIGHT T-SHIRT ", eNone, eNone, 0, 2000, FALSE, ""
  DisplayQueueScreen "ONLY $1Ä95 CALL ", " 1-800-347-5300 ", eNone, eNone, 0, 2000, FALSE, ""
  DisplayQueueScreen " WINNERS DON'T  ", "   USE DRUGS    ", eNone, eNone, 0, 2000, FALSE, ""
	if (gpFreePlay = True) then
    DisplayQueueScreen " EXTRA BALL AT  ", "  "&FormatScore(gpReplayStart)&"     ", eNone, eNone, 0, 2000, FALSE, ""
	else
    DisplayQueueScreen "   REPLAY AT    ", "  "&FormatScore(gpReplayStart)&"     ", eNone, eNone, 0, 2000, FALSE, ""
	end if
' Visual Pinball - Black Knight Messages (not part of original game ;-)
  DisplayQueueScreen " VISUAL PINBALL ", "[C] RANDY DAVIS ", eNone,        eNone,       0, 2000, FALSE, ""
  DisplayQueueScreen "TABLE CONVERSION", " CHRIS LEATHLEY ", eScrollRight, eScrollLeft, 0, 2000, FALSE, ""
  DisplayQueueScreen "                ", "                ", eScrollRight, eScrollLeft, 0, 100,  FALSE, ""
  DisplayQueueScreen " MANY THANKS TO ", "                ", eScrollLeft,  eScrollLeft, 0, 1000, FALSE, ""
  DisplayQueueScreen "-",                "MARCEL GONZALEZ ", eScrollLeft,  eScrollLeft, 0, 1000, FALSE, ""
  DisplayQueueScreen "-",                "   ROD UTTING   ", eScrollLeft,  eScrollLeft, 0, 1000, FALSE, ""
  DisplayQueueScreen "-",                " ANDREW NEWTON  ", eScrollLeft,  eScrollLeft, 0, 1000, FALSE, ""
  DisplayQueueScreen "-",                "   COREY STUP   ", eScrollLeft,  eScrollLeft, 0, 1000, FALSE, ""
  DisplayQueueScreen "-",                "  WPCMAME TEAM  ", eScrollLeft,  eScrollLeft, 0, 1000, FALSE, ""
  DisplayQueueScreen "-",                "GRIFFEN & MONTY ", eScrollLeft,  eScrollLeft, 0, 1000, FALSE, ""
  DisplayQueueScreen "-",                "   PINK FLOYD   ", eScrollLeft,  eScrollLeft, 0, 1000, FALSE, ""
  DisplayQueueScreen "-",                "  AND TO BORIS  ", eScrollLeft,  eScrollLeft, 0, 1000, FALSE, ""
  DisplayQueueScreen "                ", "                ", eScrollRight, eScrollLeft, 0, 500,  FALSE, ""
End Sub



rem **************************************************
rem **************************************************
rem	   		Battery Backed RAM (Disk) Functions
rem **************************************************
rem **************************************************

rem Load all the game stats from disk
rem
Sub LoadGameStats
  Dim Value
  ' all values have been set to a default value before so if
  ' the load fails there is something to fall back on
  Value = LoadValue("BlackKnight2000", "HighScore1")
  If (Value <> "") Then gsHighScore1 = CDbl(Value) End If
  Value = LoadValue("BlackKnight2000", "HighScore1Name")
  If (Value <> "") Then gsHighScore1Name = Value End If
  Value = LoadValue("BlackKnight2000", "HighScore2")
  If (Value <> "") then gsHighScore2 = CDbl(Value) End If
  Value = LoadValue("BlackKnight2000", "HighScore2Name")
  If (Value <> "") then gsHighScore2Name = Value End If
  Value = LoadValue("BlackKnight2000", "HighScore3")
  If (Value <> "") then gsHighScore3 = CDbl(Value) End If
  Value = LoadValue("BlackKnight2000", "HighScore3Name")
  If (Value <> "") then gsHighScore3Name = Value End If
  Value = LoadValue("BlackKnight2000", "HighScore4")
  If (Value <> "") then gsHighScore4 = CDbl(Value) End If
  Value = LoadValue("BlackKnight2000", "HighScore4Name")
  If (Value <> "") then gsHighScore4Name = Value End If

  Value = LoadValue("BlackKnight2000", "LoopChampScore")
  If (Value <> "") then gsLoopChamp = CDbl(Value) End If
  Value = LoadValue("BlackKnight2000", "LoopChampName" )
  If (Value <> "") then gsLoopChampName = Value End If

  Value = LoadValue("BlackKnight2000", "RansomLetters")
  If (Value <> "") then gsRansomLettersLit = CDbl(Value) End If
  Value = LoadValue("BlackKnight2000", "Jackpot")
  If (Value <> "") then gsJackpot = CDbl(Value) End If
  Value = LoadValue("BlackKnight2000", "GamesPlayed")
  If (Value <> "") then gsGamesPlayed = CDbl(Value) End If
End Sub

rem Save all the game stats to disk
rem
Sub SaveGameStats
  ' save the 'ram' values to disk using the inbuilt ini file system
  SaveValue "BlackKnight2000", "HighScore1",      gsHighScore1
  SaveValue "BlackKnight2000", "HighScore1Name",  gsHighScore1Name
  SaveValue "BlackKnight2000", "HighScore2",      gsHighScore2
  SaveValue "BlackKnight2000", "HighScore2Name",  gsHighScore2Name
  SaveValue "BlackKnight2000", "HighScore3",      gsHighScore3
  SaveValue "BlackKnight2000", "HighScore3Name",  gsHighScore3Name
  SaveValue "BlackKnight2000", "HighScore4",      gsHighScore4
  SaveValue "BlackKnight2000", "HighScore4Name",  gsHighScore4Name
  SaveValue "BlackKnight2000", "LoopChampScore",  gsLoopChamp
  SaveValue "BlackKnight2000", "LoopChampName",   gsLoopChampName
  SaveValue "BlackKnight2000", "RansomLetters",   gsRansomLettersLit
  SaveValue "BlackKnight2000", "Jackpot",         gsJackpot
  SaveValue "BlackKnight2000", "GamesPlayed",     gsGamesPlayed
End Sub



rem **************************************************
rem **************************************************
rem		Williams High Score Initals Entry Functions
rem **************************************************
rem **************************************************

Dim hsbModeActive
Dim hsEnteredName
Dim	hsEnteredDigits(3)
Dim hsCurrentDigit
Dim hsValidLetters
Dim hsCurrentLetter
Dim hsLetterFlash

Sub HighScoreEntryInit()
	hsbModeActive = True
	hsLetterFlash = 0

	hsEnteredDigits(0) = " "	' blank out the name
	hsEnteredDigits(1) = " "
	hsEnteredDigits(2) = " "
	hsCurrentDigit = 0			' start with first digit

	' define the valid characters allowed in the high score name
	hsValidLetters = " ABCDEFGHIJKLMNOPQRSTUVWXYZ'<>*+-/=\^0123456789`"		' ` is back arrow
	' letter display starts with the first character (space)
	hsCurrentLetter = 1
	' flush any other display's queued up and call the display name function
	DisplayFlushQueue()
	HighScoreDisplayNameNow()

	' set the flash rate/update rate of the high score entry
	HighScoreFlashTimer.Interval = 250
	HighScoreFlashTimer.Enabled = True
End Sub

rem handle the high score entry keys
rem
Sub HighScoreProcessKey(keycode)
	' previous letter
	If keycode = LeftFlipperKey Then
		playsound "WilliamsPrevious"
		hsCurrentLetter	= hsCurrentLetter - 1
		if (hsCurrentLetter = 0) then
			hsCurrentLetter = len(hsValidLetters)
		end if
		HighScoreDisplayNameNow()
	End If
    ' next letter
	If keycode = RightFlipperKey Then
		playsound "WilliamsNext"
		hsCurrentLetter	= hsCurrentLetter + 1
		if (hsCurrentLetter > len(hsValidLetters)) then
			hsCurrentLetter = 1
		end if
		HighScoreDisplayNameNow()
	End If
	' previous letter
	If keycode = PlungerKey Then
		' if not the backarrow then commit the letter
		if (mid(hsValidLetters, hsCurrentLetter, 1) <> "`") then
			playsound "WilliamsEnter"
			hsEnteredDigits(hsCurrentDigit) = mid(hsValidLetters, hsCurrentLetter, 1)
			hsCurrentDigit = hsCurrentDigit + 1
			' if that was the last digit, then commit the name
			if (hsCurrentDigit = 3) then
				HighScoreCommitName()
			else
				HighScoreDisplayNameNow()
			end if
		else
			playsound "WilliamsEsc"
			hsEnteredDigits(hsCurrentDigit) = " "
			if (hsCurrentDigit > 0) then
				hsCurrentDigit = hsCurrentDigit - 1
			end if
			HighScoreDisplayNameNow()
		end if
	end if
End Sub

rem display the currently entered initals right now with no flashing letter
rem
Sub HighScoreDisplayNameNow()
	' turn off the timer
	HighScoreFlashTimer.Enabled = False
	' do an update now (by setting hsLetterFlash to 0 it ensures that the letter is
	' displayed and not the flash character "_"
	hsLetterFlash = 0
	HighScoreDisplayName()
	' reset the timer (also resets the interval)
	HighScoreFlashTimer.Enabled = True
End Sub

rem Display the Currenly entered name on the screen, with the current letter flashing
rem
rem 	1234567890123456
rem 	ENTER YOUR NAME
rem 	    > AAA <
Sub HighScoreDisplayName()
	Dim i
	Dim TempTopStr
	Dim TempBotStr

	' do the top line (simple enough)
	TempTopStr = "ENTER YOUR NAME "
	DispCurrentTopLine = TempTopStr
	TextBoxTop.Text    = TempTopStr

	' now do the bottom line (a little more complex)
	TempBotStr = "    > "

	' if then first digit has been entered then display that
	if (hsCurrentDigit > 0) then
		TempBotStr = TempBotStr & hsEnteredDigits(0)
	end if
	' dito for second digit
	if (hsCurrentDigit > 1) then
		TempBotStr = TempBotStr & hsEnteredDigits(1)
	end if
	' and last digit
	if (hsCurrentDigit > 2) then
		TempBotStr = TempBotStr & hsEnteredDigits(2)
	end if

	' if not all the digits entered then make the current one flash
	if (hsCurrentDigit <> 3) then
		if (hsLetterFlash <> 0) then
			TempBotStr = TempBotStr & "_"
		else
			TempBotStr = TempBotStr & mid(hsValidLetters, hsCurrentLetter, 1)
		end if
	end if
	' pad out the rest of the string if not on the last letter
	if (hsCurrentDigit < 1) then
		TempBotStr = TempBotStr & hsEnteredDigits(1)
	end if
	if (hsCurrentDigit < 2) then
		TempBotStr = TempBotStr & hsEnteredDigits(2)
	end if
	TempBotStr = TempBotStr & " <    "
	' write it to the display
	DispCurrentBottomLine = TempBotStr
	TextBoxBottom.Text 	  = TempBotStr
End Sub

rem the timer which refreshes the high score entry screen has expired, refreash the display
rem and start again
rem
Sub HighScoreFlashTimer_Timer()
	HighScoreFlashTimer.Enabled = False
	hsLetterFlash = hsLetterFlash + 1
	if (hsLetterFlash = 2) then
		hsLetterFlash = 0
	end if
	HighScoreDisplayName()
	HighScoreFlashTimer.Enabled = True
End Sub

rem The High Score name has been entered, do what ever the game requires (generally put it in the
rem high score table ;-)
rem
Sub HighScoreCommitName()
	' turn off the timer
	HighScoreFlashTimer.Enabled = False
	' turn of the mode flasg
	hsbModeActive = False
	' save the entered name
	hsEnteredName = hsEnteredDigits(0) & hsEnteredDigits(1) & hsEnteredDigits(2)
	' if the player has entered in all blanks then change it to BLK
	if (hsEnteredName = "   ") then
		hsEnteredName = "BLK"
	end if

	' ADD CUSTOM GAME CODE HERE

	' have we made the top score
	if (Score > gsHighScore1) then
		' move the scores down
		gsHighScore4 	 = gsHighScore3
		gsHighScore4Name = gsHighScore3Name
		gsHighScore3 	 = gsHighScore2
		gsHighScore3Name = gsHighScore2Name
		gsHighScore2 	 = gsHighScore1
		gsHighScore2Name = gsHighScore1Name
		' put in the new one
		gsHighScore1 	 = Score
		gsHighScore1Name = hsEnteredName
		' award an extra credit if not in free play
	else
		if (Score > gsHighScore2) then
			' move the scores down
			gsHighScore4 	 = gsHighScore3
			gsHighScore4Name = gsHighScore3Name
			gsHighScore3 	 = gsHighScore2
			gsHighScore3Name = gsHighScore2Name
			' put in the new one
			gsHighScore2 	 = Score
			gsHighScore2Name = hsEnteredName
		else
			if (Score > gsHighScore3) then
				' move the scores down
				gsHighScore4 	 = gsHighScore3
				gsHighScore4Name = gsHighScore3Name
				' put in the new one
				gsHighScore3 	 = Score
				gsHighScore3Name = hsEnteredName
			else
				if (Score > gsHighScore4) then
					' put in the new one
					gsHighScore4 	 = Score
					gsHighScore4Name = hsEnteredName
				end if
			end if
		end if
	end if

	' did the player make a high score and/or loop champion
	if (MaxLoopsThisGame > gsLoopChamp) then
		gsLoopChamp		= MaxLoopsThisGame
		gsLoopChampName	= hsEnteredName
		' award an extra credit if not in free play
	end if

	' save the high score table back to disk
  SaveGameStats()

	' and back to standard attract mode displays
	DisplayFlushQueue()
	StartAttractModeDisplays()
End Sub



rem **************************************************
rem **************************************************
rem   MagnaSave Simulator
rem   Attraction Physics Engine by Dorsola
rem **************************************************
rem **************************************************

class cvpmMagnet
	private cX, cY, cStrength, cRange
	private cBalls
	private cTempX, cTempY

	Private Sub Class_Initialize()
		set cBalls = CreateObject("Scripting.Dictionary")
		cRange = 1
		cStrength = 0
	End Sub

	Public Sub InitMagnet( aTrigger, inStrength )
		cX        = aTrigger.X
		cY        = aTrigger.Y
		cRange    = aTrigger.Radius
		cStrength = inStrength
	End Sub

	Public Sub MoveTo( inX, inY )
		cX = inX
		cY = inY
	End Sub

	Public Property Get X : X = cX : End Property
	Public Property Get Y : Y = cY : End Property
	Public Property Get Strength : Strength = cStrength : End Property
	Public Property Get Size : Size = cRange : End Property
	Public Property Get Range : Range = cRange : End Property
	Public Property Get BallArray : BallArray = cBalls.Keys : End Property

	Public Property Let X( inX ) : cX = inX : End Property
	Public Property Let Y( inY ) : cY = inY : End Property
	Public Property Let Strength( inStrength ) : cStrength = inStrength : End Property
	Public Property Let Size( inSize ) : cRange = inSize : End Property
	Public Property Let Range( inSize ) : cRange = inSize : End Property

	Public Sub AddBall( aBall ) : cBalls.Add aBall,0 : End Sub
	Public Sub RemoveBall( aBall ) : cBalls.Remove(aBall) : End Sub

	Public Sub ProcessBalls()
		Dim tempObj
		for each tempObj in cBalls.Keys : AttractBall tempObj : next
	End Sub

	Public Function GetDist( aBall )
		if aBall is Nothing then
			GetDist = 100000
		else
			cTempX = aBall.X - cX
			cTempY = aBall.Y - cY
			GetDist = Sqr(cTempX*cTempX + cTempY*cTempY)
		end if
	End Function

	Public Sub AttractBall( aBall )
		if aBall is Nothing then Exit Sub
		Dim Dist
		Dist = GetDist(aBall)
		if Dist > cRange then Exit Sub

		' Attract ball toward magnet center (cX,cY).

		' Attraction force is determined by distance from center, and strength of magnet.

		Dim Force, Ratio
		Ratio = Dist / (1.4*cRange)		'1.5

		' TODO: Figure out how to dampen the force when ball is near center and
		' at low velocity, so that balls don't jitter on the magnets.
		' Also shore up instability on moving magnet.

		if Dist < 20 And cStrength >= 15 then	' ...If we're really close to center and the magnet is really strong...
			aBall.VelX = 0 : aBall.VelY = 0
      aBall.X = cX : aBall.Y = cY
		else
			if Dist = 0 then
				Force = 0
			else
				Force = cStrength * exp(-0.2/Ratio)/(Ratio*Ratio*56)
			end if
		    aBall.VelX = (aBall.VelX - cTempX * Force / Dist) * 0.985
		    aBall.VelY = (aBall.VelY - cTempY * Force / Dist) * 0.985
		End if
	End Sub
End Class

