UNIT Joystick;

{***************************************************************************}
{																			}
{		Author:				Kevin A. Lee									}
{																			}
{		Last Amended:		22nd January, 1993								}
{																			}
{		Description:		Turbo Pascal V6 Joystick routines.          	}
{																			}
{							These routines are intended for use with the	}
{							pasKAL graphics library. A maximum of two		}
{							of two joysticks are supported and can be		}
{							calibrated with the routines provided.			}
{							All movements of the joystick are converted 	}
{							into an digital form more suitable for game		}
{							programming.                                    }
{																			}
{***************************************************************************}


INTERFACE

uses
	Crt;

type
	Direction = (none, up, down, left,
				right, upleft, upright,		{ the different directions		}
				downright, downleft);		{ that the joystick can travel	}

var
	GameAdapterExists: boolean;				{ does this computer have a		}
    										{ game adapter installed?			}
	JoyPosition: array [1..2] of Direction;	{ current pos of each josytick 	}
    JoyButton1:  array [1..2] of boolean;	{ status of both button ones	}
    JoyButton2:  array [1..2] of boolean;	{ status of both button twos	}


function CalibrateJoystick(number: integer): boolean;
{                                            								}
{	Parameters:			number - number of joystick to calibrate - 1 or 2.	}
{                                                                           }
{	Returns:			false, if the joystick does not exist else true.	}
{																			}
{	Description:		Calibrates the specified joystick.					}
{						Make sure both the actual joystick and its trims	}
{						are centered before calling.						}


procedure CheckJoysticks;
{																			}
{	Description:		Checks the approximate position of both of the  	}
{						joysticks and their buttons and returns the results	}
{						in JoyPosition and JoyButton.                       }




IMPLEMENTATION



const
	GamePort = $201;

var
	JoyRange,                               { distance joystick must travel }
	Joy1Range, Joy2Range: integer;			{ before being recognised		}
	Joy1xOffset, Joy1yOffset,				{ offset of current position	}
	Joy2xOffset, Joy2yOffset: integer;		{ from the center				}
	Joy1x, Joy2x, Joy1y, Joy2y: integer;	{ current pos. of joysticks		}
    Joy1xcenter, Joy1ycenter,
	Joy2xcenter, Joy2ycenter: integer;		{ central pos. of joysticks 	}



{ routine to get current position of joystick and their button status }
function GetJoystick: integer;
label _RangeLoop;
var Button: integer;
begin
	asm
               mov    dx, GamePort
               cli                   		{ disable interrupts		}
               out    dx, al          		{ start timer				}
               xor    ax, ax
               mov    Joy1x, ax  			{ initialize to zero		}
               mov    Joy1y, ax
               mov    Joy2x, ax
               mov    Joy2y, ax
               mov    cx, JoyRange   		{# times to it. _RangeLoop 	}
	_RangeLoop:
               in     al,dx
               shr    al,1
               adc    Joy1x, 0
               shr    al,1
               adc    Joy1y, 0
               shr    al,1
               adc    Joy2x, 0
               shr    al,1
               adc    Joy2y, 0
               loop   _RangeLoop
               not    al              		{ button bits are inverted	}
               and    ax,0fh          		{ return the button status	}
			   								{ in ax                     }
               mov	  Button, ax
               sti                    		{ enable interrupts			}
    end;

    GetJoystick := Button;
end; {GetJoystick}



function CalibrateJoystick(number: integer): boolean;

	function MaxTwo(val1, val2: integer): integer;
	begin
		if (val1 > val2) then MaxTwo := val1 else MaxTwo := val2;
	end; {MaxTwo}

var flag, noJoystick: boolean;
var temp: integer;
begin
	JoyRange := 100;
    flag := false;
    noJoystick := false;

    if (number = 1) then
    begin
    	while (not flag) do
    	begin
    		temp := GetJoystick;
        	if (MaxTwo(Joy1x, Joy1y) < JoyRange) then
			begin
				flag := true;
        	end
        	else
        	begin
        		if (JoyRange < 10000) then
				begin
					JoyRange := JoyRange + 100;
            	end
            	else
            	begin
            		{ no joystick }
            		flag := true;
                	noJoystick := true;
                	CalibrateJoyStick := false;
            	end;
        	end;
    	end;

    	JoyRange := JoyRange + 100;
    	flag := false;
    	while (not flag) do
    	begin
    		temp := GetJoystick;
        	Joy1xcenter := Joy1x;
        	Joy1ycenter := Joy1y;
        	temp := GetJoystick;
        	if ((Joy1xcenter = Joy1x) and (Joy1ycenter = Joy1y)) then flag := true;
        end;

    	JoyRange := 2 * MaxTwo(Joy1xcenter, Joy1ycenter);
        Joy1range := JoyRange div 4;
        Joy1xOffset := Joy1x - Joy1xcenter;
        Joy1yOffset := Joy1y - Joy1ycenter;
    end
    else
    begin
    	while (not flag) do
    	begin
    		temp := GetJoystick;
        	if (MaxTwo(Joy2x, Joy2y) < JoyRange) then
			begin
				flag := true;
        	end
        	else
        	begin
        		if (JoyRange < 10000) then
				begin
					JoyRange := JoyRange + 100;
            	end
            	else
            	begin
            		{ no joystick }
            		flag := true;
                	noJoystick := true;
                	CalibrateJoyStick := false;
            	end;
        	end;
    	end;

    	JoyRange := JoyRange + 100;
    	flag := false;
    	while (not flag) do
    	begin
    		temp := GetJoystick;
        	Joy2xcenter := Joy2x;
        	Joy2ycenter := Joy2y;
        	temp := GetJoystick;
        	if ((Joy2xcenter = Joy2x) and (Joy2ycenter = Joy2y)) then flag := true;
        end;

    	JoyRange := 2 * MaxTwo(Joy2xcenter, Joy2ycenter);
        Joy2Range := JoyRange div 3;
        Joy2xOffset := Joy2x - Joy2xcenter;
        Joy2yOffset := Joy2y - Joy2ycenter;
    end;

    CalibrateJoystick := (not noJoystick);
end; {CalibrateJoystick}


procedure CheckJoysticks;
var	Button: integer;
begin
	Button := GetJoystick;
    Joy1xOffset := Joy1x - Joy1xcenter;
    Joy1yOffset := Joy1y - Joy1ycenter;
    Joy2xOffset := Joy2x - Joy2xcenter;
    Joy2yOffset := Joy2y - Joy2ycenter;

    if ((Joy1xOffset < Joy1Range) and (Joy1xOffset > -Joy1Range)) then
    begin
    	if (Joy1yOffset < -Joy1Range) then
        begin
        	JoyPosition[1] := up;
        end
        else
        begin
			if (Joy1yOffset > Joy1Range) then
        	begin
        		JoyPosition[1] := down;
        	end
        	else
			begin
				JoyPosition[1] := none;
        	end;
        end;
    end
    else
	begin
		if (Joy1xOffset > Joy1Range) then
    	begin
			if (Joy1yOffset < -Joy1Range) then
        	begin
        		JoyPosition[1] := upright;
        	end
        	else
			begin
				if (Joy1yOffset > Joy1Range) then
        		begin
        			JoyPosition[1] := downright;
        		end
        		else
				begin
					JoyPosition[1] := right;
        		end;
            end;
    	end
    	else
		begin
			if (Joy1xOffset < -Joy1Range) then
    		begin
				if (Joy1yOffset < -Joy1Range) then
        		begin
        			JoyPosition[1] := upleft;
        		end
        		else
				begin
					if (Joy1yOffset > Joy1Range) then
        			begin
        				JoyPosition[1] := downleft;
        			end
        			else
					begin
						JoyPosition[1] := left;
        			end;
                end;
    		end;
    	end;
	end;

    if ((Joy2xOffset < Joy2Range) and (Joy2xOffset > -Joy2Range)) then
    begin
    	if (Joy2yOffset < -Joy2Range) then
        begin
        	JoyPosition[2] := up;
        end
        else
        begin
			if (Joy2yOffset > Joy2Range) then
        	begin
        		JoyPosition[2] := down;
        	end
        	else
			begin
				JoyPosition[2] := none;
        	end;
        end;
    end
    else
	begin
		if (Joy2xOffset > Joy2Range) then
    	begin
			if (Joy2yOffset < -Joy2Range) then
        	begin
        		JoyPosition[2] := upright;
        	end
        	else
			begin
				if (Joy2yOffset > Joy2Range) then
        		begin
        			JoyPosition[2] := downright;
        		end
        		else
				begin
					JoyPosition[2] := right;
        		end;
            end;
    	end
    	else
		begin
			if (Joy2xOffset < -Joy2Range) then
    		begin
				if (Joy2yOffset < -Joy2Range) then
        		begin
        			JoyPosition[2] := upleft;
        		end
        		else
				begin
					if (Joy2yOffset > Joy2Range) then
        			begin
        				JoyPosition[2] := downleft;
        			end
        			else
					begin
						JoyPosition[2] := left;
        			end;
                end;
    		end;
    	end;
	end;


    JoyButton1[1] := ((Button and 1) = 1);
    JoyButton2[1] := (((Button shr 1) and 1) = 1);
    JoyButton1[2] := (((Button shr 2) and 1) = 1);
    JoyButton2[2] := (((Button shr 3) and 1) = 1);
end; {CheckJoysticks}



begin
	{ does this work on game ports? - i sure as hell don't know }
	GameAdapterExists := (((memw[0:$410] shr 12) and 1) = 1);
end.