;--------------------------------------
;    -~=  PINBALL DREAMS C64  =~-     -
;                                     -
; code by      WVL      /Xenon        -
;              Jackasser/Instinct     -
; music by     GRG      /Shape        -
;              Britelite/Dekadence    -
; graphics by  Jailbird /Booze Design -
;              TMR      /Cosine       -
;                                     -
; thanks to :                         -
;   Oswald (for your pixelprog!)      -
;   Krill  (for some suggestions)     -
;                                     -
; copyright notice :                  -
; There's no copyright on this piece  -
; of codework. It or parts of it may  -
; be used in non-commercial ways if   -
; all original authors are named.     -
; The copyright of the original art   -
; as seen in the original Pinball     -
; Dreams, however, stays with their   -
; original authors/respective owners. -
;--------------------------------------

;new flipper code :
;correct flipper collision speed

;--------------------------------------------------------
;note : this file is to be assembled using 6502tass.exe -
;--------------------------------------------------------

;---------------------------------------------------------------------------------------------
;estimated free memory :
;
;     $0300-$0600  =  3
;     $5800-$5c00  =  4
;     $8b00-$8c00  =  1
;     $9000-$a000  = 16
;     $d700-$de80  =  7.5
;     $e200-$e3d0  =  1.75    ;also 2x 16 bytes in the other 2 color maps free!
;     $f910-$ffff  =  7
;                    ----+
;                    40.25 blocks free
;---------------------------------------------------------------------------------------------

;---------------------------------------------------------------------------------------------
;estimated extra memory use :
;
;display data (mask)       : 1-8 blocks
;display sprites           :   4 blocks (2*8 sprites, double buffered)
;display chardata (RLE-ed) :   6 blocks?
;display code              :   4 blocks?
;extra music               :   8 blocks?
;gamecode                  :   8 blocks?
;finish engine             :   4 blocks?
;                            ----------+
;total                        35-42 blocks?
;---------------------------------------------------------------------------------------------

;--------------------------------------------------------------------------
;-Dot matrix display requires the following memory (all VIC-bank relative)-
;--------------------------------------------------------------------------
;lda #$ff
;sta $39ff
;sta $3fff
;.repeat 32,I
;        sta $0000+I*8+7
;        sta $0100+I*8+7
;        sta $0800+I*8+7
;        sta $0900+I*8+7
;        sta $1000+I*8+7
;        sta $1100+I*8+7
;        sta $1800+I*8+7
;        sta $1900+I*8+7
;.endrep
;Plus one screen with 8 bytes holding the sprite pointers

;-------------
;main options-
;-------------

;if TABLE==0 => Nightmare
;if TABLE==1 => Ignition

KEEPTIME        = 0    ;keep time during game, useful for keeping track of collisions
KEEPFLIPPERHIS  = 0    ;keep history of flipper collisions (needs KEEPTIME = 1)

SHOWRASTERTIME  = 0    ;show used rastertime in the border
WARNLOWRASTER   = 0    ;changes bordercolor if there was not enough rastertime
SENSERASTERTIME = 0    ;keep track of used rastertime

KEEPHISTORY     = 0    ;keep collision history

JOYCONTROL      = 1    ;make ball controlable by joystick, eats 91 bytes!

DAMPING         = 1    ;turn damping on/off
PLAYMUSIC       = 1    ;turn music on/off
flipperframes   = 13   ;# of frames in flipper animation

;------------------------------------------------------------
; changehistory :                                           -
;                                                           -
; 02-09-2003 : -start of history (not the code ;-))         -
;              -worked on comments in code                  -
; 03-09-2003 : -made system to display info on screen       -
;              -made normal/debug mode                      -
;              -made xtra ball-sprite images & adjusted     -
;                 display screen for the clipping           -
;              -made temporary mock-up clip routine         -
;              -rounded-up x,y position of ball,            -
;                 to avoid 'flickering' of ball             -
;              -made new REAL clipping routine              -
; 06-09-2003 : -made the ball move pixel by pixel           -
;                 from the old to the new position          -
;                 this is needed for collision              -
;                 detection                                 -
;              -added collision detection :D                -
; 07-09-2003 : -started work on 'redefinable' keys for      -
;                 moving the flippers                       -
;              -disabled the restore key                    -
; 08-09-2003 : -added 8 more bits to ballposition/speed     -
;              -updated gravity routine to 8 more bits      -
;                accuracy                                   -
;              -same for friction routine                   -
;              -same for ballmovement routine               -
;              -wrote code to read keyboard, works FINE     -
;                but there's a problem with pc-             -
;                keyboards when pressing multiple keys      -
;                DO NOT USE BOTH SHIFT KEYS FOR THE         -
;                FLIPPERS ON PC!!! works gr8 on 64.         -
;              -made clip-routine compatible with >1        -
;                layer                                      -
; 09-09-2003 : -put in a test bounce routine, so the        -
;                ball bounces from walls now                -
; 10-09-2003 : -played a bit with a tool to make the        -
;                wallmaps. Also did some estimates on       -
;                the size each wallmap probably is          -
;                going to be -> around 40 blocks each.      -
;                OUCH!                                      -
; 15-09-2003 : -increased accuracy in angle routine         -
; 22-09-2003 : -fixed last of the routines to consider      -
;                layer                                      -
; 28-09-2003 : -made a 24bit x 8bit multiply routine to     -
;                calculate speeds after collisions          -
; 07-01-2004 : -fixed a lot of bugs in the collision        -
;                routines, added collision history          -
; 08-01-2004 : -added a new way of clipping the ball        -
;                which allows more colors, without          -
;                eating more rastertime!!  uses one         -
;                invisible sprite though :(                 -
;              -finished the collision routine, looks       -
;                REALLY GOOD, but became slower a lot.      -
; 10-01-2004 : -major bugfixing today...                    -
; 11-01-2004 : -added bumpers to the engine                 -
; 12-01-2004 : -added a wall around the screen edge         -
;                added 128,NTSC & SCPU detection            -
; 14-01-2004 : -engine now also checks for crsr-down key    -
;              -added ball-shooter code (still has a bug)   -
;              -added a shooter-guide for testing purpose   -
;              -bugfixed collision routine (more freezing)  -
;              -made ball able to pass walls in one         -
;                 direction,while reflecting from the other -
;                 side                                      -
;              -reduced friction by a factor 2,much better  -
; 15-01-2004 : -made the shooter more spring-like and       -
;                 removed the bug (in a not very nice way)  -
;              -improved test-environment a bit             -
; 18-01-2004 : -bugfixing,reworking,making engine faster    -
; 20-01-2004 : -added button-collision-press code           -
;              -added ball-spin                             -
; 28-01-2004 : -added IRQ's, opened the borders, added the  -
;                 background bitmap and AGSP                -
;              -added a small scrollroutine,without copying -
; 30-01-2004 : -updated the PDtool to process and crunch    -
;                 the clipmaps, put resulting map in game   -
;              -made some routines a bit faster & smaller   -
; 09-02-2004 : -finished the hardware scroller :D and some  -
;                 more optimizations all around!            -
;              -added layer-change & button-roll-over code  -
;              -removed system that showed data on screen   -
;              -removed unused code,opcodes,data            -
; 11-02-2004 : -updated PDtool for swapping $0400/$d800     -
;                 colors, pack-optimizing the bitmap and    -
;                 writing bitmap files directly usable in   -
;                 the game engine                           -
;              -moved bitmap-data and tune outside of the   -
;                 sourcecode.. this cleans stuff up a lot!  -
;              -fixed ball sprite image, was bugged due to  -
;                 the scroller                              -
;              -added example light engine!! will do all    -
;                 lights when finishing the game.. DIE!     -
; 25-03-2004 : -made the collisionengine faster again       -
;              -removed a bug in the collisionhistory       -
; 15-07-2004 : -added real-world data thanks to Jackassers  -
;                 tool, I'm amazed it actually works :)     -
; 16-07-2004 : -made $d800 copyroutine faster and removed   -
;                 a serious bug in it, which caused keyboard-
;                 problems                                  -
;              -thought of a better more memory-efficient   -
;                 way of storing the collision data         -
; 20-07-2004 : -fixed angle accuracy during collisions @ low-
;                 speeds                                    -
;              -fixed another bug in the routine that       -
;                 did the collision calculations (nasty 1)  -
; 05-09-2004 : -added routine that handles moving the       -
;                 flippers                                  -
;              -added all the animation frames to the game  -
; 07-09-2004 : -fixed spritepointers showing in bitmap :)   -
;              -made flippers and spring scroll             -
;              -changed scroll speeds so you see the        -
;                 flippers earlier                          -
;              -added the shooterspring-sprite              -
;              -some small fixes to the flipper animation   -
; 20-09-2004 : -reworked PDtool to produce smaller clipmap  -
;                 files. Saves $88 bytes now..              -
; 21-09-2004 : -been working on the clipmap for the 2nd     -
;                 layer. This has been fitted inside the map-
;                 for the first layer.                      -
;              -model detection routines have been removed, -
;                 they can go in the menu/intro             -
;              -removed copyd800 routine                    -
; 25-09-2004 : -layer 2 collision data put into the engine  -
;              -small bugfixes in layer-switch routine      -
;              -clipmap for layer 2 put into layer 1,       -
;                 together with some logic, works fine and  -
;                 saves memory like crazy                   -
;              -collision data has been revised, a lot of   -
;                 bytes saved!                              -
; 26-09-2004 : -removed some table-generators to save bytes -
;              -fixed table-position at engine-start        -
; 01-10-2004 : -some fixes and speedups in the collision    -
;                 routine, angle-calculation routines, etc  -
; 27-12-2004 : -rewrote gravitymap routines to save 1       -
;                 byte/datarow, like the collisionmap       -
; 28-12-2004 : -added 1 extra bit of accuracy to sine       -
;                 table, didnt cost memory or cycles :)     -
;              -rewrote friction routine for extra accuracy -
;                 saved some cycles and bytes as well       -
;              -optimized multiplication routine, saved 115 -
;                 bytes!! and some cycles :)                -
; 29-12-2004 : -optimized calcangle routine a bit           -
; 01-01-2005 : -happy new year!!!                           -
;              -optimized addgravity routine, saved 85 bytes-
;              -saved some more bytes by overlapping some   -
;                 tables                                    -
;              -sped up multiply24x8 by 24 cycles, saved    -
;                 bytes as well :)                          -
;              -fixed bug in collision engine, said rol     -
;                 instead of ror.. stupid.. me bad.         -
;              -fixed a bug in the calcangle routine that   -
;                 i f*cked up 3 days ago ;(   ME BAD!!!     -
; 02-01-2005 : -added routine to dissipate some energy after-
;                 every collision, right now as test setting-
;                 4% energy is lost after each collision    -
;              -made multiplication routine a bit faster    -
; 10-01-2005 : -prepared the code & compile.bat to put      -
;                the shifted ball sprites images into the   -
;                bitmap data..                              -
;              -removed genspriteimages & balldata,saved    -
;                 about $13e bytes!                         -
; 11-01-2005 : -put shifted ball sprite images into the     -
;                background image, saved $480 bytes :)      -
; 14-01-2005 : -improved calcclippedsprite routine a bit    -
;                 -> $21 bytes, >60 cycles                  -
; 17-01-2005 : -made some tool to compress clipmap data even-
;                 more, also see my 'challenge' on csdb!    -
;                 saved about $318 bytes!!!                 -
; 19-01-2005 : -made inclusion of binary files use relative -
;                adressing.. -> will make it easier for dev -
;                on other computers.                        -
; 07-02-2005 : -removed energy loss during collision i put  -
;                 in last week, it didn't work like i       -
;                 expected..                                -
;              -put in new energy removal scheme, that can  -
;                 work with different kind of wall          -
;                 materials!! :D Now the only thing left to -
;                 add for correct ball physics is spin      -
;                 around the z-axis..                       -
; 11-02-2005 : -optimized some code in collision engine..   -
; 12-02-2005 : -put materials in specialmap! :)             -
;              -made damping dependant on wall material     -
;              -added 2nd layer to specialmap! needed as we -
;                 store material data in that map now       -
;              -removed the old bumper code.. finally ;-)   -
;              -changed order in collision engine, gives    -
;                 some speed ups, especially while rolling  -
;                 along walls (which eats rastertime)       -
;              -wrote new bumper code that works a bit      -
;                 simpler. For fun i activated the lower 2  -
;                 bumpers, lotsa FUN watching them work! :D -
; 15-02-2005 : -made dirty c64 tool that converts collision -
;                 data for flippers to a different format   -
;              -made dos tool that converts the new format  -
;                 into includable text                      -
;              -included testdata into engine ;-)           -
; 16-02-2005 : -Jackasser made a raw output option in the   -
;                 walleditor, which allowed me to delete    -
;                 the c64 tool i just made and include      -
;                 its function in the DOS tool.. This makes -
;                 it much easier to mess around with..      -
; 18-02-2005 : -added collision detection between flippers  -
;                 and ball. Still needs some tweaks, but    -
;                 looking very promising! :D                -
;              -tweaked flipper collision-generator-tool    -
; 01-03-2005 : -made option to track in-game time           -
; 02-03-2005 : -made optional collision history for flippers-
; 04-03-2005 : -fixed some bugs in flipper collisions       -
;                \- especially a bug that had to do with the-
;                   length of the flippers                  -
;              -increased gravity, to match the original pd -
;                 more closely. much more arcade action ;D  -
;              -updated flipper collision data to remove    -
;                 hole between flipper and walls.           -
;              -activated upper bumpers                     -
; 10-03-2005 : -fixed a small bug in the flipper routine    -
;              -some small optimizations                    -
;              -made ball stop 'shaking' when trapped       -
; 12-03-2005 : -made 75%,87.5%,etc damping options!         -
;                 flippers now have 87.5% damping.          -
; 13-03-2005 : -placed $d800 scroller into irq to get rid of-
;                scroll bugs                                -
;              -made the total gameloop a bit less critical -
;                 for rastertime use by allowing it to      -
;                 "borrow" cycles from the previous and next-
;                 frame for certain routines.               -
;              -edited flipper collision data again         -
;              -fixed a bug spotted by dark0ne, it turned   -
;                 out the collision routine wasn't reading  -
;                 the specialmap correctly in the 2nd layer -
; 14-03-2005 : -optimized clipmap & fixed a small 'hole'    -
;                 saved 22 bytes..                          -
; 09-04-2005 : -last week i changed the clip routine,the    -
;                 scrollroutines and some irq's, so no      -
;                 double bitmap lines are needed.. saves    -
;                 about 8 blocks of memory!                 -
;              -all of this caused some bugsies in the irqs -
;                 which i'll fix later or force Jackasser to-
; 12-04-2005 : -put Jackassers new scroll code into the game-
;                 also the display-sprites have been put in -
;                 as a result the viewable area became 6    -
;                 pixels bigger!                            -
; 13-04-2005 : -fixed a small bug in the new scroller       -
; 04-05-2005 : -made a small initialiser before decrunching -
;              -added timing stabilizer & restore protect to-
;                 the initialiser.                          -
; 25-06-2005 : -fixed a bug in the collision routines..     -
; 26-06-2005 : -found and fixed another bug in the collision-
;                 routines.. again caused by stupid mistakes-
; 01-07-2005 : -that ugly crashing bug came back again, I   -
;                 think I finally found it and fixed it by  -
;                 changing the decrunch settings of PuCrunch-
;              -added a small fix for some stupid very      -
;                 rare and specific case that can lock up   -
;                 the engine                                -
; 02-07-2005 : -stupid crashing bug is STILL there.. dunno  -
;                 what it could be :-(                      -
;              -fixed the 'bug' that the ball could fall    -
;                 through the flipper a bit. It was caused  -
;                 by the angle-tool depending on color-depth-
;                 setting of the screen, and my screen was  -
;                 set to 16 bit during first export :P      -
;                 setting it to 32 bit fixed the problems :)-
; 18-08-2005 : -Jackasser updated the code of the display,  -
;                 so it now also produces the black grid,   -
;                 giving the display a hi-res feeling.      -
; 20-08-2005 : -cleaned up the sourcecode a bit (tabs-mess) -
;              -wrote a small tool that identifies all empty-
;                 areas in the bitmaps and outputs this in a-
;                 sourcecode file                           -
; 21-08-2005 : -wrote a small tool that makes the data for  -
;                 the ball sprites. Now it's possible to    -
;                 change how the ball looks in a couple of  -
;                 seconds! :)                               -
;              -wrote a tool that replaces the              -
;                 'prepareclippointers'-routine, saves some -
;                 bytes (about 32..) + a bit faster start   -
;                 of the game!                              -
;              -modified the tool that produces data for the-
;                 flipper collisions, data is now 120 bytes -
;                 smaller! data also uses sbc-style now!    -
; 22-08-2005 : -fixed a small bug in the display code, we   -
;                 overwrote $f9ff, but didnt write the      -
;                 original data back!                       -
;              -improved page alignment of irq-code         -
;              -changed fliptosource tool a bit more, saved -
;                 another 13 bytes on the output :)         -
;              -fixed a little bug i made yesterday         -
;              -optimized flipper routines a bit..          -
; 01-11-2005 : -optimized the wall angles of nightmare      -
; 08-11-2005 : -added compilation of Ignition level to the  -
;                 game! :)    LAUNCH!                       -
;              -made lots of data file for Ignition :)      -
; 09-11-2005 : -added a feature to PDtool to fill unused    -
;                 colors in the bitmap with $d021 value     -
;              -DIE lights are interactive now              -
; 10-11-2005 : -WARP buttons are active now :)              -
;              -buttons are pulsed on press now             -
;              -one-way-pass gates are now working in       -
;                 Ignition :)                               -
; 11-11-2005 : -added update nightmare gfx                  -
;              -added gate to nightmare, and moved flippers -
;                 down a bit                                -
;              -added ball lost walltype                    -
; 13-11-2004 : -extended flipper some pixels at the bottom  -
;              -started on rewriting flipper behaviour, so  -
;                 the ball can be smacked HARDER :)         -
;------------------------------------------------------------

;------------------------------------------------------------------------------------
; to do :                                                                           -
; (things marked with a 1 are considered most important right now or easy to add)   -
; (things with a - infront are not very important right now)                        -
;                                                                                   -
;       !!  small irq bugs.. (have Jackasser fix this)                              -
;                                                                                   -
;        ! make minimum normalspeed check to activate bumpers                       -
;       !! compile sprites into bitmap before charfill tool!                        -
;       !! change flipper behaviour                                                 -
;        ? add z-ballspin to the engine                                             -
;        ! maybe test if rastertime free and do calcangle?                          -
;       !! complete display routine                                                 -
;        ~ write + fix detection routines for REU/AR/RR/EMULATOR/16&64KB VDC        -
;        ~ clean up sourcecode,and add more comments                                -
;        ~ improve speed                                                            -
;        ~ make keys for left/right flipper selectable!                             -
;        ~ buffer menu/game to ar/rr/reu/vdc if possible                            -
;        ~ add pause game                                                           -
;        ~ make menu + intro                                                        -
;        ~ handle all other keys, like space/pause/stop                             -
;                                                                                   -
; memory saving ideas                                                               -
;                                                                                   -
;        - use flipper data in mirror way (frame 2 is mirror of frame 8)            -
;        ! optimize wallangles with new import/export function of editor            -
;        - use the 16 bytes left in two of the charscreens.. can we think of a good -
;            table to put in there? (save 32 bytes) (score? :)                      -
;        - use sine-table for speed of bitmap-scrolling or some function?           -
;        ? try and optimize clipmask for new charpack tool?                         -
;        ? make collision-data relative?                                            -
;        ? mix clipchars and display-mask?                                          -
;        ? different multiplication routine?                                        -
;        ? remove tables?                                                           -
;                                                                                   -
;------------------------------------------------------------------------------------

;---------------------------------------------------------------------------------------

;-----------------------
; pointers for copying -
;-----------------------

  tabley    = $06   ;table position in chars
  tableyold = $07   ;position in previous frame
  d018now   = $08

;--------------------------------------------
; speed for change of reference system      -
; during collision between ball and flipper -
;--------------------------------------------

  xflipspeedhigh = $09
  xflipspeedlow  = $0a
  xflipspeedfrc  = $0b
  yflipspeedhigh = $0c
  yflipspeedlow  = $0d
  yflipspeedfrc  = $0e
  flippercollision = $0f

;--------------------------------------
; speeds during collision calculation -
;--------------------------------------

  normalxlow  = $10  ;x component of ball speed normal to wall
  normalxfrc  = $11
  normalxfrc2 = $12

  normalylow  = $13  ;y component of ball speed normal to wall
  normalyfrc  = $14
  normalyfrc2 = $15

  absspdxhi   = $16  ;temporary storage high component of new speeds during calculation
  absspdyhi   = $17

  result      = $18
               ;$19
               ;$1a

;------------
; game time -
;------------

  timehigh = $1b
  timelow  = $1c

  flipframe = $1d

;-----------------
; temporary data -
; for use in all -
; routines       -
;-----------------

  low      = $20
  high     = $21
  low2     = $22
  high2    = $23
  low3     = $24
  high3    = $25
  temp     = $26
  temp2    = $27
  temp3    = $28
  atemp    = $29
  xtemp    = $2a
  ytemp    = $2b
  irqtemp  = $2c
  irqtemp2 = $2d
  irqtemp3 = $2e
  irqlow   = $2f   ;same as low/high, but used inside irq's
  irqhigh  = $30

  normalx2low  = $31  ;x component of ball speed normal to wall
  normalx2frc  = $32
  normalx2frc2 = $33

  normaly2low  = $34  ;y component of ball speed normal to wall
  normaly2frc  = $35
  normaly2frc2 = $36

;------------
; ball data -
;------------

  ;----------------
  ; ball position -
  ;----------------

  ballxhi   = $40  ;high coordinate of x-position
  ballxlow  = $41  ;low coordinate of x-position
  ballxfrc  = $42  ;fractional (x/256) part of x-position
  ballxfrc2 = $43  ;fractional (x/65536) part of x-position
  ballyhi   = $44  ;same
  ballylow  = $45  ;...
  ballyfrc  = $46  ;...
  ballyfrc2 = $47  ;...
  charscreenrow = $48

  ;--------------------
  ; ball in layer 0/1 -
  ;--------------------

  layer = $49  ;0=bottom layer, 1=top layer ('ducts')

  ;----------------------------
  ; ball speed (pixels/frame) -
  ;----------------------------

  spdxhi   = $4a
  spdxlow  = $4b
  spdxfrc  = $4c
  spdxfrc2 = $4d
  spdyhi   = $4e
  spdylow  = $4f
  spdyfrc  = $50
  spdyfrc2 = $51

  gravityforce = $52

  ;----------------
  ; ball rotation -
  ;----------------

  omegaxhi  = $53     ;spin left/right
  omegaxlo  = $54
  omegaxfr  = $55
  omegaxfr2 = $56
  omegayhi  = $57     ;spin up/down
  omegaylo  = $58
  omegayfr  = $59
  omegayfr2 = $5a

  ;-------------------------
  ; speed of contact point -
  ;-------------------------

  ;this is the speed of the ball where it actually is in touch with the table
  ;meaning the speed of the ball, including all spins!

  spd2xhi   = $5b
  spd2xlow  = $5c
  spd2xfrc  = $5d
  spd2xfrc2 = $5e
  spd2yhi   = $5f
  spd2ylow  = $60
  spd2yfrc  = $61
  spd2yfrc2 = $62

  angle     = $63  ;angle in which the ball is traveling OR angle in which the CONTACT point is moving

  ;----------------
  ; ball clipping -
  ;----------------

  clipx  = $64
  ballx2 = $65      ;position of left top of the ball in chars
  bally2 = $66

  ;------------
  ; move ball -
  ;------------

  timeinaframe = $67
  addtotime    = $68
  absspdxlow   = $69
  absspdxfrc   = $6a
  absspdxfrc2  = $6b
  absspdylow   = $6c
  absspdyfrc   = $6d
  absspdyfrc2  = $6e

  ;-----------------------
  ; pinball machine data -
  ;-----------------------

  leftflipper  = $6f     ;registers for keys
  rightflipper = $70     ;->0 when not pressed
  tiltkey      = $71     ;any other value when pressed
  pausekey     = $72
  exitkey      = $73
  crsrdown     = $74

  ;------------------
  ; collision data  -
  ;------------------

  collided     = $75     ;remembers if the ball already collided this frame
                         ;0 = not collided, 1 = only angle calculated, $80 = both angle and speed calculated

  ;------------------
  ; multiplyroutine -
  ;------------------

  mult8        = $76
  mult24hi     = $77
  mult24lo     = $78
  mult24frc    = $79

  flippercollisionhistlow  = $7a
  flippercollisionhisthigh = $7b
  flipperhit               = $7c

  ;--------------
  ; misc things -
  ;--------------

  collisionhistorylow = $80
  collisionhistoryhi  = $81
  computermodel       = $82
  abstaken            = $83
  special             = $84    ;byte for special wall types (buttons/bumpers)
  material            = $85    ;wall material number
  oldx2               = $86
  oldx                = $87
  oldy                = $88
  startgameloop       = $89
  yrowlow             = $8a
  yrowhi              = $8b

  ;-----------------
  ; table position -
  ;-----------------

  tableylow  = $8c
  tableyhigh = $8d

  ;-----------------
  ; flipper speeds -
  ;-----------------

  leftspeed  = $8e
  rightspeed = $8f

  ;----------
  ; buttons -
  ;----------

  .if TABLE=0
    buttons  = $90
    die1     = $90
    die2     = $91
    die3     = $92
    leftflipperbut  = $93
    rightflipperbut = $94
    nrofbuttons = 5
  .fi
  .if TABLE=1
    buttons     = $90
    warp1       = $90
    warp2       = $91
    warp3       = $92
    warp4       = $93
    leftflipperbut  = $94
    rightflipperbut = $95
    nrofbuttons = 6
  .fi

  ;---------
  ; lights -
  ;---------

  .if TABLE=0
    lights    = $a0
    dielight1 = $a0
    dielight2 = $a1
    dielight3 = $a2
    nroflights = 3
  .fi
  .if TABLE=1
    lights = $a0
    warplight1 = $a0
    warplight2 = $a1
    warplight3 = $a2
    warplight4 = $a3
    nroflights = 4
  .fi

  ;------------
  ; game data -
  ;------------

  .if TABLE=0
    dielights = $b0
    dietime   = $b1
  .fi

  ;----------------------------------------------
  ; precalced VIC values for sprite multiplexer -
  ;----------------------------------------------

  _D015                = $c0                ; Sprite enable
  _D048                = $c1                ; Ball X, $d000,$d004,$d008
  _D159                = $c2                ; Ball X, $d001,$d005,$d009
  _D003                = $c3                ; Shooter Y
  _D006                = $c4                ; Left flipper arm X (big)
  _D007                = $c5                ; Left flipper arm Y (big)
  _D00A                = $c6                ; Left flipper arm X (small)
  _D00B                = $c7                ; Left flipper arm Y (small)
  _D00C                = $c8                ; Right flipper arm X (small)
  _D00D                = $c9                ; Right flipper arm Y (small)
  _D00E                = $ca                ; Right flipper arm X (big)
  _D00F                = $cb                ; Right flipper arm Y (big)
  _D010                = $cc                ; High X for all sprites

;----------------------------------------------
; FLD and LCR variables                       -
;----------------------------------------------

  FLDY     = $d0
  COARSEX  = $d1

;--------------------------------------------------------------------------------------

;------------------------
;add bitmaps to the game-
;------------------------

.if TABLE=0
  *=$a000
  bitmap0
    .binary .\includes\nightmar\bins\bmp0.bin
  *=$6000
  bitmap1
    .binary .\includes\nightmar\bins\bmp1a.bin
  *=$7f40
    .binary .\includes\nightmar\bins\bmp1b.bin
  *=$c000
  bitmap2
    .binary .\includes\nightmar\bins\bmp2a.bin
  *=$de80
    .binary .\includes\nightmar\bins\bmp2b.bin
  *=$8c00
    .binary .\includes\nightmar\bins\bmp0col.bin
  *=$5c00
    .binary .\includes\nightmar\bins\bmp1cola.bin
  *=$5fe8
    .binary .\includes\nightmar\bins\bmp1colb.bin
  *=$e000
    .binary .\includes\nightmar\bins\bmp2cola.bin
  *=$e3d0
    .binary .\includes\nightmar\bins\bmp2colb.bin

  *=$1000
  tune
    .binary .\includes\nightmar\bins\tune.bin
  *=$d000
  flippersprites
    .binary .\includes\nightmar\bins\flippers.bin
  *=$8600
  memd800colors
    .binary .\includes\nightmar\bins\d800col.bin
  *=$e480
  springsprite
    .binary .\includes\nightmar\bins\spring.bin

.fi
.if TABLE=1
  *=$a000
  bitmap0
    .binary .\includes\ignition\bins\bmp0.bin
  *=$6000
  bitmap1
    .binary .\includes\ignition\bins\bmp1a.bin
  *=$7f40
    .binary .\includes\ignition\bins\bmp1b.bin
  *=$c000
  bitmap2
    .binary .\includes\ignition\bins\bmp2a.bin
  *=$de80
    .binary .\includes\ignition\bins\bmp2b.bin
  *=$8c00
    .binary .\includes\ignition\bins\bmp0col.bin
  *=$5c00
    .binary .\includes\ignition\bins\bmp1cola.bin
  *=$5fe8
    .binary .\includes\ignition\bins\bmp1colb.bin
  *=$e000
    .binary .\includes\ignition\bins\bmp2cola.bin
  *=$e3d0
    .binary .\includes\ignition\bins\bmp2colb.bin

  *=$1000
  tune
    .binary .\includes\ignition\bins\tune.bin
  *=$d000
  flippersprites
    .binary .\includes\ignition\bins\flippers.bin
  *=$8600
  memd800colors
    .binary .\includes\ignition\bins\d800col.bin
  *=$e480
  springsprite
    .binary .\includes\ignition\bins\spring.bin

.fi
;--------------
;start of code-
;--------------

         * = $1d00

tableinit
        sei
        lda #$35
        sta $01

        lda #$dd
        ldx #63
fillsprite13
        sta $fc00,x
        dex
        bpl fillsprite13

        jsr clearbuttons    ;sets buttons and lights to off
        jsr lightscode      ;turn lights off in bitmap
        jsr clearscore

        ldx #$ff            ;port dc00 = outputs
        stx $dc02
        inx                 ;port dc01 = inputs
        stx $dc03

        ;--------

        ldx #2
        lda #0
        sta $00,x
        inx
        bne *-3

        .if KEEPTIME=1
          sta timelow
          sta timehigh
        .fi
                sta tabley

        ;--------

        .if KEEPHISTORY=1
          lda #<collisionhistory
          sta collisionhistorylow
          lda #>collisionhistory
          sta collisionhistoryhi
        .fi
        .if KEEPFLIPPERHIS=1
          lda #<flippercollisionhistory
          sta flippercollisionhistlow
          lda #>flippercollisionhistory
          sta flippercollisionhisthigh
        .fi

        jsr balllost

        .if PLAYMUSIC=1
          ldx #0            ;init tune
          jsr tune
        .fi

        lda #<mainirq
        sta $fffe
        lda #>mainirq
        sta $ffff
        lda #$f0
        sta $d012
        lda #$01
        sta $d019
        sta $d01a
        sta $dc0d

genswapnybble
        ldx #0
        txa
        ldy #3
        cmp #$80
        rol
        dey
        bpl *-4
        sta swapnybble,x
        inx
        bne genswapnybble+2

        lda #25
        sta tableyold
        jsr copytable            ;set d800 colors to top of screen
        jsr tablestartposition   ;calculate table-postion to match the ball position
        jsr copytable            ;set d800 colors

        lda #$3b
        sta $d011
        asl $d019                ;acknowledge irq's
        cli

;-------------------------------------------------------------------------------------------------------------------

gameloop
;-------
        .if PLAYMUSIC=1
          jsr music
        .fi

        lda startgameloop          ;wait
        beq *-2
        dec startgameloop

        .if SENSERASTERTIME=1
          lda $d012
          sta startd012
        .fi

        jsr checkforkeys           ;check if any keys are pressed

        ;-----------------------------------------------------------
        ;first we move things like the ballshooter and flippers..  -
        ;-----------------------------------------------------------

        jsr moveshooter     ;moves the ballshooter
        jsr moveflippers

        ;-------------------------
        ;we move the ball itself -
        ;-------------------------

        .if SHOWRASTERTIME=1
          lda #$06          ;colored area of border shows how much rastertime is used
          sta $d020
        .fi

        jsr moveball           ;move the ball

        ;-----------------------
        ;we handle the buttons -
        ;-----------------------

        jsr buttoncode

        ;---------------
        ;do game-logic -
        ;---------------

        .if SHOWRASTERTIME=1
          lda #$0e
          sta $d020
        .fi

        jsr pinball       ;do things like lights/score/mode

        ;-----------------------------------------------------
        ;handle the lights (actually changing them onscreen) -
        ;-----------------------------------------------------

        .if SHOWRASTERTIME=1
          lda #$0a
          sta $d020
        .fi
        jsr lightscode

        .if KEEPTIME=1
          inc timelow
          bne *+4
          inc timehigh
        .fi

;-------------------------------------

        .if SENSERASTERTIME=1
          lda $d012
          sec
startd012=*+1
          sbc #$00
highestd012=*+1
          cmp #$00
          bcc *+5
          sta highestd012
        .fi

        .if WARNLOWRASTER=1
          lda startgameloop
          beq *+5
          inc $d020
        .fi

        jsr addgravity    ;change ball-speed due to gravity
        jsr addfriction   ;change ball-speed due to friction

        .if SHOWRASTERTIME=1
          lda #0
          sta $d020
        .fi

        jmp gameloop      ;restart the loop

;--------------------------------------------------------------------------------------------------------------------

;sets the values of all buttons and lights to 0, so buttons aren't pressed & lights are turned off.

clearbuttons

        ldx #nrofbuttons-1
        lda #0
        sta buttons,x
        dex
        bpl *-3
        ldx #nroflights-1
        lda #$80
        sta lights,x
        dex
        bpl *-3

        rts

;--------------------------------------------------------------------------------------------------------------------

;resets score to 0

clearscore

        ldx #11
        lda #0
        sta score,x
        dex
        bpl *-4

        rts

;--------------------------------------------------------------------------------------------------------------------

;this routine puts an illegal screen mode at the right position,
;so the bitmap is properly clipped at the bottom of the screen.

clipbitmapirq
        pha

        lda $d011
        cmp #$3f
        bne normalclip

        lda #$7f
        sta $d011

normalclip
        lda #$00
        sta $d025
        sta $d026
        sta $d027
        sta $d028
        sta $d029
        sta $d02a
        sta $d02b
        sta $d02c
        sta $d02d
        sta $d02e

        lda $d011
        ora #$40
        sta $d011

        asl $d019
        lda #<mainirq
        sta $fffe
        lda #>mainirq
        sta $ffff
        lda #$fa
        sta $d012

        lda #0
        sta $d015

        pla
        rti

;--------------------------------------------------------------------------------------------------------------------

;this is the main irq
;it handles general stuff,plays the music and opens the lower and upper borders, also sets speed to 2mhz on c128's..

mainirq
        pha
        stx xtemp
        sty ytemp

        lda $d011              ;open border
        and #$f7
        sta $d011

        asl $d019
        lda #<scrollirq
        sta $fffe
        lda #>scrollirq
        sta $ffff
        lda #$1d
        sta $d012

        .if SHOWRASTERTIME=1
          lda $d020
          pha
          lda #7
          sta $d020
        .fi
        .if SHOWRASTERTIME=1
          pla
          sta $d020
        .fi

        .if SHOWRASTERTIME=1
          lda $d020
          pha
          lda #3
          sta $d020
        .fi

        lda #0                        ;sprites off
        sta $d015

        jsr movetable
        jsr copytable
        jsr dotmatrix                 ;display the dot matrix
        jsr display_precalc           ;precalc display for all that we've calculated

        .if SHOWRASTERTIME=1
          pla
          sta $d020
        .fi

        ldx #1
        lda #25
        sec
        sbc tabley
        bcs *+6
        adc #26
        sec
        dex

        adc #$0f
        sta FLDY
        stx COARSEX

        lda tableylow
        ;clc                ;carry always clear from adc #$0f
        adc #$06
        and #$07
        eor #$7f
        sta softy+1

        ldx #0             ;select correct start $d018 and $dd00
        lda tabley
        cmp #25
        bcc *+3
        inx
        stx d018now

        jsr setswitchirq

        inc startgameloop

        pla
        ldx xtemp
        ldy ytemp
        rti

;------------------------------------------------------------------------------------------------------------------

tablestartposition
        lda #$80
tablestartloop
        sta oldtableylow
        jsr movetable
        lda tableylow
        cmp #$00            ;oldtableylow, self modifying bit..
*=*-1
oldtableylow .byte 0
        bne tablestartloop
        rts
movetable
        lda ballylow
        sec
        sbc tableylow
        tax

        lda ballyhi
        sbc tableyhigh
        lsr

        txa
        ror
        lsr
        tax

        cpx #36
        bcc *+5
        ldx #35
        clc

        ldy #0
        lda bitmapspeed,x
        bpl *+3
        dey

        ;clc
        adc tableylow
        sta tableylow

        tya
        adc tableyhigh
        sta tableyhigh

        ;------------------------------------------------------------
        ;check if the bitmap moves too far, if so, limit the position
        ;------------------------------------------------------------

        ;lda tableyhigh
        bpl tablenottoomuchup
        lda #0
        sta tableylow
        sta tableyhigh
        beq tablenottoomuchdown2

tablenottoomuchup
        ;lda tableyhigh
        beq tablenottoomuchdown
        cmp #$02
        bcs tabletoomuchdown
        ldx tableylow
        cpx #$59
        bcc tablenottoomuchdown

tabletoomuchdown
        lda #$59
        sta tableylow
        lda #$01
        sta tableyhigh

tablenottoomuchdown
        ;lda tableyhigh            ;calc table position in chars
        lsr
        lda tableylow
        ror
        lsr
        lsr
tablenottoomuchdown2
        sta tabley
        rts

;--------------------------------------------------------------------------------------------

copyup
        sbc #1
        sta tableyold
        bpl copytable2

copytable
        lda tableyold
        cmp tabley
        bne *+3
copytableend
        rts
        bcs copyup

        adc #1
        sta tableyold
        cmp #$2b
        bcs copytableend
        ;clc
        adc #21
        cmp #51
        beq specialcopy2
copytable2
        cmp #25
        beq specialcopy1

        tay                ;calculate row*20
        sta low
        asl
        asl
        adc low
        asl
        asl

        sta low
        asl
        sta low2
        clc
        adc #20
        sta low3
        .byte $bf,<memscreendata1h,>memscreendata1h  ;lax memscreendata1h,y
        and #3
        ora #$d8
        sta high2
        adc #0
        and #$db
        sta high3

        txa
        lsr
        clc
        adc #>memd800colors
        sta high

        ldy #19
cptableloop
        .byte $b3,<low  ;lax(low),y
        sta (low2),y
        lda swapnybble,x
        sta (low3),y
        dey
        bpl cptableloop
        jmp copytable

specialcopy1
        ldy #3
        lda memd800colors+25*20,y
        sta $dbe8,y
        tax
        lda swapnybble,x
        sta $dbfc,y
        dey
        bpl specialcopy1+2

        ldy #15
specialcopy1loop
        lda memd800colors+25*20+4,y
        sta $dbec,y
        tax
        lda swapnybble,x
        sta $d800,y
        dey
        bpl specialcopy1loop
        jmp copytable

specialcopy2
        ldy #7
        lda memd800colors+51*20,y
        sta $dbf8,y
        tax
        lda swapnybble,x
        sta $d80c,y
        dey
        bpl specialcopy2+2

        ldy #11
specialcopy2loop
        lda memd800colors+51*20+8,y
        sta $d800,y
        tax
        lda swapnybble,x
        sta $d814,y
        dey
        bpl specialcopy2loop
        jmp copytable
;--------

memscreendata1h ;64 bytes
        .byte 0,0,0,0,0,0,0
        .byte 1,1,1,1,1,1
        .byte 2,2,2,2,2,2,2
        .byte 3,3,3,3,3,3
        .byte 4,4,4,4,4,4
        .byte 5,5,5,5,5,5,5
        .byte 6,6,6,6,6,6
        .byte 7,7,7,7,7,7,7
        .byte 8,8,8,8,8,8
        .byte 9,9,9,9,9,9

;--------------------------------------------------------------------------------------------------------------------

;-------------------------------------------------------------------------
;this routine moves and controls the ball shooter that is used to shoot  -
;the ball away at the beginning of the game                              -
;-------------------------------------------------------------------------

moveshooter
        ldy crsrdown         ;check if crsr-down key is pressed
        bne moveshooterdown  ;if it is, move the shooter down

        ;----------------------------------------------------------------------
        ;if we got here, either we have to move the shooter up (and increase  -
        ;the speed) or it is already at the top                               -
        ;----------------------------------------------------------------------

        ldx shooterposition    ;check if the shooter is at the top position
        bne moveshooterup

        rts

moveshooterup
        ;--------------------------------------------------
        ;if we got here, we have to move the shooter up!  -
        ;--------------------------------------------------

        lda shooterspeed
        clc
        adc #8                  ;depends on spring constant!!! higher==stiffer
        sta shooterspeed

        txa
        sec
        sbc shooterspeed
        bcs *+3
        tya                     ;y is already 0 from ldy crsrdown
        sta shooterposition

        ;lda shooterposition    ;only if shooterposition==0, we have to accelerate the ball...
        beq *+3

        rts

        ldx shooterspeed
        sta shooterspeed

        ;---------------------------------------------------------
        ;check if the ball is @ the bottom of the shooterguide.. -
        ;---------------------------------------------------------

        lda ballylow
        .if TABLE=0
          cmp #$df
        .fi
        .if TABLE=1
          cmp #$de
        .fi
        bcs *+3
        rts
        .if TABLE=0
          cmp #$e1
        .fi
        .if TABLE=1
          cmp #$e0
        .fi
        bcc *+3
        rts
        lda ballxlow
        cmp #$37
        bcc *+3
        rts
        cmp #$33
        bcs *+3
        rts
        lda ballyhi
        and ballxhi
        bne *+3
        rts

        txa
        eor #$ff
        sta temp

        tya                     ;y is already 0 from ldy crsrdown

        ;--------------------------------------------------------
        ;calculate speed for shooting, and give the ball a kick -
        ;--------------------------------------------------------

        sec
        ror temp
        ror
        sec
        ror temp
        ror

        adc spdyfrc
        sta spdyfrc
        lda temp
        adc spdylow
        sta spdylow
        bcs *+4          ;carry clear -> dec spdyhi
        dec spdyhi

        rts

moveshooterdown
        lda #0
        sta shooterspeed

        lda shooterposition
        clc
        adc #2
        bpl *+4
        lda #$7f                ;shooterposition is max $7f
        sta shooterposition

        rts

;------------------------------------------------------------------------------------------------------------------

;this irq scrolls the whole screen up and down, and also left/right if needed

        .if ((*+153)/256 - (*+14)/256) = 1     ;make sure the whole IRQ is in one page, to avoid timing problems with branches
          *=*/256*256+256                      ;153 = #bytes until endofprecisetiming
        .fi

; Somehow the above align code suddenly failed to run!!!! STUPID TASS  (/JackAsser)
;*=*/256*256+256

scrollirq
        sta atemp
        stx xtemp
        sty ytemp

        ; Read timer interrupt and compensate for variance
        lda #%00000111
        eor $dc04
        sta *+4
startofprecisetiming
.page
        bpl *+2
        lda #$a9
        lda #$a9
        lda #$a9
        lda #$a5
        nop
        ; Raster beam at line 50, cycle 41
.endp
        lda #$07
        sta $d025        ;color %01 to yellow
        lda #$09
        sta $d026        ;color %10 to brown
        lda $f9ff
        sta f9ffwriteback+1
        lda #$55
        sta $f9ff        ;Jackasser : you're writing into data here!!, i fixed this for you ;)
        sta $ffff
        nop
        ldx #$00
;30,12
        stx $d021
;------------------------------------
.page
        ; FLD (29,16)
fld_loop
        ora ($00,x)
        lda $d012
        clc
        adc #$07
        and #$07
        ora #$18
        sta $d011        ; Line 29, Cycle 34
        lda $d01c
        eor #$ff
        nop
        nop
        inx
        cpx FLDY
        sta $d01c
        bne fld_loop
.endp
        nop
        nop

        ; Line crunch (68,15)
.page
lcr_loop
        lda $d01c
        eor #$ff
        tay

        pha
        pla
        nop

        lda $d012
        clc
        adc #$02
        and #$07
        ora #$78
        inx
        cpx #$2a

        sta $d011        ; Line 68, cycle 52
        sty $d01c

        bne lcr_loop
.endp
        ldy #4           ;wait 6 + y*5 cycles -> 4y => 26 cycles
.page
        dey
        bpl *-1
.endp
        ora ($00,x)
        inc $d011

        ; Update VIC-banks
        ldx d018now
        lda d018tab,x
        sta $d018
        lda dd00tab,x
        sta $dd00

        ; VSP new, sorry jackasser for messing with your code ;)

        ;72,58
        ldy COARSEX          ;wait 20 or 36 cycles
f9ffwriteback
        lda #$00
.page
        pha
        pla
        sta $f9ff
        dey
        bpl *-6
.endp
endofprecisetiming
        dec $d011

        ; Fine tune scrolling

softx   lda #$18
        sta $d016
softy   lda #$00
        sta $d011
        and #$3f

        .if SHOWRASTERTIME=1
          inc $d020
        .fi

        jsr display

        .if SHOWRASTERTIME=1
          dec $d020
        .fi

        asl $d019
toirql  lda #<clipbitmapirq
        sta $fffe
toirqh  lda #>clipbitmapirq
        sta $ffff
tod012  lda #$f7
        sta $d012

        ldx xtemp
        lda softy+1
        and #$3f
        ldy #81
        cpy $d012
        bne *-3
        sta $d011
        ;---------------------------------------
        lda atemp
        ldy ytemp
        rti

;--------------------------------------------------------------------------------------------------------------------

switchgfxirq
        pha
        stx xtemp
        sty ytemp

        lda #<clipbitmapirq    ;12 cycles
        sta $fffe
        lda #>clipbitmapirq
        sta $ffff

        lda #$f7               ;12 cycles
        sta $d012
        asl $d019

        ; WERNER!!! The following stabilize code isn't very stable, depending on how many cycles
        ; the scrollirq has taken this code may crash. I had to add two extra cycles to make it stable again.
        ; But let's not bother with it. This is something that have to be retimed again later when we
        ; have shuffled around the bitmaps anyway...
        ;
        ; Jackasser : I know, but I just didnt care :-)

        lda $dc04
        eor #$ff
        clc
        adc #$32
        sta switchit+1

switchit
        bne *+0
        lda #$a9
        lda #$a9
        lda #$a9
        lda #$a9
        lda #$a9
        lda #$a9
        lda #$a9
        lda #$a9
        lda #$a9
        lda #$a9
        lda #$a9
        lda #$24
        nop

        lda #$00
        lda #$00

        ldx d018now
        lda d018tab+1,x
        ldy dd00tab+1,x
        sta $d018
        sty $dd00

        ;this irq might be executed some chars above the area with the sprite-pointer
        ;problem, so we use it to repair the color-data.

        cpx #0                  ;only repair if we're at the bottom of the table
        beq dontfixpointers
fixcolors
        lda #$cf                ;set correct color-data!
        sta $e3f9
        lda #$bc                ;93,92,90,40,91,41,4f,4e
        sta $e3fb               ;!!,..,!!,..,!!,..,..,..
        lda #$3e                ;!! == ball sprite pointer
        sta $e3fd
        lda #$3e
        sta $e3fe
        lda #$6e
        sta $e3ff

        lda tabley              ;check if the sprites are visible, if so, jump to the fix-irq
        cmp #$22
        bcc dontfixpointers

        lda #<writepointerirq
        sta $fffe
        lda #>writepointerirq
        sta $ffff
        lda #$f6
        sec
        sbc tableylow
        sta $d012
dontfixpointers

        ldx xtemp
        ldy ytemp
        pla
        rti

writepointerirq      ;this irq writes the correct sprite-pointers for the flippers & shooter
        pha
        stx xtemp

        ldx leftflipperpointer
        stx $e3fb
        inx
        stx $e3fd
        ldx rightflipperpointer
        stx $e3ff
        inx
        stx $e3fe

        lda #$92                ;spring sprite
        sta $e3f9

        lda tableylow           ;check if the spring-sprite is visible
        cmp #70
        bcs gotospringcolor     ;if so, we have to go to another irq that changes sprite colors

        lda #<clipbitmapirq
        sta $fffe
        ldx #>clipbitmapirq
        lda #$f7
writepointerirq2
        stx $ffff
        sta $d012
        asl $d019

        pla
        ldx xtemp
        rti

gotospringcolor
        lda #<setspringcolorsirq      ;jump to the irq that changes colors
        sta $fffe
        ldx #>setspringcolorsirq
        lda #$39
        sec
        sbc tableylow
        bne writepointerirq2          ;and back to the irq to use the end of the irq

setspringcolorsirq     ;this irq sets the correct multicolor colors for the spring-sprite
        pha

        lda #$0b
        sta $d026
        lda #$0f
        sta $d025

        lda #<clipbitmapirq
        sta $fffe
        lda #>clipbitmapirq
        sta $ffff

        lda #$f7
        sta $d012
        asl $d019

        pla
        rti

;--------------------------------------------------------------------------------------------------------------------

setswitchirq
        lda tableylow
        ldx tabley
        cpx #27
        bcc *+5
        sec
        sbc #25*8
        cmp #5*8-6
        bcc noswitch
        cmp #25*8
        bcs noswitch

        eor #$ff
        clc
        adc #$18

        sta tod012+1

        lda #<switchgfxirq
        sta toirql+1
        lda #>switchgfxirq
        sta toirqh+1

        rts

noswitch
        lda #<clipbitmapirq
        sta toirql+1
        lda #>clipbitmapirq
        sta toirqh+1
        lda #$f7
        sta tod012+1
        rts

;------------------------------------------------------------------------------------------------------------------

;this routine calculates the correct animation frame for the flipper sprites

moveflippers

        ldy #0
        ldx #0
        lda leftflipper         ;if not pressed -> x = 0
        beq setleftflip
        inx                     ;if pressed -> x = 1
        stx leftup
        lda leftflipperbut      ;if pressed AND not pressed before => x = 2
        bne setleftflip
        sty leftspeed
        inx
setleftflip
        stx leftflipperbut

        inc leftspeed

        lda leftflipperanim
        sta prevleftflipper
        ldx leftup
        beq dontmoveleftup

        clc
        adc leftspeed
        cmp #flipperframes
        bcc writeleft
        sty leftup
        lda #flipperframes-1
writeleft
        sta leftflipperanim
        bne moverightflipper
dontmoveleftup
        sec
        sbc leftspeed
        bcs writeleft2
        tya
writeleft2
        sta leftflipperanim
moverightflipper

        ;---

        ldx #0
        lda rightflipper        ;if not pressed -> x = 0
        beq setrightflip
        inx                     ;if pressed -> x = 1
        stx rightup
        lda rightflipperbut     ;if pressed AND not pressed before => x = 2
        bne setrightflip
        sty rightspeed
        inx
setrightflip
        stx rightflipperbut

        inc rightspeed

        lda rightflipperanim
        sta prevrightflipper
        ldx rightup
        beq dontmoverightup

        clc
        adc rightspeed
        cmp #flipperframes
        bcc writeright
        sty rightup
        lda #flipperframes-1
writeright
        sta rightflipperanim
        bne stopflippers
dontmoverightup
        sec
        sbc rightspeed
        bpl writeright2
        tya
writeright2
        sta rightflipperanim
stopflippers

        lda leftflipperanim
        cmp prevleftflipper
        bne *+4
        sty leftspeed
        lda rightflipperanim
        cmp prevrightflipper
        bne *+4
        sty rightspeed

        rts
        ;---

leftup     .byte 0
rightup    .byte 0
prevleftflipper  .byte 0
prevrightflipper .byte 0

;------------------------------------------------------------------------------------------------------------------

addgravity
        ;determines direction and strength of gravity at the position of the ball
        ;and adds the effect to ball speed

        ;the gravity-map is char-based, so an 8x8 grid is used.
        ;the map is crunched by re-using same rows, and internally inside a row

        ;calc position in char-grid

        lda ballyhi          ;calculate char-y position
        lsr a
        lda ballylow
        ror a
        bcs *+8
        ldx ballyfrc
        cpx #$80
        sbc #0
        lsr a
        and #$fe
        tay                  ;use y to determine row to get gravdata from

        lda layer            ;get gravity-data from the correct layer
        beq *+10
        ldx layer1grav,y     ;if layer=1, get rowdata from layer1grav
        lda layer1grav+1,y
        bne *+8

        ldx layer0grav,y     ;if layer=0, get rowdata from layer0grav
        lda layer0grav+1,y
        stx low
        sta high

        lda ballxhi          ;calculate char-x position
        lsr
        lda ballxlow
        ror
        bcs *+8
        ldx ballxfrc
        cpx #$80
        sbc #0
        lsr
        lsr

        ldy #$01             ;'decrunch' grav-data by looping until
        cmp (low),y          ; ballx < the boundarydata
        bcc *+8
        iny
        iny
        sbc (low),y
        bcs *-4
        dey
        lda (low),y          ; read gravity data
        tax

        ;decode radial gravitydata to cartesian

        and #$0f
        sta gravityforce       ;force part (....xxxx)
        txa
        lsr                    ;angular part (xxxx....)
        lsr
        lsr
        lsr
        tay

        lda gravitydirectiondata,y    ;calculate y-part of cartesian
        asl
        ora gravityforce
        tax
        lda spdyfrc2
        bcs subyspeed          ;force points up or down?

                               ;if we got here, the force points down
        ;clc                   ;carry is clear from bcs!
        adc forcedatalow,x     ;change ball speed
        sta spdyfrc2
        lda spdyfrc
        adc forcedata,x
        sta spdyfrc
        bcc addxspeed
        inc spdylow
        bne addxspeed
        inc spdyhi
        bcs addxspeed
subyspeed
                               ;force points up
        ;sec                   ;carry is set by asl!
        sbc forcedatalow,x
        sta spdyfrc2
        lda spdyfrc
        sbc forcedata,x
        sta spdyfrc
        bcs addxspeed
        lda spdylow
        sbc #0
        sta spdylow
        bcs addxspeed
        dec spdyhi
addxspeed
        lda gravitydirectiondata+4,y  ;calculate x-part of cartesian
        beq endaddgravity
        asl
        ora gravityforce
        tax
        lda spdxfrc2           ;force points right
        bcs subxspeed
        ;clc                   ;clc by asl!
        adc forcedatalow,x
        sta spdxfrc2
        lda spdxfrc
        adc forcedata,x
        sta spdxfrc
        bcc *+8
        inc spdxlow
        bne *+4
        inc spdxhi
        rts                    ;end of gravity
subxspeed
        ;sec                   ;sec by asl!
        sbc forcedatalow,x     ;force points left
        sta spdxfrc2
        lda spdxfrc
        sbc forcedata,x
        sta spdxfrc
        bcs *+12
        lda spdxlow
        sbc #0
        sta spdxlow
        bcs *+4
        dec spdxhi
endaddgravity
        rts

;------------------------------------------------------------------------------------

;this table shows how to convert angle-part of grav-data to cartesian.
;bits 0-3 show the length of the vector in that direction (see forcedata for exact length)
;bit 7 shows whether the force should be added or substracted to the speed

;these tables are needed to calculate how strong the resulting force in a direction is
;, calculated from how much it is pointed in that direction and how strong the total force is

forcedatalow=*-14
        ;force table for spdfrc2 part
        .byte 0,0                                                       ;direction $00
        .byte 0,196,136,76,16,212,152,92,31,227,167,107,47,243,183,123  ;direction $10
        .byte 0,106,212,62,168,18,124,230,80,186,36,142,248,99,205,55   ;direction $20
        .byte 0,217,178,139,100,61,22,239,200,161,122,83,44,5,222,183   ;direction $30
        .byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0                           ;direction $40

forcedata=*-18
        ;direction $10  .382683432x    force pointed a little bit in this direction
        .byte 1,2,3,3,4,5,6,6,7,8,9,9,10,11

        ;direction $20  .707106781x
        .byte 0,1,2,4,5,7,8,9,11,12,14,15,16,18,19,21

        ;direction $30  .923879532x
        .byte 0,1,3,5,7,9,11,12,14,16,18,20,22,24,25,27

        ;direction $40  1x        force is completely pointed into this direction
        .byte 0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30

;--------------------------------------------------------------------------------------

addfriction
        ;1 calc speed of contact point
        ;2 calc friction
        ;3 calc new ball speed
        ;4 change ballspin

        ;  6!4   x=quadrant
        ;  -+-
        ;  2!0
        ;-----------------------------------------------------
        ;add ballspin to speed to get speed of contact point -
        ;-----------------------------------------------------

        ldx #0

        lda spdyfrc2
        clc
        adc omegayfr2
        sta spd2yfrc2
        lda spdyfrc    ;calc y-speed
        adc omegayfr
        sta spd2yfrc
        lda spdylow
        adc omegaylo
        sta spd2ylow

        bpl yspeedspinadd

        ;absolute

        txa            ;make speed positive
        sec            ;substract speed from 0
        sbc spd2yfrc2
        sta spd2yfrc2
        txa
        sbc spd2yfrc
        sta spd2yfrc
        txa
        sbc spd2ylow
        ldx #4
        sta spd2ylow
yspeedspinadd

        ;--------

        lda spdxfrc2
        clc
        adc omegaxfr2
        sta spd2xfrc2
        lda spdxfrc    ;same for x
        adc omegaxfr
        sta spd2xfrc
        lda spdxlow
        adc omegaxlo
        sta spd2xlow

        bpl xspeedspinadd

        ;make speed positive
        ;substract speed from 0

        inx
        inx
        lda #0
        sec
        sbc spd2xfrc2
        sta spd2xfrc2
        lda #0
        sbc spd2xfrc
        sta spd2xfrc
        lda #0
        sbc spd2xlow
        sta spd2xlow
xspeedspinadd
        stx angle      ;save quadrant information (see above)

        ora spd2ylow   ;if both spd2xlow and spd2ylow are 0 -> maybe we have to shift in bits from spd2frc2!
        bne speedbig   ;at least one has speed > 1pixel/frame

        lda spd2xfrc2  ;'multiply' x-speed by 256
        ldx spd2xfrc
        sta spd2xfrc
        stx spd2xlow

        lda spd2yfrc2   ;'multiply' y-speed by 256
        ldx spd2yfrc
        sta spd2yfrc
        stx spd2ylow
speedbig
        jsr calcangle
        bcc *+3
        ;all speeds are 0 so there's no friction
        rts

        ;substract x friction from speed

        ;lda angle      ;use angle to get force in x direction
        ;clc            ;we came here by bcc!
        adc #$c0
        tay

        lda sintable,y     ;read force from table
        cpy #$81           ;get MSB (bit 8)
        rol
        rol                ;make force small enough
        tax
        rol
        and #%00000111
        cpy #$81
        bcc *+5
        ora #%11111000     ;make value negative if necessary
        clc
        sta temp

        txa                ;add force to x-speed
        and #%11111100
        adc spdxfrc2
        sta spdxfrc2

        ldx #0              ;reduce speed
        lda temp
        bpl *+3             ;if friction<0, add #$ff to spdhi/low!
        dex
        adc spdxfrc
        sta spdxfrc
        txa
        adc spdxlow
        sta spdxlow
        txa
        adc spdxhi
        sta spdxhi

        ;---------------
        ; x ball spin! -
        ;---------------

        cpy #$81           ;calc ball-spin change
        ror temp
        cpy #$81
        ror temp

        ;lda temp          ;alternative code for above.. faster if >2 ror's
        ;cmp #$80
        ;ror
        ;cmp #$80
        ;ror
        ;sta temp

        lda sintable,y     ;change ball spin
        clc
        adc omegaxfr2
        sta omegaxfr2

        lda temp
        adc omegaxfr
        sta omegaxfr
        txa
        adc omegaxlo
        sta omegaxlo
        txa
        adc omegaxhi
        sta omegaxhi

        ;-----------------------------
        ;y friction     ;same for y  -
        ;-----------------------------

        lda angle
        eor #$80
        tay

        lda sintable,y     ;read force from table
        cpy #$81           ;get MSB (bit 8)
        rol
        rol                ;make force small enough
        tax
        rol
        and #%00000111
        cpy #$81
        bcc *+5
        ora #%11111000     ;make value negative if necessary
        clc
        sta temp

        txa                ;add force to y-speed
        and #%11111100
        adc spdyfrc2
        sta spdyfrc2

        ldx #0
        lda temp
        bpl *+3             ;if friction<0, add #$ff to spdhi/low!
        dex
        adc spdyfrc
        sta spdyfrc
        txa
        adc spdylow
        sta spdylow
        txa
        adc spdyhi
        sta spdyhi

        ;---------------
        ; y ball spin! -
        ;---------------

        cpy #$81           ;calc ball-spin change
        ror temp
        cpy #$81
        ror temp

        ;lda temp          ;alternative code for above.. faster if >2 ror's
        ;cmp #$80
        ;ror
        ;cmp #$80
        ;ror
        ;sta temp

        lda sintable,y     ;change ball spin
        clc
        adc omegayfr2
        sta omegayfr2

        lda temp
        adc omegayfr
        sta omegayfr
        txa
        adc omegaylo
        sta omegaylo
        txa
        adc omegayhi
        sta omegayhi

endfriction
        rts

;-------------------------------------------------------------------------------------

calcangle
        lda spd2ylow
        ora spd2xlow
        jsr accuracy   ;calculate #bits used
        sty acc1+1
        sty acc2+1

        ;-----------------------------------------------------------------
        ;make speeds use as much bits as possible to increase accuracy   -
        ;by multiplying/dividing them by a certain amount (determined by -
        ;the most number of bits used in spdlow)                         -
        ;-----------------------------------------------------------------

        lda spd2xfrc
        clc
acc1                   ;use all 8 bits, so shift used bits from lowbyte into
        bcc *+0        ;the fractional byte!
        lsr spd2xlow
        ror a
        lsr spd2xlow
        ror a
        lsr spd2xlow
        ror a
        lsr spd2xlow
        ror a
        lsr spd2xlow
        ror a
        lsr spd2xlow
        ror a
        lsr spd2xlow
        ror a
        lsr spd2xlow
        ror a
        sta spd2xlow

        lda spd2yfrc
        clc
acc2                   ;same as above, but for y-component
        bcc *+0
        lsr spd2ylow
        ror a
        lsr spd2ylow
        ror a
        lsr spd2ylow
        ror a
        lsr spd2ylow
        ror a
        lsr spd2ylow
        ror a
        lsr spd2ylow
        ror a
        lsr spd2ylow
        ror a
        lsr spd2ylow
        ror a
        sta spd2ylow
fastcalcangle

        ;swap x,y-speed if necessary (needed for log, see below!), we want the value in
        ;y to be bigger than the value in x

        cmp spd2xlow
        bcs ybiggest
        inc angle
        ldy spd2xlow
        tax
        bcc fastcalcangle2

        ;calculate angle in which ball is travelling
        ;using angle=atan(y/x) -> y/x is done using logarithms log(y/x)=log(y)-log(x)
        ;the atan-table has a inverse log built in, to undo log(y/x)
ybiggest
        tay
        ldx spd2xlow

        ;if x=0 then angle = $40, as log(0) doesn't exist (== -infinity)
fastcalcangle2
        bne *+14
        cpy #0          ;if BOTH speeds are zero
        bne *+6         ;don't calculate the friction
        tya
        sta angle
        ;sec            ;skip adding friction, sec not necessary coz 0 compared with 0
        rts

        lda #$40
        bne undoswap

        lda loglow,y    ;calculate log(y/x)
        sec
        sbc loglow,x
        lda loghigh,y
        sbc loghigh,x   ;use only resulting loghigh (y/x) for calculating angle
        tay
        lda atandata,y  ;do angle=atan{invlog(log[y/x])}
undoswap
        ;we transform back to the correct quadrant

        ldx angle
        eor calcangleeortable,x
        ;sec            ;carry is set after substracting the logs!
        adc calcangleadctable,x
        sta angle
        clc
        rts

;-------------------------------------------------------------------------------------

accuracy
        ;cmp #0    ;a just loaded!
        bne *+5
        ldy #24
        rts
        cmp #$10
        bcc acc1b

        cmp #$40  ;bit 4/5/6/7
        bcc acc1a
        asl
        bcc *+5
        ldy #0    ;bit 7 is set
        rts
        ldy #3    ;bit 6
        rts
acc1a
        cmp #$20  ;bit 4/5
        bcc *+5
        ldy #6    ;bit 5
        rts
        ldy #9    ;bit 4
        rts
acc1b
        cmp #$04  ;bit 0/1/2/3
        bcc acc1c

        cmp #$08  ;bit 2/3
        bcc *+5
        ldy #12   ;bit 3
        rts
        ldy #15   ;bit 2
        rts
acc1c
        cmp #$02  ;bit 0/1
        bcc *+5
        ldy #18   ;bit 1
        rts
        ldy #21   ;bit 0
        rts

accuracy2
        ;cmp #0
        beq acc2c
        cmp #$10
        bcc acc2a

        cmp #$40  ;bit 4/5/6/7
        bcc *+5
                   ;bit 7 kan niet
        ldy #7    ;bit 6
        rts

        cmp #$20  ;bit 4/5
        bcc *+5
        ldy #6    ;bit 5
        rts
        ldy #5    ;bit 4
        rts
acc2a
        cmp #$04  ;bit 0/1/2/3
        bcc acc2b

        cmp #$08  ;bit 2/3
        bcc *+5
        ldy #4    ;bit 3
        rts
        ldy #3    ;bit 2
        rts
acc2b
        adc #2    ;1   -> 1   nasty unreadable bit of code.. well, shit happens.
        lsr       ;2,3 -> 2
acc2c
        tay
        rts

;--------------------------------------------------------------------------------------

moveball
        ;moves the ball until time
        ;runs out. if a collision
        ;occurs, calc new ball
        ;direction and speed.

        .if JOYCONTROL=1
          lda $dc00               ;joystick mode? picks ball up
          sta joystick            ;and drops somewhere else
          and #$10
          bne *+5
          jmp joydebug
        .fi

        lda #0                    ;the ball has not yet collided this frame
        sta collided
        sta flippercollision
        sta flipperhit

        lda ballylow
        eor #$80
        sta oldy                  ;put a different value in oldy
        lda layer
        asl
        ora ballyhi               ;encode layer into ballyhigh
        sta ballyhi

moveballagain ;jump-in point after a collision!

        ldy ballyhi
        lda collisiontable1,y     ;select correct pixelrow
        sta col2+2
        lda collisiontable2,y
        sta col3+2

        lda #0
        sta abstaken

        lda spdxlow                ;determine how many times to lsr, until spdxlow = 0 or #$ff
        bpl *+4
        eor #$ff
        sta temp
        ldy #$90                   ;select bcc in loop
        lda spdylow
        bpl *+6
        eor #$ff
        ldy #$b0                   ;select bcs in loop

        sty poops                  ;set correct bcc/bcs in loop
        ora temp
        ora leftspeed              ;make steps smaller if necessary for flipper collisions!
        ora rightspeed
        jsr accuracy2

        lda collided               ;if we collided before, the chance is big
        beq notcollidedbefore      ;we need to reduce addtotime.
                                   ;for example : timeinaframe after collision is $40
                                   ;new addtotime=$80 -> resulting timeinaframe is $c0
        lda #$80
        sec                        ;calculate time left in this frame
        sbc timeinaframe
        cmp addtotimetable,y
        bcs *+5
        iny
        bne *-6

notcollidedbefore
        lda addtotimetable,y
        sta addtotime

        ldx #$18                   ;prepare to write 'sec' to code
        lda spdxlow                ;copy speed to temporary adresses
        sta absspdxlow
        bpl *+4
        ldx #$38                   ;write 'sec' if spdx is negative
        stx carry1
        lda spdxfrc
        sta absspdxfrc
        lda spdxfrc2
        sta absspdxfrc2

        ldx #$18
        lda spdylow
        sta absspdylow
        bpl *+4
        ldx #$38
        stx carry2
        lda spdyfrc
        sta absspdyfrc
        lda spdyfrc2
        sta absspdyfrc2

        ;-----------------------------------
        ;ror speed until stepsize <1 pixel -
        ;-----------------------------------

        cpy #0
        beq movepixelloop
carry1  clc                 ;or sec
        ror absspdxlow
        ror absspdxfrc
        ror absspdxfrc2
carry2  clc                 ;or sec
        ror absspdylow
        ror absspdyfrc
        ror absspdyfrc2
        dey
        bne carry1

movepixelloop

        ;------------------------
        ;move the ball one step -
        ;------------------------

        lda ballyfrc2
        clc
        adc absspdyfrc2
        sta ballyfrc2
        lda ballyfrc
        adc absspdyfrc
        sta ballyfrc
        lda ballylow
        adc absspdylow
        sta ballylow
        tax
poops   bcc collisionsameyhigh     ;bcc/bcs depending on the direction the ball is moving

        lda ballyhi
        eor #$01
        sta ballyhi
        tay
        lda collisiontable1,y     ;select correct pixelrow
        sta col2+2
        lda collisiontable2,y
        sta col3+2
collisionsameyhigh
        lda ballxfrc2
        clc
        adc absspdxfrc2
        sta ballxfrc2
        lda ballxfrc
        adc absspdxfrc
        sta ballxfrc
        lda ballxlow
        adc absspdxlow
        sta ballxlow
        lda ballxhi
        adc spdxhi
        sta ballxhi
movepixelloop2
        ;---------------------------------
        ;calculate multicolor x-position -
        ;---------------------------------

        ;lda ballxhi
        lsr
        lda ballxlow
        ror
        adc #0                    ;adc 0 to make it correct with regard to reading walldata

        ;----------------------------------------------
        ;check if we checked that position before...  -
        ;----------------------------------------------

        cpx oldy
        beq collisionsameyrow     ;we checked this y-position before, so no new row-data, and MAYBE no collision

        ;--------------------------------------
        ;get collisiondata from correct y-row -
        ;--------------------------------------

col2    ldy collisionmap0low,x
        sty yrowlow
col3    ldy collisionmap0high,x
        sty yrowhi

        ;------------------------------------
        ;read angle from correct x-position -
        ;------------------------------------

collisionsameyrow2
        sta oldx2

        ldy #$01
        cmp (yrowlow),y
        bcc *+8
        iny
        iny
        sbc (yrowlow),y
        bcs *-4
        dey
        lda (yrowlow),y
        cmp #$55                 ;if angle = 55, then no collision
        bne movecloser

        ;if we've gotten here, it means the ball didn't collide

        ;check if we're inside the flipper-areas

        lda flipperhit
        bne notinsideflipperarea
        .if TABLE=0
          cpx #$b8
        .fi
        .if TABLE=1
          cpx #$ae
        .fi
        bcc notinsideflipperarea
        lda ballyhi                  ;
        cmp #1                       ; also checks for layer!
        bne notinsideflipperarea     ;
        .if TABLE=0
          cpx #$f4
        .fi
        .if TABLE=1
          cpx #$ea
        .fi
        bcs notinsideflipperarea
        lda oldx2
        .if TABLE=0
          cmp #44                    ;same distance left/right flipper!
        .fi
        .if TABLE=1
          cmp #42
        .fi
        bcc notinsideflipperarea
        .if TABLE=0
          cmp #105
        .fi
        .if TABLE=1
          cmp #101
        .fi
        bcs notinsideflipperarea

        jmp flippercollisiondetect  ;check if the ball might have hit one of the flippers

notinsideflipperarea
        ;the ball wasn't inside the flipper area, so it didnt collide.
nocollision
        lda oldx2
nocollision3
        sta oldx                 ;save checked position, so we don't check it again
        stx oldy
nocollision2
        lda addtotime            ;check if total frame-time has run out
        clc
        adc timeinaframe
        sta timeinaframe
        bmi *+5
        jmp movepixelloop        ;if not, loop again

        and #$7f                 ;save any remaining time..
endmoveloopquick
        sta timeinaframe

        lda ballyhi              ;remove layer encoding from ballyhigh
        and #$01
        sta ballyhi

        ;check here if timeinaframe !=0 and correct
        ;if timeinaframe >0 then we moved the ball a little bit too far
        ;hopefully it doesn't matter that much ;)

        rts
collisionsameyrow
        cmp oldx
        bne collisionsameyrow2
        beq nocollision2
movecloser
        ;----------------------------------------------------
        ;check if we ran into a collision OR something else -
        ;like a button-roll-over or layer-change            -
        ;----------------------------------------------------

        lsr
        bcc movecloser2          ;if bit0==0 -> collision

        cmp #$02                 ;if value = 0/1 -> change layer
        bcs buttonrollover

        sta layer                ;change layer

        lda #0                   ;if we hit a wall, we reset the flipper-hit status
        sta flipperhit

        lda ballyhi
        lsr
        lda layer
        rol
        sta ballyhi

        tay
        lda collisiontable1,y     ;select correct pixelrow
        sta col2+2
        lda collisiontable2,y
        sta col3+2

        ldx ballylow
        txa
        eor #$80
        sta oldy
        lda ballxhi

        jmp movepixelloop2        ;check position again in next layer!

buttonrollover            ;if we got here, the ball rolled over a button
        ;OR the stupid player lost the ball!! darn him!

        cmp #$7f          ;$ff/2 -> ball lost
        bne ballnotlost
        jsr balllost
        lda #0
        jmp endmoveloopquick ;stop moving the ball

ballnotlost
        tay               ;so we press it
        lda buttons-2,y
        ora #1
        sta buttons-2,y
        bne nocollision

        ;----------------------------------------------------------------------
        ;try to move closer to the wall after a collision has been detected!! -
        ;----------------------------------------------------------------------
movecloser2
        ;---------------------------------------------------
        ;first we check if the ball can pass.              -
        ;if the ball passes, it is a waste of time to      -
        ;move closer to the wall. If it hits, we need to   -
        ;calculate the angle anyway, so no time is wasted. -
        ;---------------------------------------------------

        asl
        sta temp2                ;save wallangle for later use
movecloser3
        ldx collided             ;only if collided == 0 we haven't calculated the angle
        bne checkforballpass

        ;-------------------------------------------------
        ;if we got here, we have to calculate the angle! -
        ;-------------------------------------------------

        ldy abstaken           ;make a copy of the big value of the
        bne absalreadytaken    ;absspeed, before we make it smaller
        inc abstaken
        ldy absspdxfrc
        sty spd2xlow
        ldy absspdyfrc
        sty spd2ylow
        ldy absspdxfrc2
        sty spd2xfrc
        ldy absspdyfrc2
        sty spd2yfrc
absalreadytaken
        inc collided            ;set the register.. (we're doing the calcs now)
                                ;x=quadrant, same as in addfriction routine

        ;--------------------------------------
        ;first we make the speeds positive..  -
        ;--------------------------------------

        lda spd2xlow        ;if all the speeds are 0 we'll stop the collision dead in it's tracks.
        ora spd2ylow
        ora spd2xfrc
        ora spd2yfrc
        beq endpassball     ;and we act like the ball passes

        lda spdyhi
        bpl cont

        txa                     ;make vy positive
        sec
        sbc spd2yfrc
        sta spd2yfrc
        txa
        sbc spd2ylow
        sta spd2ylow
        ldx #4
cont
        lda spdxhi
        bpl cont2

        lda #0                  ;make vx positive
        sec
        sbc spd2xfrc
        sta spd2xfrc
        lda #0
        sbc spd2xlow
        sta spd2xlow
        inx
        inx
cont2
        stx angle           ;put quadrantdata away
        lda spd2xlow        ;check if one of either spd2x or spd2y is >=$80
cont3
        ora spd2ylow        ;to improve accuracy, we will shift the speeds left until
        bmi dontfix         ;we use the full 8 bits (bit 7 of either spd2xlow or spd2ylow is set)

        asl spd2yfrc        ;if not, multiply both speeds by 2
        rol spd2ylow
        asl spd2xfrc
        rol spd2xlow
        bpl cont3           ;check again, unless (save cycles) spd2xlow >= $80

dontfix
        lda spd2ylow
        jsr fastcalcangle   ;calculate angle :)
        sta angle
checkforballpass

        ;---------------------------------------------------------
        ;here we check if the ball passes the wall or collides.. -
        ;---------------------------------------------------------

        lda angle          ;ball passes if angle is $81..$ff
        clc
        adc temp2
        asl
        .if KEEPHISTORY=1
          bne *+5          ;ball rolls if $00 or $80 -> don't move closer to wall!
          jmp collision
        .else
          beq collision
        .fi
        bcc dontletpass    ;collide if ballangle+wallangle = $1..$7f

        ;----------------------------------------------------------
        ;if the cpu got here, the ball passes and doesn't collide -
        ;----------------------------------------------------------

endpassball
        .if KEEPHISTORY=1
          ldy #1                            ;store the latest calculated
          lda angle                         ;angle
          sta (collisionhistorylow),y

          lda collisionhistorylow           ;pointers for next collision entry
          clc
          adc #$10
          sta collisionhistorylow
          bcc *+4
          inc collisionhistoryhi

          lda collisionhistoryhi            ;wrap collisionhistory after $1000 bytes
          cmp #>endcollisionhistory
          bne *+6
          lda #>collisionhistory
          sta collisionhistoryhi
        .fi

        lda flippercollision                ;if there was a collision with one of the flippers
        beq *+5                             ;we move back to the original reference frame
        jsr addflipperspeed

        ldx ballylow
        jmp nocollision

dontletpass

        ;---------------------------------------------------
        ;if the ball collides, we move closer to the wall! -
        ;---------------------------------------------------

        lda flipperhit                      ;if the ball was hit by a moving flipper
        bne collision                       ;we do the collision immediately

        ldy addtotime
        bpl collision
        ;cpy #$40
        ;bcc collision

        lda flippercollision                ;if there was a collision with one of the flippers
        beq *+5                             ;we move back to the original reference frame
        jsr addflipperspeed

        lsr addtotime

        lda absspdxlow      ;halve the step-size
        asl
        ror absspdxfrc
        ror absspdxfrc2
        lda absspdylow
        asl
        ror absspdyfrc
        ror absspdyfrc2

        lda ballyfrc2       ;move the ball back (half a previous step)
        sec
        sbc absspdyfrc2
        sta ballyfrc2
        lda ballyfrc
        sbc absspdyfrc
        sta ballyfrc
        lda ballylow
        sbc absspdylow
        sta ballylow
        tax
        lda ballyhi
        sbc spdyhi
        cmp ballyhi
        beq collisionsameyhigh2

        tay
        sty ballyhi
        lda collisiontable1,y     ;select correct pixelrow
        sta col2+2
        lda collisiontable2,y
        sta col3+2
collisionsameyhigh2

        lda ballxfrc2
        sec
        sbc absspdxfrc2
        sta ballxfrc2
        lda ballxfrc
        sbc absspdxfrc
        sta ballxfrc
        lda ballxlow
        sbc absspdxlow
        sta ballxlow
        lda ballxhi
        sbc spdxhi
        sta ballxhi

        jmp movepixelloop2

;-----------------------------------------------------------------------------------------

;this routine handles the ball-collisions..

;saved in collisionhistory :
; angle      calcedangle wallangle  newangle    xspeedlow xspeedfrc yspeedlow yspeedfrc
; absspdxfrc absspdxfrc2 absspdyfrc absspdxfrc2 newspeeds..............................

collision

        ;save all kind of data to the collision history

        .if KEEPHISTORY=1
          ldy #0
          lda angle                    ;save previous calced angle
          sta (collisionhistorylow),y
          iny
          lda angle
          sta (collisionhistorylow),y
          iny
          lda temp2
          sta (collisionhistorylow),y  ;save wallangle
          ldy #4
          lda spdxlow                  ;save important part of x-speed
          sta (collisionhistorylow),y
          iny
          lda spdxfrc
          sta (collisionhistorylow),y
          iny
          lda spdylow                  ;y-speed
          sta (collisionhistorylow),y
          iny
          lda spdyfrc
          sta (collisionhistorylow),y
          iny
          lda absspdxfrc               ;step-sized x-speed
          sta (collisionhistorylow),y
          iny
          lda absspdxfrc2
          sta (collisionhistorylow),y
          iny
          lda absspdyfrc               ;step-sized y-speed
          sta (collisionhistorylow),y
          iny
          lda absspdyfrc2
          sta (collisionhistorylow),y
        .fi

        ;-------------------------------------------------------
        ; check for special conditions during the collision :  -
        ; by reading the specialmap                            -
        ;-------------------------------------------------------

        lda flippercollision
        beq nospecialflip

        lda #0
        sta special

        lda #flipmaterial
        bpl nospecialcollision2

nospecialflip

        lda ballyhi           ;read from the correct position in the specialmap
        lsr
        lda ballylow
        ror

        .if TABLE=0
          ldy layer
          cpy #1              ;layer=0 -> carry clear, layer=1 -> carry set
          ror                 ;add 128 to read from layer 1
          and #$fe
        .fi
        .if TABLE=1
          lsr                 ;we read always from layer 0
          and #$fe
        .fi

        tay
        lda specialmap0,y
        sta low
        lda specialmap0+1,y
        sta high

        lda ballxhi
        lsr
        lda ballxlow
        ror
        lsr
        lsr

        ldy #1                 ;'decrunch' special-data by looping until
        cmp (low),y            ; a < the boundarydata
        bcc *+8
        iny
        iny
        cmp (low),y
        bcs *-4
        dey
        lda (low),y            ;read special data
        sta special
        bpl nospecialcollision ;nothing special happens here
        and #%00011111
        tay
        lda specialbytes,y     ;load wall material for this special case

nospecialcollision
        and #$7f
nospecialcollision2
        sta material           ;wall material

        ;check if we only have to add spin

        ldy angle               ;only add spin effect if angle-wallangle
        tya
        clc                     ;=#%?0000000
        adc temp2
        asl
        bne calcspeed

        ;--------------------------
        ;here we only add spin... -
        ;--------------------------

        lda flippercollision
        beq *+5
        jsr addflipperspeed      ;back to original reference system after a collision

        ;no code here yet...

        jmp endpassball

calcspeed
        ;since : Vxold = sin(angle) * V  -> V = Vxold / sin(angle) OR Vyold / cos (angle)
        ;        Vxnew = sin(anglenew) * V
        ;   ->   Vxnew = Vxold * sin(anglenew) / sin(angle)

        ;determine wether to use V=Vxold / sin(angle) or V=Vyold / cos(angle)
        ;we want to use the one which is biggest, sin or cos..
        ;!also we want to have V positive!

        tya
        and #$3f
        tax
        lda coshtable,x
        sta mult8

        tya                       ;      \5 | 6/      octants 1,2,5,6 -> use sin
        clc                       ;    4  \ | /  7    octants 0,3,4,7 -> use cos
        adc #$20                  ;      ---+---      by adding $20, we shift the octants
        asl                       ;    3  / | \  0    so octants 0,1,4,5 -> use cos
        bpl usecos                ;      /2 | 1\
usesin

        ;instead of dividing by sin(a) or cos(a)
        ;we multiply with :
        ;(1/sin(a))-1 and add 1 later
        ;this works bcoz .5<=sin(a)<=1 => 1<=[1/sin(a)]<=2

        lda spdylow
        bmi makeyspeedpos
        sta mult24hi
        lda spdyfrc
        sta mult24lo
        lda spdyfrc2
        sta mult24frc
        jmp calcv
makeyspeedpos
        lda #0
        sec
        sbc spdyfrc2
        sta mult24frc
        lda #0
        sbc spdyfrc
        sta mult24lo
        lda #0
        sbc spdylow
        sta mult24hi
        jmp calcv
usecos
        lda spdxlow
        bmi makexspeedpos
        sta mult24hi
        lda spdxfrc
        sta mult24lo
        lda spdxfrc2
        sta mult24frc
        jmp calcv
makexspeedpos
        lda #0
        sec
        sbc spdxfrc2
        sta mult24frc
        lda #0
        sbc spdxfrc
        sta mult24lo
        lda #0
        sbc spdxlow
        sta mult24hi

calcv   ;calculate speed |V|=Vxold / sin (angle) = [Vxold * 2 *([1/sin]-1)]/2 + Vxold
        ;use (a+b+c)/x=a/x+b/x+c/x   with x=sin/cos, a=spdxlow,b=frc etc..

        jsr multiply24x8       ;multiply with [1/sin(a)]-1

        lsr result+0           ;divide by 2
        ror result+1
        lda result+2
        ror
        clc                    ;add original speed Vxold :)
        adc mult24frc
        sta mult24frc
        lda result+1
        adc mult24lo
        sta mult24lo
        lda result+0
        adc mult24hi
        sta mult24hi           ;|V| is now in mult24

        lda ballylow        ;save the position where we collided
        sta oldy
        lda oldx2
        sta oldx

        lda ballxfrc2       ;move the ball back out of the wall
        sec                 ;while we still have the old speeds...
        sbc absspdxfrc2
        sta ballxfrc2
        lda ballxfrc
        sbc absspdxfrc
        sta ballxfrc
        lda ballxlow
        sbc absspdxlow
        sta ballxlow
        lda ballxhi
        sbc spdxhi
        sta ballxhi

        lda ballyfrc2
        sec
        sbc absspdyfrc2
        sta ballyfrc2
        lda ballyfrc
        sbc absspdyfrc
        sta ballyfrc
        lda ballylow
        sbc absspdylow
        sta ballylow
        lda ballyhi
        sbc spdyhi
        sta ballyhi

        ;-------------------------------------------------------
        ;this part is not necessary, ballyhi is checked again  -
        ;before the collisiondata is read                      -
        ;-------------------------------------------------------
        ;
        ;tay
        ;lda collisiontable1,y     ;select correct pixelrow
        ;sta col2+2
        ;lda collisiontable2,y
        ;sta col3+2

collisionsameyhigh3

        ;calculate new angle : newangle = -angle-wall-wall

        lda #0
        sec
        sbc temp2
        asl
        sec
        sbc angle
        sta angle

        .if KEEPHISTORY=1               ;put new ball angle (after collision) into
          ldy #3                        ;collisionhistory
          sta (collisionhistorylow),y
        .fi

        ;----------------------
        ;calculate new X-speed-
        ;----------------------

        eor #$40
        and #$7f
        tax
        lda sintable,x

        sta mult8
        jsr multiply24x8
        lda angle
        clc
        adc #$40
        bmi negxspeed

        ;put new x component..

        lda result+2
        sta absspdxfrc2
        lda result+1
        sta absspdxfrc
        lda result+0
        sta absspdxlow
        lda #0
        beq calcnewyspeed
negxspeed
        lda #0
        sec
        sbc result+2
        sta absspdxfrc2
        lda #0
        sbc result+1
        sta absspdxfrc
        lda #0
        sbc result+0
        sta absspdxlow
        lda #0
        sbc #0
calcnewyspeed
        sta absspdxhi

        ;calculate new Y-speed

        lda angle
        and #$7f
        tax
        lda sintable,x

        sta mult8
        jsr multiply24x8

        lda #0
        ldy angle
        bpl contcollision

        sec
        sbc result+2
        sta result+2
        lda #0
        sbc result+1
        sta result+1
        lda #0
        sbc result+0
        sta result+0
        lda #0
        sbc #0
contcollision
        sta absspdyhi

        .if DAMPING=1

          ;-----------------------------------------------------------
          ;calculate x component of speed normal to the wall         -
          ;use Vnormaltowall = (Vbeforecollision-Vaftercollision)/2  -
          ;-----------------------------------------------------------

          lda spdxfrc2
          sec
          sbc absspdxfrc2
          sta normalxfrc2
          lda spdxfrc
          sbc absspdxfrc
          sta normalxfrc
          lda spdxlow
          sbc absspdxlow
          cmp #$80
          ror
          sta normalxlow
          sta normalx2low
          lda normalxfrc
          ror
          sta normalxfrc
          sta normalx2frc
          lda normalxfrc2
          ror
          sta normalxfrc2
          sta normalx2frc2

          ;---------------------------------------------------
          ;calculate y component of speed normal to the wall -
          ;---------------------------------------------------

          lda spdyfrc2
          sec
          sbc result+2
          sta normalyfrc2
          lda spdyfrc
          sbc result+1
          sta normalyfrc
          lda spdylow
          sbc result+0
          cmp #$80
          ror
          sta normalylow
          sta normaly2low
          lda normalyfrc
          ror
          sta normalyfrc
          sta normaly2frc
          lda normalyfrc2
          ror
          sta normalyfrc2
          sta normaly2frc2

          ;-----------------------------
          ;reduce speed normal to wall -
          ;-----------------------------

          ldx material
          lda walldamping,x     ;number of times to divide - depends on material
          and #$7f
          tay
          beq enddampreduce
dampreduceloop
          lda normalylow
          asl
          ror normalylow
          ror normalyfrc
          ror normalyfrc2

          lda normalxlow
          asl
          ror normalxlow
          ror normalxfrc
          ror normalxfrc2
          dey
          bne dampreduceloop
enddampreduce
          lda walldamping,x
          bpl adddamping

          lda normalx2frc2
          sec
          sbc normalxfrc2
          sta normalxfrc2
          lda normalx2frc
          sbc normalxfrc
          sta normalxfrc
          lda normalx2low
          sbc normalxlow
          sta normalxlow
          lda normaly2frc2
          sec
          sbc normalyfrc2
          sta normalyfrc2
          lda normaly2frc
          sbc normalyfrc
          sta normalyfrc
          lda normaly2low
          sbc normalylow
          sta normalylow
adddamping
          ;--------------------------
          ;add damping to new speed -
          ;--------------------------

          lda absspdxfrc2
          clc
          adc normalxfrc2
          sta spdxfrc2
          lda absspdxfrc
          adc normalxfrc
          sta spdxfrc
          ldx #0
          lda normalxlow
          bpl *+3
          dex
          adc absspdxlow
          sta spdxlow
          txa
          adc absspdxhi
          sta spdxhi

          lda result+2
          clc
          adc normalyfrc2
          sta spdyfrc2
          lda result+1
          adc normalyfrc
          sta spdyfrc
          ldx #0
          lda normalylow
          bpl *+3
          dex
          adc result+0
          sta spdylow
          txa
          adc absspdyhi
          sta spdyhi
        .fi
        .if DAMPING=0
          lda absspdxfrc2
          sta spdxfrc2
          lda absspdxfrc
          sta spdxfrc
          lda absspdxlow
          sta spdxlow
          lda absspdxhi
          sta spdxhi
          lda result+2
          sta spdyfrc2
          lda result+1
          sta spdyfrc
          lda result+0
          sta spdylow
          lda absspdyhi
          sta spdyhi
        .fi
        .if KEEPHISTORY=1
          ldy #$0c
          lda spdxlow
          sta (collisionhistorylow),y
          iny
          lda spdxfrc
          sta (collisionhistorylow),y
          iny
          lda spdylow
          sta (collisionhistorylow),y
          iny
          lda spdyfrc
          sta (collisionhistorylow),y

          lda collisionhistorylow         ;pointers for next collision entry
          clc
          adc #$10
          sta collisionhistorylow
          bcc *+4
          inc collisionhistoryhi

          lda collisionhistoryhi          ;wrap collisionhistory after $1000 bytes
          cmp #>endcollisionhistory
          bne *+6
          lda #>collisionhistory
          sta collisionhistoryhi
        .fi

        lda #0                  ;set collided to 0 -> the angle and speed change after we add extra speed
        sta collided            ;so we can't use them as basis for the next collision.. :(

        lda flippercollision
        beq *+5
        jsr addflipperspeed2

        lda special             ;check if we have to add extra speed after the collision
        bmi addspeedaftercollision
        jmp moveballagain       ;we don't have to add extra speed

addspeedaftercollision
        cmp #%11000000          ;bit 6 & 7 set -> bumper!
        bcc nobumper

        ldx #0                  ;get bump vector from sinetable
        lda temp2
        eor #$80
        tay
        cpy #$81
        bcc *+3
        dex
        lda sintable,y
        sta absspdxfrc
        stx absspdxlow
        stx absspdxhi

        ldx #0
        lda temp2
        clc
        adc #$c0
        tay
        cpy #$81
        bcc *+3
        dex
        lda sintable,y
        sta absspdyfrc
        stx absspdylow
        stx absspdyhi

        lda special
        and #%00011111
        tax
        ldy bumperstrength,x

increasebumperloop
        asl absspdxfrc
        rol absspdxlow
        asl absspdyfrc
        rol absspdylow
        dey
        bpl increasebumperloop

        ;------------------------------
        ;add extra speed to ballspeed -
        ;------------------------------

        lda spdxfrc
        clc
        adc absspdxfrc
        sta spdxfrc
        lda spdxlow
        adc absspdxlow
        sta spdxlow
        lda spdxhi
        adc absspdxhi
        sta spdxhi

        lda spdyfrc
        clc
        adc absspdyfrc
        sta spdyfrc
        lda spdylow
        adc absspdylow
        sta spdylow
        lda spdyhi
        adc absspdyhi
        sta spdyhi
nobumper
        jmp moveballagain       ;and continue moving again!

        ;------------------------------------------------------------------------------
        ;old button-press code
        ;         ;-------------------------------------------
        ;         ;if we got here, the ball pressed a button -
        ;         ;-------------------------------------------
        ;
        ;         tax
        ;         lda #2
        ;         sta button1-1,x        ;set button-value to 2 (still being pressed)
        ;         bne nospecialcollision
        ;
        ;------------------------------------------------------------------------------

;------------------------------------------
;change back to original reference system -
;------------------------------------------

addflipperspeed
        ldx #0
        stx flippercollision

        lda spdxfrc
        clc
        adc xflipspeedfrc
        sta spdxfrc
        lda spdxlow
        adc xflipspeedlow
        sta spdxlow

        lda spdyfrc
        clc
        adc yflipspeedfrc
        sta spdyfrc
        lda spdylow
        adc yflipspeedlow
        sta spdylow

        .if KEEPFLIPPERHIS=1
          jsr nextflippercollision
        .fi

        rts
addflipperspeed2
        ldx #0
        stx flippercollision

        lda spdxfrc
        clc
        adc xflipspeedfrc
        sta spdxfrc
        lda spdxlow
        adc xflipspeedlow
        sta spdxlow
        lda spdxhi
        adc xflipspeedhigh
        sta spdxhi

        lda spdyfrc
        clc
        adc yflipspeedfrc
        sta spdyfrc
        lda spdylow
        adc yflipspeedlow
        sta spdylow
        lda spdyhi
        adc yflipspeedhigh
        sta spdyhi

        .if KEEPFLIPPERHIS=1
          jsr nextflippercollision
        .fi

        rts


;--------------------------------------------------------------------------------------


flippercollisiondetect
        .if TABLE=0
          cmp #44+27+1           ;correct!
        .fi
        .if TABLE=1
          cmp #44+27+1-1
        .fi
        bcc leftflipperdetect
        .if TABLE=0
          cmp #104-27            ;correct!
        .fi
        .if TABLE=1
          cmp #104-27-2
        .fi
        bcs rightflipperdetect
        jmp nocollision3
leftflipperdetect
        sec
        .if TABLE=0
          sbc #44                ;CORRECT
        .fi
        .if TABLE=1
          sbc #43
        .fi
        sta temp

        lda prevleftflipper
        ldy leftup
        ldx leftspeed
        jsr getflipperangle

        bcs noflipcollision2

        lda (low),y
        sta temp2

        .if KEEPFLIPPERHIS=1
          ldy #0
          lda timehigh
          sta (flippercollisionhistlow),y
          iny
          lda timelow
          sta (flippercollisionhistlow),y
          iny
          lda temp2
          sta (flippercollisionhistlow),y
          iny
          lda leftflipperspeed
          sta (flippercollisionhistlow),y
          iny
          lda ballxlow
          sta (flippercollisionhistlow),y
          iny
          lda ballylow
          sta (flippercollisionhistlow),y
        .fi

        ldx leftspeed            ;check if speed needs to be added
        beq doleftcollision      ;if 0 -> normal collision :)
        lda temp                 ;read multiplication factor
        bne leftflipaddspeed     ;if 0 -> normal collision

doleftcollision
        .if KEEPFLIPPERHIS=1
          ldy #6
          lda angle
          sta (flippercollisionhistlow),y
        .fi

        jmp movecloser3
leftflipaddspeed
        lda flipframe
        ldy leftup           ;if leftup == 0 -> flipper moves down
        beq *+5              ;correct for negative speeds
        clc
        adc #14  ; flipperframes

        ;TEMP
        lsr

        tax
        stx temp

        lda fxspeedfrc,x
        sta mult24frc
        ldy #0
        lda fxspeedlow,x
        sta mult24lo
        bpl *+3
        dey                  ;calculate hi byte of speed
        sty mult24hi

        lda ballxlow         ;calculate multiplication factor
        sec
        .if TABLE=0
          sbc #87
        .fi
        .if TABLE=1
          sbc #85
        .fi

        jmp addflipspeed

noflipcollision2
        ldx ballylow
        jmp nocollision

rightflipperdetect
        eor #$ff

        .if TABLE=0
          adc #104               ;+1 not necessary,as carry is set
        .fi
        .if TABLE=1
          adc #102
        .fi

        sta temp

        lda prevrightflipper
        ldy rightup
        ldx rightspeed
        jsr getflipperangle

        bcs noflipcollision2

        lda #0
        sec
        sbc (low),y
        sta temp2                ;angle of flipper at collision position

        .if KEEPFLIPPERHIS=1
          ldy #0
          lda timehigh
          sta (flippercollisionhistlow),y
          iny
          lda timelow
          sta (flippercollisionhistlow),y
          iny
          lda temp2
          sta (flippercollisionhistlow),y
          iny
          lda rightflipperspeed
          sta (flippercollisionhistlow),y
          iny
          lda ballxlow
          sta (flippercollisionhistlow),y
          iny
          lda ballylow
          sta (flippercollisionhistlow),y
        .fi

        lda temp                 ;read multiplication factor
        beq *+9                  ;if 0 -> normal collision
        ldx rightspeed
        lda fxspeedfrc,x
        bne rightflipaddspeed

        .if KEEPFLIPPERHIS=1
          ldy #6
          lda angle
          sta (flippercollisionhistlow),y
        .fi

        jmp movecloser3
rightflipaddspeed

        ldy #0
        tya
        sec
        sbc fxspeedfrc,x
        sta mult24frc
        tya
        sbc fxspeedlow,x
        sta mult24lo
        bpl *+3
        dey
        sty mult24hi

        stx temp

        .if TABLE=0
          lda #208       ;$68 -> 0  ==  208 -> 0
        .fi
        .if TABLE=1
          lda #204
        .fi
        sec
        sbc ballxlow

addflipspeed
        ldx flipframe
        cmp maxmultiply,x
        bcc *+6
        lda maxmultiply,x
        clc
        
        ;TEMP
        lsr
        ;lsr
        clc
        ;TEMP

        sta mult8

        ;multiply multiplication factor by speed of flipper -> 1,2,3,4 or 5...

        ldx flipspeed
        dex
        dex
        bmi *+4
        adc mult8     ;x2
        dex
        bmi *+4
        adc mult8     ;x3
        dex
        bmi *+4
        adc mult8     ;x4
        dex
        bmi *+4
        adc mult8     ;x5
        sta mult8

        .if KEEPFLIPPERHIS=1
          ldy #$10
          lda mult24hi
          sta (flippercollisionhistlow),y
          iny
          lda mult24lo
          sta (flippercollisionhistlow),y
          iny
          lda mult24frc
          sta (flippercollisionhistlow),y
        .fi

        jsr multiply24x8

        lda mult24hi
        bmi *+4                  ;correct for negative numbers!
        lda #$00
        sta xflipspeedhigh
        lda result+1
        sta xflipspeedlow
        lda result+2
        sta xflipspeedfrc

        .if KEEPFLIPPERHIS=1
          ldy #$13
          lda xflipspeedhigh
          sta (flippercollisionhistlow),y
          iny
          lda xflipspeedlow
          sta (flippercollisionhistlow),y
          iny
          lda xflipspeedfrc
          sta (flippercollisionhistlow),y
        .fi

        ldx temp
        lda fyspeedfrc,x
        sta mult24frc
        ldy #0
        lda fyspeedlow,x
        sta mult24lo
        bpl *+3
        dey
        sty mult24hi

        .if KEEPFLIPPERHIS=1
          ldy #8
          lda mult24hi
          sta (flippercollisionhistlow),y
          iny
          lda mult24lo
          sta (flippercollisionhistlow),y
          iny
          lda mult24frc
          sta (flippercollisionhistlow),y
        .fi

        jsr multiply24x8

        lda mult24hi
        bmi *+4                  ;correct for negative numbers!
        lda #$00
        sta yflipspeedhigh
        lda result+1
        sta yflipspeedlow
        lda result+2
        sta yflipspeedfrc

        .if KEEPFLIPPERHIS=1
          ldy #$b
          lda yflipspeedhigh
          sta (flippercollisionhistlow),y
          iny
          lda yflipspeedlow
          sta (flippercollisionhistlow),y
          iny
          lda yflipspeedfrc
          sta (flippercollisionhistlow),y
          iny
          lda temp
          sta (flippercollisionhistlow),y
          iny
          lda mult8
          sta (flippercollisionhistlow),y
          iny
        .fi

        lda #1
        sta flippercollision     ;set change of reference flag
        sta flipperhit

        .if KEEPFLIPPERHIS=1
          ldy #$18
          lda spdxlow
          sta (flippercollisionhistlow),y
          iny
          lda spdxfrc
          sta (flippercollisionhistlow),y
          iny
          lda spdylow
          sta (flippercollisionhistlow),y
          iny
          lda spdyfrc
          sta (flippercollisionhistlow),y
        .fi

        lda spdxfrc              ;change to new reference system
        sec
        sbc xflipspeedfrc
        sta spdxfrc
        sta spd2xfrc
        lda spdxlow
        sbc xflipspeedlow
        sta spdxlow

        ldx #0
        stx collided
        lda spdyfrc
        sec
        sbc yflipspeedfrc
        sta spdyfrc
        sta spd2yfrc
        lda spdylow
        sbc yflipspeedlow
        sta spdylow

        ;make positive copies & prepare to calculate angle

        stx spd2yfrc2
        stx spd2xfrc2

        bpl flipypos
        txa
        sec
        sbc spdyfrc
        sta spd2yfrc
        txa
        sbc spdylow
        ldx #4
flipypos
        sta spd2ylow

        lda spdxlow
        bpl flipxpos
        inx
        inx
        lda #0
        sec
        sbc spdxfrc
        sta spd2xfrc
        lda #0
        sbc spdxlow
flipxpos
        sta spd2xlow
        stx angle        ;save quadrant information (see above)

        ;lda spd2xlow
        ora spd2ylow     ;if both spd2xlow and spd2ylow are 0 -> maybe we have to shift in bits from spd2frc2!
        bne flipbigspeed ;at least one has speed > 1pixel/frame

        lda spd2xfrc2    ;'multiply' x-speed by 256
        ldx spd2xfrc
        sta spd2xfrc
        stx spd2xlow

        lda spd2yfrc2    ;'multiply' y-speed by 256
        ldx spd2yfrc
        sta spd2yfrc
        stx spd2ylow
flipbigspeed

        .if KEEPFLIPPERHIS=1
          ldy #$1c
          lda spd2xlow
          sta (flippercollisionhistlow),y
          iny
          lda spd2xfrc
          sta (flippercollisionhistlow),y
          iny
          lda spd2ylow
          sta (flippercollisionhistlow),y
          iny
          lda spd2yfrc
          sta (flippercollisionhistlow),y
        .fi

        jsr calcangle

        .if KEEPFLIPPERHIS=1
          ldy #6
          lda angle
          sta (flippercollisionhistlow),y
         .fi

        jmp checkforballpass

;--------


timecompare2
        .byte 255
        .byte 128/2,255
        .byte 128/3,128/3*2,255
        .byte 128/4,128/4*2,128/4*3,255
        .byte 128/5,128/5*2,128/5*3,128/5*4,255
        .byte 128/6,128/6*2,128/6*3,128/6*4,128/6*5,255
timecompare=*-1
        ;.byte 0-1
        .byte 1-1,3-1,6-1,10-1,15-1

prevframe    .byte 0  ;previous flipper frame
updown       .byte 0  ;flipper moves up or down
flipspeed    .byte 0

getflipperangle
        ;here we select the correct flippertween to use
        ;depending on flipperframe and flipperspeed

        sta prevframe
        sty updown
        stx flipspeed

        ;x must hold flipperspeed

        ldy timecompare,x
        ldx #$ff             ;<- frame to be played + previous frame
        lda timeinaframe

        inx
        iny
        cmp timecompare2,y   ;compare current time in the frame to switch-times, depending on speed
        bcs *-5

        ;x now holds how many frames we moved so far..

        txa
        ldy updown
        beq *+7              ;if we move down, make speed negative
        eor #$ff
        ;clc
        adc #1

        clc                  ;add to previous frame
        adc prevframe

        ;check if we didnt move outside frame# bounds..

        bpl *+4
        lda #0               ;don't allow negative frame #'s
        cmp #flipperframes   ;max frame#
        bcc *+4
        lda #flipperframes-1
        sta flipframe
        tax

        lda flipcollisionlow,x
        sta low
        lda flipcollisionhigh,x
        sta high

        .if KEEPFLIPPERHIS=1
          txa
          ldy #7
          sta (flippercollisionhistlow),y
        .fi

        lda temp           ;flipper column
        asl
        cmp maxmultiply,x  ;compare with the length of the flipper
        beq specialflipcollision
        bcs noflipcollisionnosec
        asl
        tay
        lda (low),y
        .if TABLE=0
          clc
          adc #3
        .fi
        .if TABLE=1
          sec
          sbc #7
        .fi
        cmp ballylow
        bcs noflipcollisionnosec
        iny
        ;clc               ;not necessary because of compare
        .if TABLE=0
          ;sec
          sbc #2 ;3 -> 2 because carry = clear
          clc
        .fi
        .if TABLE=1
          ;clc
          adc #7
          clc
        .fi
        adc (low),y        ;calculate average of top & bottom y-position to see where the flipper is hit
        ror
        .if TABLE=0
          clc
          adc #3
        .fi
        .if TABLE=1
          sec
          sbc #7
        .fi
        cmp ballylow
        bcc notintoppart

        ;if we got here, the top of the flipper is hit!
normalflippercollision
        iny
        clc        ;carry must be clear
        rts

notintoppart
        lda (low),y
        .if TABLE=0
          clc
          adc #3
        .fi
        .if TABLE=1
          sec
          sbc #7
        .fi
        iny
        cmp ballylow
        bcs normalflippercollision   ;if we branch here, the bottom of the flipper is hit!
noflipcollisionsec
        sec
noflipcollisionnosec    ;carry must be set!
        rts

;special piece of detection code for the sides of the flippers

specialflipcollision
        asl
        tay
        lda ballylow
        .if TABLE=0
          sec
          sbc #3
        .fi
        .if TABLE=1
          clc
          adc #7
        .fi

        cmp (low),y          ;rle decode
        bcc noflipcollisionsec
        iny
        iny
        sbc (low),y
        bcs *-4
        dey
        lda (low),y
        cmp #$55             ;if empty
        beq noflipcollisionnosec  ;-> no collision - same value, so carry is set
        clc                  ;carry clear -> collision
        rts


;-----------------------------------------------------------------------

nextflippercollision
        .if KEEPFLIPPERHIS=1
          lda flippercollisionhistlow
          clc
          adc #$40
          sta flippercollisionhistlow
          bcc *+4
          inc flippercollisionhisthigh

          lda flippercollisionhisthigh
          cmp #>endflippercollisionhistory
          beq *+3
          rts

          lda #<flippercollisionhistory
          sta flippercollisionhistlow
          lda #>flippercollisionhistory
          sta flippercollisionhisthigh
          rts
        .fi

;--------------------------------------------------------------------------------------

        .if JOYCONTROL=1

joystick .byte 0

joydebug
        lda #0
        sta spdxfrc2
        sta spdxfrc
        sta spdxlow
        sta spdxhi
        sta spdyfrc2
        sta spdyfrc
        sta spdylow
        sta spdyhi

        lsr joystick
        bcs *+15
        lda ballylow
        sec
        sbc #1
        sta ballylow
        lda ballyhi
        sbc #0
        sta ballyhi

        lsr joystick
        bcs *+8
        inc ballylow
        bne *+4
        inc ballyhi

        lsr joystick
        bcs *+15
        lda ballxlow
        sec
        sbc #1
        sta ballxlow
        lda ballxhi
        sbc #0
        sta ballxhi

        lsr joystick
        bcs *+8
        inc ballxlow
        bne *+4
        inc ballxhi

        rts

        .fi

;--------------------------------------------------------------------------------------

pinball
        .if TABLE=0
        ;  jsr diedemocycle
        .fi

        rts


;========NIGHTMARE===========================
.if TABLE=0

  ;------------------------------
  ;cycle through the die-lights -
  ;------------------------------

  diedemocycle

          lda dietime
          beq *+5
          dec dietime
          rts

          lda #16
          sta dietime

          lda dielights
          clc
          adc #1
          and #7
          sta dielights
          sta temp

          ldx #$80
          ldy #$81

          lsr temp
          bcc *+10
          lda dielight3    ;turn light on
          bne *+12
          sty dielight3
          beq *+8

          lda dielight3    ;turn light off
          beq *+4
          stx dielight3

          ;---

          lsr temp
          bcc *+10
          lda dielight2    ;turn light on
          bne *+12
          sty dielight2
          beq *+8

          lda dielight2    ;turn light off
          beq *+4
          stx dielight2

        ;---

          lsr temp
          bcc *+10
          lda dielight1    ;turn light on
          bne *+12
          sty dielight1
          beq *+8

          lda dielight1    ;turn light off
          beq *+4
          stx dielight1

          rts

.fi
;========NIGHTMARE===========================

;--------------------------------------------------------------------------------------

dotmatrix

        lda #$00
        sta $dd00
        lda #$e0
        sta $d018
        lda #240
        sta $fbf8
        sta $fbf9
        sta $fbfa
        sta $fbfb
        sta $fbfc
        sta $fbfd
        sta $fbfe
        sta $fbff

        ; Places the sprites for the dotmatix display

        lda #$ff        ; only 0-7
        sta $d015        ;all enable
        sta $d01c        ;all multicolor
        sta $d01d        ;all X-expanded
        sta $d017        ;all Y-expanded
        sta $d01b        ;all sprites in front of gfx (should be behind later!)

        ;set dotmatrix colors
        lda #$00
        ;sta $d025        ;color %01 to black
        ;sta $d026        ;color %10 to black
        sta $d027
        sta $d029
        sta $d02b

        ; Center the 8 sprites on the screen

        lda #240
        sta $d000
        lda #40
        sta $d002
        lda #88
        sta $d004
        lda #136
        sta $d006
        lda #184
        sta $d008
        lda #232
        sta $d00a
        lda #24
        sta $d00c
        lda #72
        sta $d00e

        lda #$C1
        sta $d010

        ; Y-Position

        lda #$1e
        sta $d001
        sta $d003
        sta $d005
        sta $d007
        sta $d009
        sta $d00b
        sta $d00d
        sta $d00f

        rts

display
;-----------------
;algemene dingen -
;-----------------
        .if TABLE=0   ;set background color
          lda #$06
        .fi
        .if TABLE=1
          lda #$00
        .fi
        sta $d021

        lda #$00      ;turn expansion off
        sta $d01d
        sta $d017
        lda #$e8+2    ;set flippers + spring to multicolor
        sta $d01c
        lda #2        ;lower priority of spring-sprite
        sta $d01b

        ; Set the precalced VIC values
        lda _D015
        sta $d015

        lda _D048
        sta $d000
        sta $d004
        sta $d008
        lda _D159
        sta $d001
        sta $d005
        sta $d009
        lda _D00A
        sta $d00a
        lda _D007
        sta $d007
        lda _D00B
        sta $d00b
        lda _D00C
        sta $d00c
        lda _D00F
        sta $d00f
        lda _D00D
        sta $d00d
        lda _D006
        sta $d006
        lda _D00E
        sta $d00e
        lda _D010
        sta $d010

        lda #$42        ; shooter
        sta $d002
        lda _D003
        sta $d003

        ;set spritepointers

        ldx #(spriteimage/64)&255   ;set spritepointers
        stx $8ffc
        ldx #(spriteimage2/64)&255
        stx $8ffa
        ldx #(spriteimage3/64)&255
        stx $8ff8

        ldx #(spriteimageb/64)&255
        stx $5ffc
        ldx #(spriteimage2b/64)&255
        stx $5ffa
        ldx #(spriteimage3b/64)&255
        stx $5ff8

        ldx #(spriteimagec/64)&255
        stx $e3fc
        ldx #(spriteimage2c/64)&255
        stx $e3fa
        ldx #(spriteimage3c/64)&255
        stx $e3f8

        ; Set colors

        lda #$01    ;color of flipper centre
        sta $d026

        .if TABLE=0
          ldx #$0d  ;flipper colors
          lda #$05
        .fi
        .if TABLE=1
          ldx #$0a
          lda #$02
        .fi

        stx $d025
        sta $d02a
        sta $d02c
        sta $d02d
        sta $d02e
        lda #$0c
        sta $d028
        lda #$0b
        sta $d027
        lda #$0f
        sta $d029
        lda #$0c
        sta $d02b
        rts

display_precalc

        ;------------------------------
        ;set right sprite-coordinates -
        ;------------------------------

        lda #$15
        sta _D015

        ;--------------
        ;display ball -
        ;--------------

        lda ballxfrc
        asl
        lda ballxlow
        ;clc
        adc #24-7
        tax
        and #$f8
        sta _D048

        lda ballxhi
        adc #0
        beq *+4
        lda #$15

        ora #$02           ;shootersprite
        sta _D010
        txa
        and #$07
        sta clipx

        lda ballylow
        sec
        sbc tableylow
        clc
        adc #$50-7          ;$50 is y position of sprite at the top position
        sta _D159

        jsr calcclippedsprite  ;clip the sprite

        ;------------------
        ;display flippers -
        ;------------------

        ;check if the flippers should be displayed or not..

        lda tableyhigh
        bne *+5
        jmp skipdisplayflippers
        lda tableylow
        .if TABLE=0
          cmp #$1a
        .fi
        .if TABLE=1
          cmp #$10
        .fi
        bcc skipdisplayflippers     ;skip displaying the flippers if they are off the screen

        lda _D015
        ora #$e8
        sta _D015
        lda #<leftflipperxoriginal
        sta _D006
        lda #<rightflipperxoriginal
        sta _D00E

        lda leftflipperanim
        lsr
        tax
        lda leftflipperx,x
        sta _D00A
        lda bigflipperyoffset,x
        sec
        sbc tableylow

        .if TABLE=0
          clc
          adc #3
        .fi
        .if TABLE=1
          sec
          sbc #7
        .fi

        sta _D007
        clc
        adc smallflipperyoffset,x
        sta _D00B

        lda rightflipperanim
        lsr
        tax
        lda rightflipperx,x
        sta _D00C
        lda bigflipperyoffset,x
        sec
        sbc tableylow

        .if TABLE=0
          clc
          adc #3
        .fi
        .if TABLE=1
          sec
          sbc #7
        .fi

        sta _D00F
        clc
        adc smallflipperyoffset,x
        sta _D00D

        lda leftflipperanim
        lsr
        asl
        ;clc
        adc #64
        sta leftflipperpointer
        lda rightflipperanim
        lsr
        asl
        ;clc
        adc #64+2*7
        sta rightflipperpointer

skipdisplayflippers

        ;-----------------
        ;display shooter -
        ;-----------------

        ;check if the shooter should be displayed or not...

        lda tableyhigh
        beq skipdisplayshooter

        lda tableylow
        cmp #$43
        bcc skipdisplayshooter

        lda _D015
        ora #$02
        sta _D015

        lda shooterposition
        lsr
        lsr
        lsr
        clc
        .if TABLE=0
          adc #$39
        .fi
        .if TABLE=1
          adc #$38
        .fi
        sec
        sbc tableylow
        sta _D003

skipdisplayshooter

        rts

.if TABLE=0
  leftflipperxoriginal  = $70        ;x position of left flipper
  rightflipperxoriginal = $d0        ;x position of right flipper
  flipperyoriginal      = $c5        ;y position of both flippers
.fi
.if TABLE=1
  leftflipperxoriginal  = $6e        ;x position of left flipper
  rightflipperxoriginal = $cc        ;x position of right flipper
  flipperyoriginal      = $ba        ;y position of both flippers
.fi
;-------------------------------------------------------------------------------------

;this routine 'cuts' pieces out of the ball-sprite
;this way the ball can move behind all sorts of objects

;===========NIGHTMARE SPECIAL==================================================
.if TABLE=0           ;special code for Nightmare!                            =
  specialfix          ;selects the correct y-row when the ball is in layer 2  =
          cpy #8*2                                                           ;=
          bcs specialfix2                                                    ;=
                                                                             ;=
          ldy #60*2                                                          ;=
          bne calcclip3                                                      ;=
  specialfix2                                                                ;=
          cpy #45*2                                                          ;=
          bcc calcclip4                                                      ;=
          cpy #51*2                                                          ;=
          bcs calcclip4                                                      ;=
          tya                                                                ;=
          ;clc                                                               ;=
          adc #6*2                                                           ;=
          tay                                                                ;=
          bne calcclip3                                                      ;=
.fi                                                                          ;=
;===========NIGHTMARE SPECIAL==================================================

calcclippedsprite

        ;calculate position of chars needed for clipping
        ;xposition

        lda ballxfrc
        asl
        lda ballxlow
        adc #0
        tay

        lda ballxhi   ;get position of left side of sprite
        adc #0
        lsr
        tya
        ror
        sbc #3
        lsr           ;shift right to get charposition
        lsr
        sta ballx2

        ldx ballylow
        dex
        txa
        and #7
        sta clipoffset+1

        ldx #2              ;fetch 2 charrows
                            ;if the top of the ball is in pixel 0 or 1, we only need to fetch
        cmp #6              ;2 charrows, this corresponds to the middle of the ball being
        bcs *+3             ;at pixel 0 or 7 OR clipoffset+1 being 6 or 7.
        inx                 ;if the middle is not at pixel 0 or 7, we fetch 3 rows instead
        stx irqtemp2        ;=number of rows to fetch

        lda ballyhi         ;calculate in what charrow the top of the ball is in
        lsr
        lda ballylow
        ror
        sbc #3              ;substract radius of the ball (7)

        ;bcs *+6            ;quick fix
        ;ldy #$7e
        ;bne calcclip2

        lsr
calcclip2
        lsr
        sta charscreenrow
        asl
        tay

        ;======NIGHTMARE SPECIAL=====================
        .if TABLE=0                                ;=
          lda layer                                ;=
          bne specialfix                           ;=
          cpy #51*2                                ;=
          bcc *+4                                  ;=
        calcclip4                                  ;=
          ldy #57*2   ;point to empty clipmap area ;=
        calcclip3                                  ;=
        .fi                                        ;=
        ;======NIGHTMARE SPECIAL=====================

        ;======IGNITION SPECIAL======================
        .if TABLE=1                                ;=
          cpy #32*2        ;if charrow 32 or bigger =
          bcs clipignition ;point to row 0          =
          lda layer        ;if layer 1              =
          beq *+4          ;point to row 0          =
        clipignition                               ;=
          ldy #0                                   ;=
        .fi
        ;======IGNITION SPECIAL======================

        sty bally2

        ;get clipchars from clipmap, decrunch!

decrunchcliploop2
        lda layer0clipmap,y
        sta irqlow
        lda layer0clipmap+1,y
        sta irqhigh

        ldx #3                   ;fetch 3 chars each row
        lda ballx2

        ldy #1
        cmp (irqlow),y
        bcc *+8
        iny                      ;'decrunch' clip-data by looping until
        iny                      ; ballx < the boundarydata
decrunchcliploop
        cmp (irqlow),y
        bcs *-4
        dey
        lda (irqlow),y          ; read clipmap data
        pha
        dex
        beq *+9
        txa                     ; if x=2 -> eor #3 -> 1 -> ballx+1 is ok!
        ;clc                    ; if x=1 -> eor #3 -> 2 -> ballx+2 is ok!
        eor #3                  ; x=0 and x=3 never get here..
        adc ballx2
        bne decrunchcliploop-1

        lda bally2
        adc #2
        and #$7e
        tay
        sty bally2
        inc charscreenrow
        dec irqtemp2            ; one row done
        bne decrunchcliploop2

;calculate clipped ball

        ldx clipx               ;use clipx to select correct shifted spriteimage
        lda spriteimagefrom1,x
        sta spritea1+1
        sta spritea2+1
        sta spritea3+1
        lda spriteimagefrom2,x
        sta spriteb1+1
        sta spriteb2+1
        sta spriteb3+1
        lda spriteimagefrom3,x
        sta spritec1+1
        sta spritec2+1
        sta spritec3+1
        lda spriteimagefrom4,x
        sta spritea1+2
        sta spritea2+2
        sta spritea3+2
        lda spriteimagefrom5,x
        sta spriteb1+2
        sta spriteb2+2
        sta spriteb3+2
        lda spriteimagefrom6,x
        sta spritec1+2
        sta spritec2+2
        sta spritec3+2

        ldx #0
        ldy charscreenrow
        cpy #26                 ;bank switch at 25 (+1, we moved one too many in above code)
        bcc *+8
        inx
        cpy #51                 ;bank switch at 50 (+1, we moved one too many in above code)
        bcc *+3
        inx
        stx d018now             ;specifies in what bank the sprite is in..

        lda #$30
        sta $01

        ldy #44                 ;15 rows of 3 bytes to be copied
bigbigcliploop
        lda spritepointers,x
        sta point1a+1
        sta point1b+1
        sta point1c+1
        lda spritepointers+9,x
        sta point1a+2
        sta point1b+2
        sta point1c+2
        lda spritepointers+3,x
        sta point2a+1
        sta point2b+1
        sta point2c+1
        lda spritepointers+3+9,x
        sta point2a+2
        sta point2b+2
        sta point2c+2
        lda spritepointers+6,x
        sta point3a+1
        sta point3b+1
        sta point3c+1
        lda spritepointers+6+9,x
        sta point3a+2
        sta point3b+2
        sta point3c+2

bigcliploop
        pla
        tax
        lda clipcharslow,x
        sta char1+1
        lda clipcharshigh,x
        sta char1+2

        pla
        tax
        lda clipcharslow,x
        sta char2+1
        lda clipcharshigh,x
        sta char2+2

        pla
        tax
        lda clipcharslow,x
        sta char3+1
        lda clipcharshigh,x
        sta char3+2

clipoffset ldx #0
cliploop
spritea1   lda $1000,y
char1      and $1000,x
point1a    sta spriteimage,y
spriteb1   and $1000,y
point2a    sta spriteimage2,y
spritec1   and $1000,y
point3a    sta spriteimage3,y
           dey
spritea2   lda $1000,y
char2      and $1000,x
point1b    sta spriteimage,y
spriteb2   and $1000,y
point2b    sta spriteimage2,y
spritec2   and $1000,y
point3b    sta spriteimage3,y
           dey
spritea3   lda $1000,y
char3      and $1000,x
point1c    sta spriteimage,y
spriteb3   and $1000,y
point2c    sta spriteimage2,y
           beq point3c
spritec3   and $1000,y
point3c    sta spriteimage3,y

        dey
        bmi endclip
        dex
        bpl cliploop

        ;here is right between two char rows
        ;if we are also between two vic banks, we need to change the sprite image also

        lda #7
        sta clipoffset+1

        dec charscreenrow
        lda charscreenrow
        cmp #25
        bne noswitchbank
switchbank
        ldx d018now
        dex
        jmp bigbigcliploop
noswitchbank
        cmp #50
        beq switchbank
        jmp bigcliploop
endclip
        lda #$35
        sta $01
        rts

;----------------------------------------------------------------------------------------

music
        jsr $1003
        rts

;-----------------------------------------------------------------------------------------

;this routine check if certain keys are being pressed
;keyregister = 0 when not pressed, any other value -> key is pressed

checkforkeys

        ldx #5
checkkeyloop
        lda keycolumn,x
        sta $dc00
        lda $dc01
        eor #$ff
        ldy keyindex,x
        and keyrow,x
        sta $00,y

        dex
        bpl checkkeyloop

        .if KEEPHISTORY=1
          ;this routine clears the collision-history when space is pressed!

          lda tiltkey
          beq endcollisionclear

          lda #<collisionhistory
          sta collisionhistorylow
          lda #>collisionhistory
          sta collisionhistoryhi

          ldy #0
          collisionclearloop
          lda #0
          sta (collisionhistorylow),y
          iny
          bne *-3

          inc collisionhistoryhi
          lda collisionhistoryhi
          cmp #>endcollisionhistory
          bne collisionclearloop

          lda #>collisionhistory
          sta collisionhistoryhi

          lda #0
          sta startgameloop

          endcollisionclear
        .fi
        .if KEEPFLIPPERHIS=1

          ;this routine clears the flipper collision-history when space is pressed!

          lda tiltkey
          beq endcollisionclear2

          lda #<flippercollisionhistory
          sta flippercollisionhistlow
          lda #>flippercollisionhistory
          sta flippercollisionhisthigh

          ldy #0
          collisionclearloop2
          lda #0
          sta (flippercollisionhistlow),y
          iny
          bne *-3

          inc flippercollisionhisthigh
          lda flippercollisionhisthigh
          cmp #>endflippercollisionhistory
          bne collisionclearloop2

          lda #>flippercollisionhistory
          sta flippercollisionhisthigh

          lda #0
          sta startgameloop

          endcollisionclear2
        .fi

        rts

;-----------------------------------------------------------------------------------------

;this routine multiplies a 24 bit number (speed) by an 8 bit number (sinus)

multiply24x8
        lda #0
        sta result02+1
        sta result12+1
        sta result22+1

        ldy mult8      ;copy hi-byte of 24-bit arg
        tya            ;check if we remove bits by shifting right..
        eor mult24hi
        lsr
        tya
        bcc multiply1c ;if not, continue

        lsr a          ;correct for the missing bit 0... either mult1 or mult2 has bit 0 set...
        bcs multiply1a

        sty result02+1 ;mult2 has bit0 set -> add mult1 to result!!
        bcc multiply1b
multiply1a
        ldx mult24hi   ;mult1 has bit0 set -> add mult2 to result!
        stx result02+1
multiply1b
        asl            ;y= old y and #$fe
multiply1c
        adc mult24hi   ;determine which is bigger, mult1 or mult2
        ror a          ;carry jitter door clc/sec
        tay            ;(mult2+mult1)/2 -> y
        adc #0         ;adds 1 if mult2 is odd
        sec
        sbc mult24hi
        bcs multiply1d
        eor #$ff
        adc #1
        sec
multiply1d
        tax            ;(mult2+mult1)/2-mult1=(mult2-mult1)/2 -> x
        lda squarelow,y
        ;sec
        sbc squarelow,x
        sta result01+1
        lda squarehigh,y
        sbc squarehigh,x
        sta result+0

;--------------------------------

        ldy mult8      ;copy hi-byte of 24-bit arg
        tya            ;check if we remove bits by shifting right..
        eor mult24lo
        lsr
        tya
        bcc multiply2c ;if not, continue

        lsr a          ;correct for the missing bit 0... either mult1 or mult2 has bit 0 set...
        bcs multiply2a

        sty result12+1 ;mult2 has bit0 set -> add mult1 to result!!
        bcc multiply2b
multiply2a
        ldx mult24lo   ;mult1 has bit0 set -> add mult2 to result!
        stx result12+1
multiply2b
        asl            ;y= old y and #$fe
multiply2c
        adc mult24lo   ;determine which is bigger, mult1 or mult2
        ror a          ;carry jitter door clc/sec
        tay            ;(mult2+mult1)/2 -> y
        adc #0         ;adds 1 if mult2 is odd
        sec
        sbc mult24lo
        bcs multiply2d
        eor #$ff
        adc #1
        sec
multiply2d
        tax            ;(mult2+mult1)/2-mult1=(mult2-mult1)/2 -> x
        lda squarelow,y
        ;sec
        sbc squarelow,x
        sta result11+1
        lda squarehigh,y
        sbc squarehigh,x
        pha

;--------------------------------
        ldy mult8      ;copy hi-byte of 24-bit arg
        tya            ;check if we remove bits by shifting right..
        eor mult24frc
        lsr
        tya
        bcc multiply3c ;if not, continue

        lsr a          ;correct for the missing bit 0... either mult1 or mult2 has bit 0 set...
        bcs multiply3a

        sty result22+1 ;mult2 has bit0 set -> add mult1 to result!!
        bcc multiply3b
multiply3a
        ldx mult24frc  ;mult1 has bit0 set -> add mult2 to result!
        stx result22+1
multiply3b
        asl            ;y= old y and #$fe
multiply3c
        adc mult24frc  ;determine which is bigger, mult1 or mult2
        ror a          ;carry jitter door clc/sec
        tay            ;(mult2+mult1)/2 -> y
        adc #0         ;adds 1 if mult2 is odd
        sec
        sbc mult24frc
        bcs multiply3d
        eor #$ff
        adc #1
        sec
multiply3d
        tax            ;(mult2+mult1)/2-mult1=(mult2-mult1)/2 -> x
        lda squarelow,y
        ;sec
        sbc squarelow,x
        sta result21+1
        lda squarehigh,y
        sbc squarehigh,x
        tax

;--------------------------------
        ;finalise answer by adding all partial results

result22 lda #0
         clc
result21 adc #0

result20 txa
result11 adc #0
         tay             ;result+2

result10 pla
result01 adc #0
         tax             ;result+1

         bcc *+5
         inc result+0
         clc

         tya             ;result+2
         ;clc
result12 adc #0
         sta result+2
         txa             ;result+1
result02 adc #0
         sta result+1
         bcc *+4
         inc result+0

        rts

;--------------------------------------------------------------------------------------------------------------------

balllost

        ;put ball back in the duct

        lda #1
        sta layer        ;put ball in bottom layer
        sta ballyhi
        sta ballxhi
        lda #$c0         ;put ball in duct
        sta ballylow
        lda #$34
        sta ballxlow

        rts

;--------------------------------------------------------------------------------------------------------------------

coshtable  ;table holds values of ((1/cos(angle))-1)*512

        .byte 0,0,1,1,2,4,6,8,10,13,16,19,23,27,32,37,42,48,54,61,69,76,85,94,104,114,125,137,150,164,179,195,212
        .byte 195,179,164,150,137,125,114,104,94,85,76,69,61,54,48,42,37,32,27,23,19,16,13,10,8,6,4,2,1,1,0

;-------------------------------------------------------------------------------------------------------------------
;-------------------------------------------------------------------------------------------------------------------
;-------------------------------------------------------------------------------------------------------------------

;END OF ENGINE!!!






















;START OF DATA!!!

;-------------------------------------------------------------------------------------------------------------------
;-------------------------------------------------------------------------------------------------------------------
;-------------------------------------------------------------------------------------------------------------------
;-------------------------------------------------------------------------------------------------------------------

.if TABLE=0     ;NIGHTMARE
  .include .\includes\nightmar\source\buttons.txt
  .include .\includes\nightmar\source\lights.txt
  .include .\includes\nightmar\source\clipdata.txt
  .include .\includes\nightmar\source\inbitmap.txt
  .include .\includes\nightmar\source\maps.txt
*=$8000
clipcharset
  .include .\includes\nightmar\source\clipchar.txt
.fi

.if TABLE=1     ;IGNITION
  .include .\includes\ignition\source\buttons.txt
  .include .\includes\ignition\source\lights.txt
  .include .\includes\ignition\source\clipdata.txt
  .include .\includes\ignition\source\inbitmap.txt
  .include .\includes\ignition\source\maps.txt
*=$8000
clipcharset
  .include .\includes\ignition\source\clipchar.txt
.fi


*=$0600
flipperdata
  .include .\sources\flipdata.txt

;-------------------------------------------------------------------------------------------------------------------

;
;        ------   = angle $0          |\\   = angle $40
;        \\\\\\\                      |\\
;                                     |\\
;
; $01 == go to layer 0
; $03 == go to layer 1
; any other odd number -> press button x/2-2

;------------------------------------------------------------------------------------------------

swapnybble       = $0200
;flipperdata      = $0600  ;->$0b00
sintable         = $0c00  ;used in friction
atandata         = $0d00  ;used to calc angle
loghigh          = $0e00  ;used to calc angle
loglow           = $0f00  ;used to calc angle
;tune            = $1000
;bitmap0col      = $5c00...$6000
;bitmap0         = $6000...$7f40

spriteimageb     = $7e80  ;this is where the calculated clipped ballsprite goes
spriteimage2b    = $7ec0
spriteimage3b    = $7f00

;clipcharset      = $8000  ;charset with all the chars for the clipmap
squarelow        = $8400  ;lsb of table of squares
squarehigh       = $8500  ;msb of table of squares
;memd800colors   = $8600
;bitmap1col      = $8c00...$9000
collisionhistory           = $9000  ;history of collisions  TEMPORARY
endcollisionhistory        = $9800
flippercollisionhistory    = $9800
endflippercollisionhistory = $a000
;bitmap1         = $a000...$c000

spriteimage      = $bf40
spriteimage2     = $bf80
spriteimage3     = $bfc0

;bitmap2         = $c000...$e000  (including room for 28 sprites)
;flippersprites  = $d000...$d700
;bitmap2col      = $e000...$e400
spriteimagec     = $e440
spriteimage2c    = $e400
spriteimage3c    = $e4c0
;springsprite    = $e480

;------------------------------------------------------------------------------------------------

*=sintable
        .byte $00,$06,$0D,$13,$19,$1F,$25,$2C,$32,$38,$3E,$44,$4A,$50,$56,$5C,$62,$67,$6D,$73,$78,$7E,$83,$88,$8E,$93,$98,$9D,$A2,$A7,$AB,$B0
        .byte $B4,$B9,$BD,$C1,$C5,$C9,$CD,$D0,$D4,$D7,$DB,$DE,$E1,$E4,$E7,$E9,$EC,$EE,$F0,$F2,$F4,$F6,$F7,$F9,$FA,$FB,$FC,$FD,$FE,$FE,$FF,$FF
        .byte $FF,$FF,$FF,$FE,$FE,$FD,$FC,$FB,$FA,$F9,$F7,$F6,$F4,$F2,$F0,$EE,$EC,$E9,$E7,$E4,$E1,$DE,$DB,$D7,$D4,$D0,$CD,$C9,$C5,$C1,$BD,$B9
        .byte $B4,$B0,$AB,$A7,$A2,$9D,$98,$93,$8E,$88,$83,$7E,$78,$73,$6D,$67,$62,$5C,$56,$50,$4A,$44,$3E,$38,$32,$2C,$25,$1F,$19,$13,$0D,$06
        .byte $00,$FA,$F3,$ED,$E7,$E1,$DB,$D4,$CE,$C8,$C2,$BC,$B6,$B0,$AA,$A4,$9E,$99,$93,$8D,$88,$82,$7D,$78,$72,$6D,$68,$63,$5E,$59,$55,$50
        .byte $4C,$47,$43,$3F,$3B,$37,$33,$30,$2C,$29,$25,$22,$1F,$1C,$19,$17,$14,$12,$10,$0E,$0C,$0A,$09,$07,$06,$05,$04,$03,$02,$02,$01,$01
        .byte $01,$01,$01,$02,$02,$03,$04,$05,$06,$07,$09,$0A,$0C,$0E,$10,$12,$14,$17,$19,$1C,$1F,$22,$25,$29,$2C,$30,$33,$37,$3B,$3F,$43,$47
        .byte $4C,$50,$55,$59,$5E,$63,$68,$6D,$72,$78,$7D,$82,$88,$8D,$93,$99,$9E,$A4,$AA,$B0,$B6,$BC,$C2,$C8,$CE,$D4,$DB,$E1,$E7,$ED,$F3,$FA
*=atandata
        .byte $20,$20,$21,$21,$22,$22,$23,$23,$24,$24,$24,$25,$25,$26,$26,$27,$27,$27,$28,$28,$29,$29,$29,$2A,$2A,$2B,$2B,$2B,$2C,$2C,$2C,$2D
        .byte $2D,$2E,$2E,$2E,$2F,$2F,$2F,$30,$30,$30,$30,$31,$31,$31,$32,$32,$32,$32,$33,$33,$33,$34,$34,$34,$34,$35,$35,$35,$35,$35,$36,$36
        .byte $36,$36,$36,$37,$37,$37,$37,$37,$38,$38,$38,$38,$38,$38,$39,$39,$39,$39,$39,$39,$39,$3A,$3A,$3A,$3A,$3A,$3A,$3A,$3B,$3B,$3B,$3B
        .byte $3B,$3B,$3B,$3B,$3B,$3B,$3C,$3C,$3C,$3C,$3C,$3C,$3C,$3C,$3C,$3C,$3C,$3D,$3D,$3D,$3D,$3D,$3D,$3D,$3D,$3D,$3D,$3D,$3D,$3D,$3D,$3D
        .byte $3D,$3E,$3E,$3E,$3E,$3E,$3E,$3E,$3E,$3E,$3E,$3E,$3E,$3E,$3E,$3E,$3E,$3E,$3E,$3E,$3E,$3E,$3E,$3E,$3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F
        .byte $3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F
        .byte $3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F,$3F,$40,$40,$40,$40,$40,$40,$40,$40,$40,$40,$40,$40,$40,$40,$40,$40,$40,$40,$40,$40,$40
        .byte $40,$40,$40,$40,$40,$40,$40,$40,$40,$40,$40,$40,$40,$40,$40,$40,$40,$40,$40,$40,$40,$40,$40,$40,$40,$40,$40,$40,$40,$40,$40,$40
*=loghigh
        .byte $00,$00,$1F,$32,$3F,$4A,$52,$59,$5F,$65,$69,$6E,$72,$75,$79,$7C,$7F,$82,$84,$87,$89,$8C,$8E,$90,$92,$94,$95,$97,$99,$9A,$9C,$9D
        .byte $9F,$A0,$A2,$A3,$A4,$A6,$A7,$A8,$A9,$AA,$AB,$AD,$AE,$AF,$B0,$B1,$B2,$B3,$B3,$B4,$B5,$B6,$B7,$B8,$B9,$B9,$BA,$BB,$BC,$BD,$BD,$BE
        .byte $BF,$C0,$C0,$C1,$C2,$C2,$C3,$C4,$C4,$C5,$C5,$C6,$C7,$C7,$C8,$C8,$C9,$CA,$CA,$CB,$CB,$CC,$CC,$CD,$CD,$CE,$CE,$CF,$D0,$D0,$D0,$D1
        .byte $D1,$D2,$D2,$D3,$D3,$D4,$D4,$D5,$D5,$D6,$D6,$D6,$D7,$D7,$D8,$D8,$D9,$D9,$D9,$DA,$DA,$DB,$DB,$DB,$DC,$DC,$DC,$DD,$DD,$DE,$DE,$DE
        .byte $DF,$DF,$DF,$E0,$E0,$E0,$E1,$E1,$E1,$E2,$E2,$E2,$E3,$E3,$E3,$E4,$E4,$E4,$E5,$E5,$E5,$E6,$E6,$E6,$E7,$E7,$E7,$E7,$E8,$E8,$E8,$E9
        .byte $E9,$E9,$EA,$EA,$EA,$EA,$EB,$EB,$EB,$EB,$EC,$EC,$EC,$ED,$ED,$ED,$ED,$EE,$EE,$EE,$EE,$EF,$EF,$EF,$EF,$F0,$F0,$F0,$F0,$F1,$F1,$F1
        .byte $F1,$F2,$F2,$F2,$F2,$F3,$F3,$F3,$F3,$F3,$F4,$F4,$F4,$F4,$F5,$F5,$F5,$F5,$F5,$F6,$F6,$F6,$F6,$F7,$F7,$F7,$F7,$F7,$F8,$F8,$F8,$F8
        .byte $F8,$F9,$F9,$F9,$F9,$F9,$FA,$FA,$FA,$FA,$FA,$FB,$FB,$FB,$FB,$FB,$FC,$FC,$FC,$FC,$FC,$FD,$FD,$FD,$FD,$FD,$FD,$FE,$FE,$FE,$FE,$FE
*=loglow
        .byte $00,$00,$E2,$89,$C5,$08,$6B,$83,$A7,$12,$EB,$4D,$4E,$FC,$65,$91,$8A,$53,$F5,$71,$CD,$0C,$30,$3B,$30,$11,$DF,$9B,$48,$E5,$74,$F6
        .byte $6C,$D6,$36,$8B,$D7,$1A,$54,$86,$B0,$D3,$EE,$03,$12,$1B,$1E,$1B,$13,$06,$F3,$DD,$C1,$A2,$7E,$56,$2A,$FA,$C7,$91,$57,$19,$D9,$95
        .byte $4F,$05,$B9,$6A,$18,$C4,$6E,$15,$BA,$5C,$FC,$9A,$36,$D0,$68,$FE,$92,$25,$B5,$44,$D1,$5C,$E6,$6E,$F5,$7A,$FD,$7F,$00,$7F,$FD,$7A
        .byte $F5,$6F,$E8,$60,$D6,$4B,$BF,$32,$A4,$15,$84,$F3,$60,$CD,$38,$A3,$0D,$75,$DD,$44,$AA,$0F,$73,$D6,$39,$9B,$FC,$5C,$BB,$1A,$78,$D5
        .byte $31,$8D,$E8,$42,$9B,$F4,$4C,$A4,$FB,$51,$A7,$FC,$50,$A4,$F7,$4A,$9C,$EE,$3E,$8F,$DF,$2E,$7D,$CB,$19,$66,$B3,$FF,$4B,$96,$E1,$2B
        .byte $75,$BE,$07,$50,$98,$DF,$26,$6D,$B3,$F9,$3F,$84,$C8,$0D,$51,$94,$D7,$1A,$5C,$9E,$E0,$21,$62,$A2,$E3,$22,$62,$A1,$E0,$1E,$5C,$9A
        .byte $D8,$15,$52,$8E,$CB,$07,$42,$7D,$B8,$F3,$2E,$68,$A2,$DB,$15,$4E,$86,$BF,$F7,$2F,$67,$9E,$D5,$0C,$43,$79,$AF,$E5,$1B,$50,$85,$BA
        .byte $EF,$23,$58,$8C,$BF,$F3,$26,$59,$8C,$BF,$F1,$24,$56,$87,$B9,$EA,$1C,$4C,$7D,$AE,$DE,$0E,$3E,$6E,$9E,$CD,$FC,$2B,$5A,$89,$B7,$E5
*=squarelow
        .byte $00,$01,$04,$09,$10,$19,$24,$31,$40,$51,$64,$79,$90,$A9,$C4,$E1,$00,$21,$44,$69,$90,$B9,$E4,$11,$40,$71,$A4,$D9,$10,$49,$84,$C1
        .byte $00,$41,$84,$C9,$10,$59,$A4,$F1,$40,$91,$E4,$39,$90,$E9,$44,$A1,$00,$61,$C4,$29,$90,$F9,$64,$D1,$40,$B1,$24,$99,$10,$89,$04,$81
        .byte $00,$81,$04,$89,$10,$99,$24,$B1,$40,$D1,$64,$F9,$90,$29,$C4,$61,$00,$A1,$44,$E9,$90,$39,$E4,$91,$40,$F1,$A4,$59,$10,$C9,$84,$41
        .byte $00,$C1,$84,$49,$10,$D9,$A4,$71,$40,$11,$E4,$B9,$90,$69,$44,$21,$00,$E1,$C4,$A9,$90,$79,$64,$51,$40,$31,$24,$19,$10,$09,$04,$01
        .byte $00,$01,$04,$09,$10,$19,$24,$31,$40,$51,$64,$79,$90,$A9,$C4,$E1,$00,$21,$44,$69,$90,$B9,$E4,$11,$40,$71,$A4,$D9,$10,$49,$84,$C1
        .byte $00,$41,$84,$C9,$10,$59,$A4,$F1,$40,$91,$E4,$39,$90,$E9,$44,$A1,$00,$61,$C4,$29,$90,$F9,$64,$D1,$40,$B1,$24,$99,$10,$89,$04,$81
        .byte $00,$81,$04,$89,$10,$99,$24,$B1,$40,$D1,$64,$F9,$90,$29,$C4,$61,$00,$A1,$44,$E9,$90,$39,$E4,$91,$40,$F1,$A4,$59,$10,$C9,$84,$41
        .byte $00,$C1,$84,$49,$10,$D9,$A4,$71,$40,$11,$E4,$B9,$90,$69,$44,$21,$00,$E1,$C4,$A9,$90,$79,$64,$51,$40,$31,$24,$19,$10,$09,$04,$01
*=squarehigh
        .byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$01,$01,$01,$01,$01,$01,$01,$02,$02,$02,$02,$02,$03,$03,$03,$03
        .byte $04,$04,$04,$04,$05,$05,$05,$05,$06,$06,$06,$07,$07,$07,$08,$08,$09,$09,$09,$0A,$0A,$0A,$0B,$0B,$0C,$0C,$0D,$0D,$0E,$0E,$0F,$0F
        .byte $10,$10,$11,$11,$12,$12,$13,$13,$14,$14,$15,$15,$16,$17,$17,$18,$19,$19,$1A,$1A,$1B,$1C,$1C,$1D,$1E,$1E,$1F,$20,$21,$21,$22,$23
        .byte $24,$24,$25,$26,$27,$27,$28,$29,$2A,$2B,$2B,$2C,$2D,$2E,$2F,$30,$31,$31,$32,$33,$34,$35,$36,$37,$38,$39,$3A,$3B,$3C,$3D,$3E,$3F
        .byte $40,$41,$42,$43,$44,$45,$46,$47,$48,$49,$4A,$4B,$4C,$4D,$4E,$4F,$51,$52,$53,$54,$55,$56,$57,$59,$5A,$5B,$5C,$5D,$5F,$60,$61,$62
        .byte $64,$65,$66,$67,$69,$6A,$6B,$6C,$6E,$6F,$70,$72,$73,$74,$76,$77,$79,$7A,$7B,$7D,$7E,$7F,$81,$82,$84,$85,$87,$88,$8A,$8B,$8D,$8E
        .byte $90,$91,$93,$94,$96,$97,$99,$9A,$9C,$9D,$9F,$A0,$A2,$A4,$A5,$A7,$A9,$AA,$AC,$AD,$AF,$B1,$B2,$B4,$B6,$B7,$B9,$BB,$BD,$BE,$C0,$C2
        .byte $C4,$C5,$C7,$C9,$CB,$CC,$CE,$D0,$D2,$D4,$D5,$D7,$D9,$DB,$DD,$DF,$E1,$E2,$E4,$E6,$E8,$EA,$EC,$EE,$F0,$F2,$F4,$F6,$F8,$FA,$FC,$FE

;-----------------------------------------------------------------------------------------------
