Contributor: SCOTT TUNSTALL

{
SPACE LORDS 7 - VGA PC VERSION.
(C) 1995 Scott Tunstall & K. Sillett (BBC Maestro)

3 PLAYER ACTION !!!

Apologies for the swearing in some of my posts Gayle. To make up
for it, I've given ya a QUALITY video game. Seriously!
It certainly looks smart... don't ask me where I got the graphics
from tho' - some folk may complain! ;)

BEFORE YOU RUN THIS PLEASE USE THE XX3402 DECODER ON PART 2 OF
THE SPACE LORDS POST TO CREATE THE FILE IMAGES.ZIP. THEN UNZIP
THE IMAGES FILE INTO WHERE YOUR SPACE LORDS GAME EXECUTABLE FILE
(LORDS.EXE) WILL BE.

THEN, RUN THE EXE AND HAVE FUN! :)

New game requirements:
----------------------
500K of base memory
MCGA/VGA graphics adaptor supporting 320 x 200 x 256 mode
386 SX 25 processor (at worst) - will run VERY SLOWLY ON THIS MACHINE
(Ok on a 486 DX-2)

(Of course, if you are Dave "Stallion Man" Norrie you can use a
8Mb RAM Pentium f***ing 90 - lucky c***!! I'll put one over him
and buy an IBMRISC 400Mhz baby! (No games for it tho' - I'll change
that !)


Most importantly a 101 key keyboard is essential.


PLAYER #     UP      ROTATE LEFT    ROTATE RIGHT     FIRE
-----------------------------------------------------------------
1            '1'     'A'            'X'              'LEFT SHIFT'
2            'O'     ';'            '@'              '>'
3            'Home'  'Keypad 9'     'Keypad -'       'Keypad 3'
4            JOYSTICK 1      (Not implemented)
5            JOYSTICK 2      (Not implemented)

6..100 require to be LapLinked (Aye right then)

}




{$DEFINE FULLDISPLAY}   { <-- $UNDEF if using a slow 386 }
{$DEFINE BUMPING}       { <-- Player to player bumping }
{$DEFINE BONUSES}       { <-- Want Any bonuses on screen }
{$DEFINE MESSAGES}      { <-- This may be silly of you to $UNDEF. }


{$a+,b-,s-,e+,n+,r-,v-,g+}


Program SPACE_LORDS_7;   { 7 editions already - GULP! }

Uses Dos,NEWGRAPH, NwKBDInt, Crt;

     {NEWGRAPH is in JUNE 1996 EDITION OF THE SWAG }
     {AS IS NEWKBDINT - KEYBOARD HANDLER }



Const TopBoundary = -8;          { Top of window }
      BottomBoundary = 204;
      LeftBoundary = -4;
      RightBoundary = 323;


      MaxPlayers = 3;           { Max no of players on screen at once }

{$IFDEF BONUSES}
      MaxBonuses = 6;           { Max no of bonuses on screen at once }
{$ENDIF}

      MaxAliens = 10;           { Getting busy on the screen ! }
      MaxStars  = 20;           { Number of parallax stars }


      MaxExplodeWidth = 200;    { And how far the explosion circles go }
      ShipTurnAngle = 4;        { Degrees that ships turn in }
      PointsForBumping = 500;   { Guess what these are ? }
      PointsForShooting = 100;
      DeductionForShooting = 10;


      {
      BIT FLAGS - LEAVE ALONE
      }

      Dead = 0;                    { Playerstatus defines }
      ShootAble = 1;               { This MUST stay at 1 - V. Important }
      Warping = 2;                 { This MUST stay at 2 ! }
      Exploding = 4;               { This MUST stay at 4 ! }
      Spinning = 8;                { This MUST stay at 8 ! }
      Frozen = 16;

      {
      Player Speed stuff
      }

      MaxPlayerSpeed = 4;          { This is the MAXIMUM number of
                                   pixels that a player ship jumps
                                   in 1 pass. Pretty fast man }
      SlowestPlayerSpeed = 1;      { The least number of pixel
                                   jumps }









      {
      Laser stuff - Alter MaxLasers if you like, leave the rest
      }

      MaxLasers = (MaxPlayers * 10)+10;  { How many lasers allocated }
      MaxPlayerLasers = 10;              { How many each player has }
      MaxLaserPower = 5;

      NumLaserTypes = 3;           { The current # of laser types }
      LaserFree = 0;
      NormalLaser = 1;             { Lasers stop at edge of screen }
      LaserWraps = 2;              { Lasers can go off one side &
                                   reappear on the other }
      LaserRebound = 3;            { Makes lasers bounce off wall }

      PlayerLaserSize = 4;
      AlienLaserSize = 4;








      {
      Bonus stuff - don't change the values of the constants
      otherwise some strange effects will occur, OK? If you want
      to add some more stuff you'll have to update BonusString
      too..
      }

{$IFDEF BONUSES}

      NumberOfBonuses = 13;


{     BONUS NAME                POINTS FOR COLLECTING IT
      ----------                ------------------------
}

      SlowDownBonus = 1;        SlowDownBonusPointsValue = 100;
      EnergyBonus = 2;          EnergyBonusPointsValue = 200;
      FreezeBonus = 3;          FreezeBonusPointsValue = 300;
      ReverseBonus = 4;         ReverseBonusPointsValue = 400;
      DisableBonus = 5;         DisableBonusPointsValue = 500;
      InvulnerabilityBonus = 6; InvulnerabilityBonusPointsValue = 600;
      AssFiringBonus = 7;      AssFiringBonusPointsValue = 700;
      NormalBonus = 8;          NormalBonusPointsValue = 50;
      ToodysBonus = 9;          ToodysBonusPointsValue = 2000;
      LaserBonus = 10;          LaserBonusPointsValue = 200;
      WarpBonus =  11;          WarpBonusPointsValue = 1000;
      BounceLaserBonus = 12;    BounceLaserBonusPointsValue = 200;

      UnknownBonus = 13;


{$ENDIF}
      MaxInvulnerableTime = 200;

{$IFDEF BONUSES}
      MaxFrozenTime = 100;
      MaxFireHaltTime = 100;
      MaxKeyReverseTime = 200;
      MaxSlowedDownTime = 100;
      MaxBanzaiTime = 100;
      MaxDisableTime = 100;

{$ENDIF}

      EnergyIncrement = 5;
      SlowDownIncrement = 10;
      NormalMessageTime = 80;

      PacDelayConst = 4;


{
And now to define ALL aspects of a player's ship
}

Type PlayerStruct = Record

     PlayerStatus: byte;           { 0 = Dead, 1 = ShootAble, 2= Exploding,
                                   4 = Spinning, 8 = Frozen }
     FrozenTime: word;

     ExplodeWidth:byte;

     PlayerColour: byte;

     PlayerAngle: integer;
     SpinAngle: integer;

     SpinSpeed: byte;
     SpinCount: byte;


     PlayerX: integer;

     PlayerY: integer;

     PlayerWraps : boolean;

     PlayerMessage: String[38];
     MessageTime: byte;

     BanzaiTime: word;

     {
     Speed stuff
     }

     PlayerSpeed: byte;            { Exceed 3 and ship movement is
                                      quite jerky. }
     NormalPlayerSpeed: byte;
     SlowedDownTime: word;
     PlayerWait: byte;
     WaitCount: byte;
     MaxWaitCount: byte;

     Thrusting: boolean;


     PlayerEnergy: integer;
     MaxPlayerEnergy: integer;
     RechargeTime: byte;
     RechargeLatch: byte;
     RechargeDeduction: byte;

     KeyReverseTime: byte;

     AutoFire: boolean;

     DisableTime: byte;

     AssFiring : boolean;

     FireKeyReleased: boolean;
     FireDelay:byte;
     FireLatch:byte;


     LaserDeduction: byte;


     CurrentLaserType: byte;
     CurrentLaserPower: byte;
     CurrentLaserSpeed: byte;
     CurrentMaxLaserTravel: byte;

     LaserHurts: boolean;
     EnemyLaserHurts: boolean;
     Invulnerable: boolean;
     InvulnerableTime: word;

     PlayerScore: LongInt;

End;


Type Laser = Record
     LaserType: byte;
     FiredBy: byte;
     LaserAngle: integer;
     LaserX: integer;
     LaserY: integer;
     LaserColour: byte;
     LaserSize: byte;
     LaserSpeed: byte;

     LaserTravel: byte;
     MaxLaserTravel: byte;
     LaserPower: byte;
End;


{$IFDEF BONUSES}

{
Yeah! Some Pick - Ups for the players!
}


Type Bonus = Record
     BonusType: byte;
     BonusX: integer;                { Position on screen }
     BonusY: integer;
     BonusXIncrement: integer;
     BonusYIncrement: integer;
     End;



Type BonusArray = Array[1..MaxBonuses] of Bonus;
{$ENDIF}


Type PlayerArray = Array[1..MaxPlayers] of PlayerStruct;
Type LaserArray = Array[1..MaxLasers] of Laser;

Var

    PlayerRec: PlayerArray;
    LaserRec: LaserArray;
    TempLaser: Laser;

{$IFDEF BONUSES}
    BonusRec: BonusArray;
{$ENDIF}


    OldKbdInt: procedure;

    PlanetSeg,PlanetOfs: word;
    titleBitmapSeg,titleBitmapOfs: word;
    EmporerSeg,EmporerOfs: word;
    ScratchSeg,ScratchOfs: word;

    FontSegment, FontOffset: word;
    FontHeight: byte;

    PacPointer: Array[0..7] of Pointer;
    AlienPointer: Pointer;
    AlienShapeSize: word;

    DestroyerPalette: PaletteType;
    titleBitmapPalette: PaletteType;
    EmporerPalette: PaletteType;


    TempKey: char;

    ColourTable: array[1..MaxPlayers] of byte;
    QCos, QSin : array[0..359] of real;

    PlayersOn: byte;
    PlayersAlive: byte;                         { How many players are
                                                  left on the screen -
                                                  initially, PlayersAlive
                                                  equals PlayersOn but
                                                  as people are killed it
                                                  decrements }
    LasersFired: byte;
    LastLaserIndex: byte;
    AlienCount: byte;



{$IFDEF BONUSES}
    BonusesOnScreen: byte;
    BonusString: string[NumberOfBonuses];

{$ENDIF}

    Message: String[40];


Procedure Warp(PlayerNo:byte); Forward;


Procedure LoadGraphics;
Var Count: byte;
Begin
     TextMode(CO80);
     TextBackGround(Black);
     ClrScr;

     TextBackGround(Red);
     For Count:=0 to 79 do Write(Chr(32));

     TextColor(White);
     Gotoxy(1,1);
     Writeln('SPACE LORDS 7.1.2.3.5.2.9.«  (C) 1994,5 Scott Tunstall.  Lauder College Version');
     Writeln;
     Writeln;
     TextBackGround(Black);
     TextColor(LightGray);
     Writeln('Beginning LORDS_INIT Refresh daemon.. OK.');
     Writeln;
     For Count:=0 to 79 do write('=');
     Writeln('THIS VERSION IS PUBLIC DOMAIN AND MAY BE SWAPPED AND COPIED FREELY');
     Writeln('YOU MAY NOT DISASSEMBLE, REPLICATE OR ALTER THE PROGRAM CODE IN ANY');
     Writeln('WAY UNLESS YOU CONTACT THE AUTHOR.');
     For Count:=0 to 79 do write('=');

     Writeln('Please wait.. Loading in PCX files from hard disk..');
     Writeln;

     Bitmap(PlanetSeg, PlanetOfs);
     Bitmap(titleBitmapSeg, titleBitmapOfs);
     Bitmap(EmporerSeg, EmporerOfs);
     Bitmap(ScratchSeg, ScratchOfs);


     Write('DESTROYR.PCX .. ');

     SetSourceBitmapAddr(PlanetSeg, PlanetOfs);
     LoadPCX('DESTROYR.PCX',DestroyerPalette);

     Writeln('loaded.'); Write('BACK.PCX .. ');

     SetSourceBitmapAddr(titleBitmapSeg, titleBitmapOfs);
     LoadPCX('BACK.PCX',titleBitmapPalette);

     Writeln('loaded.'); Write('EMPORER.PCX .. ');

     SetSourceBitmapAddr(EmporerSeg, EmporerOfs);
     LoadPCX('EMPORER.PCX',EmporerPalette);

     Writeln('loaded.');


End;

{
Sorry I had to get rid of the Pascal but I was pissed off
with it's slothfulness !
}


Procedure BitMapCopy(TheSegment, TheOffset:word);
Begin
     Asm
     MOV AX,DS
     MOV ES,ScratchSeg
     MOV DI,ScratchOfs
     MOV SI,TheOffset
     MOV DS,TheSegment

     MOV CX,16000
     REPZ
     DB $66
     MOVSW
     MOV DS,AX
     End;
     SetSourceBitmapAddr(ScratchSeg,ScratchOfs);
     SetDestinationBitmapAddr($a000,0);
End;

{========================================================

This routine could possibly be slowing the system down
quite a lot as it calls the video interrupt which as most
codies know is as slow as a snail on mogadon. Hmm.

I will update this in 1998 when I've got me postgraduate
but right now you'll have to make do with this s**t OK?
}


Procedure SelectFont(FontNo: byte);
Var TempWidth: byte;
Begin
     UseFont(FontNo);
     GetCurrentFontAddr(FontSegment,FontOffset);
     GetCurrentFontSize(TempWidth,FontHeight);
End;


{====================

Display coloured text

}


Procedure TextXY(x,y:integer;txt:string);
Begin
     SetColour(254);
     OutTextXY(x+1,y+1,txt);
     SetColour(255);
     OutTextXY(x,y,txt);
End;


{===============================================================

This Bresenham circle routine isn't mine. I nicked it from the
SWAG (the rest of the stuff is 100% mine though) and to be quite
honest I couldn't be bothered converting it to assembler, so if
any gurus out there (like me!) want to then they can convert.

              *** You'd be sad tho' !! ***
}

Procedure Circle(X, Y : integer; Radius:byte);
Var
   Xs, Ys    : Integer;
   Da, Db, S : Integer;
   TX, TR    : word;
begin
     if (Radius = 0) then
          Exit;

     if (Radius = 1) then
     begin
          PutPixel(X, Y, GetColour);
          Exit;
     end;

     Xs := 0;
     Ys := Radius;

     Repeat
           TX:=Sqr(Xs+1);
           TR:=Sqr(Radius);
           Da := TX + Sqr(Ys) - TR;
           Db := TX + Sqr(Ys - 1) - TR;
           S  := Da + Db;

           Inc(Xs);
           if (S > 0) then
                Dec(Ys);

           PutPixel(X+Xs-1, Y-Ys+1, GetColour);
           PutPixel(X-Xs+1, Y-Ys+1, GetColour);
           PutPixel(X+Ys-1, Y-Xs+1, GetColour);
           PutPixel(X-Ys+1, Y-Xs+1, GetColour);
           PutPixel(X+Xs-1, Y+Ys-1, GetColour);
           PutPixel(X-Xs+1, Y+Ys-1, GetColour);
           PutPixel(X+Ys-1, Y+Xs-1, GetColour);
           PutPixel(X-Ys+1, Y+Xs-1, GetColour);
     Until (Xs >= Ys);
end;

Procedure InitPlayers;
Var count: byte;
Begin
     For count:= 1 to MaxPlayers do
         With PlayerRec[count] do
              Begin
              Warp(Count);

              PlayerMessage:='Player '+chr(48+Count)+' ready !';
              MessageTime:=NormalMessageTime;

              ExplodeWidth:=0;
              PlayerColour:=ColourTable[Count];

              PlayerWraps:=True;

              PlayerSpeed:=4;
              NormalPlayerSpeed:=PlayerSpeed;

              SlowedDownTime:=0;
              PlayerWait:=1;

              WaitCount:=15;
              MaxWaitCount:=WaitCount;

              Thrusting:=False;

              InvulnerableTime:=MaxInvulnerableTime; { So if you warp into Paccy you
                                                       can still get away }
              BanzaiTime:=0;

              PlayerEnergy:=20;
              MaxPlayerEnergy:=PlayerEnergy;
              RechargeTime:=40;
              RechargeLatch:=RechargeTime;
              RechargeDeduction:=10;

              KeyReverseTime:=0;

              AssFiring:=False;
              DisableTime:=0;

              AutoFire:=True;
              FireKeyReleased:=true;
              FireDelay:=3;
              FireLatch:=FireDelay;

              CurrentLaserType:=NormalLaser;
              CurrentLaserPower:=1;
              CurrentLaserSpeed:=8;
              CurrentMaxLaserTravel:=80;

              LaserDeduction:=1;

              LaserHurts:=False;
              EnemyLaserHurts:=True;

              PlayerScore:=0;
         End;
End;


{
Flush laser array
}

Procedure InitLasers;
Var Count: byte;
Begin
     LasersFired:=0;
     LastLaserIndex:=1;
     For Count:=1 to MaxLasers do
     With LaserRec[Count] do
         LaserType:=LaserFree;
End;

{$IFDEF BONUSES}
Procedure InitBonuses;
Var Count: byte;
Begin
     BonusesOnScreen:=0;
     BonusString:='SEFRDIANTLWB?';      { Not explaining what this is for }

     For Count:= 1 to MaxBonuses do
         With BonusRec[Count] do
         Begin
              BonusType:=0;
         End;
End;
{$ENDIF}

Procedure SetUpPlayers;
var Count: word;
    keyhit: char;
    PromptLatch: byte;
    PromptTime: byte;
    TextRefreshCount: byte;

Begin
     For Count:=0 to 359 do
         Begin
         QCos[Count]:=Cos(Count * (PI/180));
         QSin[Count]:=Sin(Count * (PI/180));
     end;

     { Assign player colours }

     For Count:=1 to MaxPlayers do
         ColourTable[Count]:=256-Count;

     Randomize;

     PlayersOn:=MaxPlayers;
     PlayersAlive:=PlayersOn;

     InitPlayers;
     InitLasers;
{$IFDEF BONUSES}
     InitBonuses;
{$ENDIF}


     {
     Now draw the title screen
     }

     PromptLatch:=50;
     PromptTime:=PromptLatch;
     TextRefreshCount:=0;

     SetPalette(254, 63,0,0);
     SetPalette(255, 63,63,0);

     Repeat
           BitMapCopy(titleBitmapSeg,titleBitmapOfs);

           SelectFont(6);

           TextXY(92,8,'SPACE LORDS 7«');

           SelectFont(1);
           TextXY(32,70, 'PROGRAMMING BY : Scott Tunstall');

           if (TextRefreshCount < 4) Then
              Begin
              TextXY(32,96,  'VECTOR GFX  BY  : Scott Tunstall');
              TextXY(32,112, 'PAC MAN     BY  : Namco (tm)');
              TextXY(32,128, 'DIRTY WOMEN AT  : MarketGait');
              end
           else
              Begin
              SelectFont(Font8x16);
              TextXY(48,96,  'SO RONNY NOW DO YOU BELIEVE');
              TextXY(48,114, 'THAT I WROTE THIS PROGRAM ?');
              SelectFont(Int43Font);
              End;


           Delay(1);
           Dec(PromptTime);
           If PromptTime=0 Then
              Begin
              PromptTime:=50;
              Inc(TextRefreshCount);
              Asm
              AND BYTE PTR TextRefreshCount, $7
              End;
           End;

           If (PromptTime > 25) Then
              Begin
              TextXY(32,162,'PRESS SPACE TO BEGIN THE GAME !');
           End;

           SelectFont(Font8x16);
           TextXY(32,180,'Program  (C) 1995 Scott Tunstall.');


           CopySourceBitmap ;

           if keypressed then
              keyhit:=readkey;

     Until keyhit = ' ';

End;

Procedure DrawPlayerStuff;
var PlayerCount: byte;
    OriginX: integer;
    OriginY: integer;
    Angle: integer;
    LineCount: byte;
    CircCount: byte;
    TempString: string[6];

Begin
     UseFont(1);
     For PlayerCount:=1 to PlayersOn do
         With PlayerRec[PlayerCount] do
              Begin

              Str(PlayerScore,TempString);
              SetColour(PlayerColour);
              OutTextXY(0,192- PlayerCount SHL 3,TempString);

              If MessageTime <>0 Then
                 Begin
                 Dec(MessageTime);

{$IFDEF FULLDISPLAY}
                 TextXY(56,192-PlayerCount SHL 3,PlayerMessage);
                 SetColour(PlayerColour);
{$ELSE}
                 OutTextXY(56,192-PlayerCount SHL 3,PlayerMessage);
{$ENDIF}

              End;

              {
              Time to draw the ship. I am quite pleased that this
              routine is fairly fast.
              }



              If (PlayerStatus And ShootAble)=ShootAble  Then
                 Begin
                 If (InvulnerableTime >10) Or
                    (InvulnerableTime MOD 2 = 1) Then
                    Circle(PlayerX,PlayerY,12);

                 If (BanzaiTime = 0) Or ((BanzaiTime MOD 8 )>3 ) Then
                    Begin
                    Angle:=PlayerAngle;

                    {
                    Nose of ship is 8 pixels away from
                    the start area at degree 
                    }

                    OriginX:=PlayerX+ Round(QCos[Angle] * 8);
                    OriginY:=PlayerY+ Round(QSin[Angle] * 8);

                    MoveTo(OriginX,OriginY);

                    Asm
                    MOV AX,Angle
                    ADD AX,135
                    CMP AX,360
                    JB @ThisAngleIsOK1
                    SUB AX,360
   @ThisAngleIsOK1:
                    MOV Angle,AX
                    End;

                    LineTo(PlayerX+ Round(QCos[Angle] * 8),
                    PlayerY+ Round(QSin[Angle] * 8));
                    ;

                    Asm
                    MOV AX,Angle
                    ADD AX,45
                    CMP AX,360
                    JB @ThisAngleIsOK2
                    SUB AX,360
   @ThisAngleIsOK2:
                    MOV Angle,AX
                    End;

                    LineTo(PlayerX+Round(QCos[Angle] * 2),
                    PlayerY+Round(QSin[Angle] * 2));

                    Asm
                    MOV AX,Angle
                    ADD AX,45
                    CMP AX,360
                    JB @ThisAngleIsOK3
                    SUB AX,360
   @ThisAngleIsOK3:
                    MOV Angle,AX
                    End;

                    LineTo(PlayerX+Round(QCos[Angle] * 8),
                    PlayerY+Round(QSin[Angle] * 8));

                    LineTo(OriginX,OriginY);




   {$IFDEF FULLDISPLAY}

                    If Thrusting And (Random(2)=1) Then
                       Begin
                       SetColour(Random(255));


                       Angle:=PlayerAngle;

                       Asm
                       MOV AX,Angle  { I've tried the other way ! }
                       ADD AX,150
                       CMP AX,360
                       JB @ThisAngleIsOK4
                       SUB AX,360
   @ThisAngleIsOK4:
                       MOV Angle,AX
                       End;


                       MoveTo(PlayerX+Round(QCos[Angle]*5),
                       PlayerY+Round(QSin[Angle]*5));

                       Asm
                       MOV AX,Angle
                       ADD AX,30
                       CMP AX,360
                       JB @ThisAngleIsOK5
                       SUB AX,360
   @ThisAngleIsOK5:
                       MOV Angle,AX
                       End;


                       LineTo(PlayerX+Round(QCos[Angle]*8),
                       PlayerY+Round(QSin[Angle]*8));

                       {Inc(Angle,30);

                       If Angle > 360 Then
                          Dec(Angle,360);}

                       Asm
                       MOV AX,Angle
                       ADD AX,30
                       CMP AX,360
                       JB @ThisAngleIsOK6
                       SUB AX,360
   @ThisAngleIsOK6:
                       MOV Angle,AX

                       End;

                       LineTo(PlayerX+Round(QCos[Angle]*5),PlayerY+Round(QSin[Angle]*5));

                    End;

   {$ENDIF}
                    SetColour(PlayerColour);

                    OriginX:=PlayerX-12;
                    OriginY:=PlayerY+12;

                    Line(OriginX,OriginY,OriginX + PlayerEnergy,OriginY);
                    End;
                 End
              Else
                  If (PlayerStatus = Exploding) Or (PlayerStatus = Warping) Then
                     Begin
                     For circcount:=0 to 40 do
                         PutPixel(PlayerX+Round(QCos[circcount SHL 3]*ExplodeWidth),
                         PlayerY+Round(QSin[circcount SHL 3]*ExplodeWidth),PlayerColour);

                  End;
         End;
End;

{
Put the lasers on the screen.
}


Procedure DrawLasers;
var LaserCount: byte;
Begin
     If LasersFired <>0 Then
     For LaserCount:=1 to MaxLasers do
         If LaserRec[LaserCount].LaserType <> LaserFree Then
         With LaserRec[LaserCount] do
         Begin
         SetColour(LaserColour);
         MoveTo(LaserX,LaserY);
         LineRel(Round(QCos[LaserAngle]*LaserSize),
         Round(QSin[LaserAngle]*LaserSize));
         End;

End;


{$IFDEF BONUSES}

Procedure DrawBonuses;
var BonusCount: byte;

Begin
     SetColour(255);
     If BonusesOnScreen <>0 Then
        For BonusCount:=1 to MaxBonuses do
            With BonusRec[BonusCount] do
            If BonusType <>0 Then
               Begin
               Circle(BonusX+4,BonusY+4,12);

{$IFDEF FULLDISPLAY}
               UseFont(Font8x14);
               TextXY(BonusX,BonusY,BonusString[BonusType]);
{$ELSE}
               OutTextXY(BonusX,BonusY,BonusString[BonusType]);
{$ENDIF}
               End;

End;

{$ENDIF}

Procedure CheckBounds(Var XPos,YPos:integer;
                          ObjectWraps: boolean;
                          Var DidWrap:boolean); Assembler;

Asm
   CMP ObjectWraps,1

   JNE @ObjectDoesNotWrap

   MOV SI,RightBoundary
   MOV DI,LeftBoundary
   MOV CX,BottomBoundary
   MOV DX,TopBoundary
   JMP @LetsDoThisshit


@ObjectDoesNotWrap:
   MOV SI,LeftBoundary
   MOV DI,RightBoundary
   MOV CX,TopBoundary
   MOV DX,BottomBoundary

@LetsDoThisshit:
     XOR AL,AL

     LES BX,XPos
     MOV BX,[ES:BX]

     CMP BX,LeftBoundary
     JG @XPosMoreThanLeft

     LES DI,XPos
     MOV [ES:DI],SI

     INC AL
     JMP @NowTestVertical


@XPosMoreThanLeft:
     CMP BX,RightBoundary
     JL @NowTestVertical

     LES SI,Xpos
     MOV [ES:SI],DI

     INC AL




@NowTestVertical:
     LES BX,Ypos
     MOV BX,[ES:BX]

     CMP BX,TopBoundary
     JG @YPosMoreThanTop

     LES DI,Ypos
     MOV [ES:DI],CX
     MOV AL,1
     JMP @Finito

@YPosMoreThanTop:
     CMP BX,BottomBoundary
     JL @Finito

     LES DI,YPos
     MOV [ES:DI],DX

     MOV AL,1

@Finito:
     LES DI,DidWrap
     MOV [ES:DI],AL
End;


Procedure AddLaser(LaserToAdd: Laser);
Var VacantLaserNumber: byte;
    LaserCount: byte;

Begin
     If LaserRec[LastLaserIndex].LaserType = LaserFree Then
        VacantLaserNumber:=LastLaserIndex
     Else
         Begin
         VacantLaserNumber:=$FF;
         For LaserCount:=1 to MaxLasers do
             Begin
             If LaserRec[LaserCount].LaserType = LaserFree Then
                Begin
                VacantLaserNumber:=LaserCount;
                LaserCount:=MaxLasers;
             End;
         End;
     End;

     If VacantLaserNumber <> $FF Then
        Begin
        Inc(LasersFired);
        LaserRec[VacantLaserNumber]:=LaserToAdd;
     End;
End;


Procedure DoFireRoutine(ShipNo:byte);
Var TAngle: word;
Begin
     If LasersFired <> MaxLasers Then
        With PlayerRec[ShipNo] do
        Begin
             TempLaser.LaserType:=CurrentLaserType;
             TempLaser.FiredBy:=ShipNo;
             If AssFiring Then
                Begin
                TempLaser.LaserX:=PlayerX-Round(QCos[PlayerAngle] * 6);
                TempLaser.LaserY:=PlayerY-Round(QSin[PlayerAngle] * 6);

                TAngle:=PlayerAngle+180;

                Asm
                MOV AX,TAngle
                CMP AX,360
                JB @NoReset
                SUB AX,360
@NoReset:
                MOV Tangle,AX
                End;

                TempLaser.LaserAngle:= TAngle;
                End
             Else
                 Begin
                 Templaser.LaserX:=PlayerX+Round(QCos[PlayerAngle] * 6);
                 Templaser.LaserY:=PlayerY+Round(QSin[PlayerAngle] * 6);
                 Templaser.LaserAngle:= PlayerAngle;
             End;

             { Make sure you know who fired the laser }

             TempLaser.LaserColour:=PlayerColour;

             TempLaser.LaserPower:=CurrentLaserPower;
             TempLaser.LaserSize:= PlayerLaserSize;
             TempLaser.LaserSpeed:=CurrentLaserSpeed;
             TempLaser.MaxLaserTravel:=CurrentMaxLaserTravel;

             AddLaser(TempLaser);

             Dec(PlayerScore,DeductionForShooting);
             If PlayerScore < 0 Then PlayerScore:=0;
        End;
End;


Procedure AlterShip(ShipNo:byte;UpKey,DownKey,LeftKey,RightKey,FireKey:boolean);
Var DiscardedVar: boolean;
    TempKey: boolean;

Begin
       With PlayerRec[ShipNo] do
            Begin

            If UpKey Then
               Begin
               Thrusting:=True;
               If WaitCount > 1 Then
                  Dec(WaitCount);
               End
            Else
                Begin
                Thrusting:=False;
                If WaitCount < MaxWaitCount Then
                   Inc(WaitCount)
                Else


                    Begin
                    Dec(RechargeTime);
                    If (RechargeTime = 0) And
                    (PlayerEnergy < MaxPlayerEnergy) And
                    (PlayerScore >= RechargeDeduction) Then

                       Begin
                       RechargeTime:=RechargeLatch;
                       Inc(PlayerEnergy);

                       Dec(PlayerScore, RechargeDeduction);
                       End;
                    End;
                End;


            If KeyReverseTime <>0 Then
               Begin
               TempKey:=LeftKey;
               LeftKey:=RightKey;
               RightKey:=TempKey;
            End;


            If LeftKey Then
            Begin
                 Dec(PlayerAngle,ShipTurnAngle);
                 If PlayerAngle <1 Then
                    Inc(PlayerAngle,360);
            End;


            If RightKey Then
            Begin
                 Inc(PlayerAngle,ShipTurnAngle);
                 If PlayerAngle > 359 Then
                    Dec(PlayerAngle,360);
            End;

            {
            Has the player held down the fire button.
            }

            If FireKey Then
               Begin
               If (DisableTime=0) Then
                  Begin
                  If AutoFire Then
                  Begin

                     If FireDelay = 0 Then
                        Begin
                        FireDelay:=FireLatch;
                        DoFireRoutine(ShipNo);
                        End
                     Else

                         Dec(FireDelay);
                  End
                  Else
                      If FireKeyReleased Then
                      Begin
                         FireKeyReleased:=False;
                         DoFireRoutine(ShipNo);
                      End;
               End;
            End
            Else

                FireKeyReleased:=True;



            If WaitCount <> MaxWaitCount Then
               Begin
               Inc(PlayerWait);
               If PlayerWait >= WaitCount Then
                  Begin
                  PlayerWait:=0;
                  Inc(PlayerX, Round(Qcos[PlayerAngle]*PlayerSpeed));
                  Inc(PlayerY, Round(QSin[PlayerAngle]*PlayerSpeed));


                  CheckBounds(PlayerX,PlayerY,PlayerWraps,DiscardedVar);
                  End;
            End;
       End;

End;

Procedure UpDatePlayersSpin(PlayerNo:byte);
Var DiscardedVar: boolean;
Begin
     With PlayerRec[PlayerNo] do
     Begin


     Inc(PlayerAngle,ShipTurnAngle SHL 3);
     If PlayerAngle > 359 Then Dec(PlayerAngle,360);


     Inc(PlayerX, Round(Qcos[SpinAngle]*SpinSpeed));
     Inc(PlayerY, Round(QSin[SpinAngle]*SpinSpeed));


     CheckBounds(PlayerX,PlayerY,PlayerWraps,DiscardedVar);
     End;
End;

{$IFNDEF BONUSES}
Procedure UpDateBonusTimer(PlayerNo:byte);
Begin
     { Shields }
     With PlayerRec[PlayerNo] do
     If InvulnerableTime <>0  Then
        Begin
        Dec(InvulnerableTime);
        If InvulnerableTime = 0 Then
           Begin
           PlayerMessage:='SHIELDS DOWN!';
           MessageTime:=NormalMessageTIme;
           EnemyLaserHurts:=True;
        End;
     End;
End;

{$ELSE}

Procedure UpdateBonusTimers(PlayerNo:byte);
Begin
     With PlayerRec[PlayerNo] do
     Begin

     { Firing }

     If DisableTime <>0 Then
        Begin
        Dec(DisableTime);
        If DisableTime = 0 Then
           Begin
           PlayerMessage:='I CAN SHOOT AGAIN!';
           MessageTime:=NormalMessageTime;
        End;
     End;

     { Slothfullness }

     If SlowedDownTime <>0 Then
     Begin
          Dec(SlowedDownTime);
          If SlowedDownTime = 0 Then
             PlayerSpeed:=NormalPlayerSpeed;
     End;

     { Key reversing, i.e. press key for left and you go right }

     If KeyReverseTime <>0 Then
        Dec(KeyReverseTime);

     { Shields }

     If InvulnerableTime <>0  Then
        Begin
        Dec(InvulnerableTime);
        If InvulnerableTime = 0 Then
           Begin
           PlayerMessage:='SHIELDS DOWN!';
           MessageTime:=NormalMessageTIme;
           EnemyLaserHurts:=True;
        End;
     End;

     { Toody's special bonus }

     If BanzaiTime <> 0 Then
        Begin
        Dec(BanzaiTime);
        If BanzaiTime = 0 Then
           Begin
           PlayerMessage:='TOODY''S POWER GONE!';
           MessageTime:=NormalMessageTime;
        End;
     End;

     End;
End;

{$ENDIF}

{
You have to check the player's status byte to determine whether
or not he's spinning, frozen, etc.
}


Procedure CheckPlayerStatusByte(PlayerNo:byte);
Begin
     With PlayerRec[PlayerNo] Do
     Begin
     {
     Now service the PlayerStatus bits
     }

     If (PlayerStatus And Frozen)=Frozen Then
        Begin
        If FrozenTime > 0 Then
           Dec(FrozenTime)
        Else
            PlayerStatus:=PlayerStatus And (255-Frozen);
     End;


     If (PlayerStatus And Spinning)=Spinning Then
        Begin

        Dec(SpinCount);
        If SpinCount <>0 Then
           UpdatePlayersSpin(PlayerNo)
        Else
            Begin

            PlayerStatus:= ShootAble;
            WaitCount:=MaxWaitCount;
            End;
        End
     Else
         If PlayerStatus = Exploding Then
            Begin

            Inc(ExplodeWidth,5);

            If ExplodeWidth >= MaxExplodeWidth Then
               Begin
               PlayerStatus:= Dead;
               Dec(PlayersAlive);
               End;
            End
         Else
             If PlayerStatus = Warping Then
                Begin
                Dec(ExplodeWidth,5);
                If ExplodeWidth <=5 Then
                   PlayerStatus:=ShootAble;
             End;

     End;
End;

{
Update the player's ships.

PlayerStatus is a combination of BIT FLAGS which indicate to the
program the current player status. Doh!

If bit 0 of PlayerStatus is set then the player is still ShootAble. (i.e. Alive)
If bit 1 of PlayerStatus is set then the player is Warping.
If bit 2 of PlayerStatus is set then the player is Exploding.
If bit 3 of PlayerStatus is set then the Player is Spinning.
If bit 4 of PlayerStatus is set the player is Frozen.

Bits 5 - 7 are undefined and should stay that way for now.
}

Procedure MoveShips;
Var PlayerCount: byte;
Begin
     For PlayerCount:=1 to PlayersOn do
         With PlayerRec[PlayerCount] do
         If (PlayerStatus = ShootAble) Then
            Begin
            Case PlayerCount Of

            1: AlterShip(1,keydown[2],keydown[15],keydown[30],keydown[45],keydown[42]);
            2: AlterShip(2,keydown[24],keydown[38],keydown[39],keydown[40],keydown[52]);
            3: AlterShip(3,keydown[71],keydown[76],keydown[73],keydown[74],keydown[81]);

            End;

{$IFNDEF BONUSES}
            UpdateBonusTimer(PlayerCount);
{$ELSE}
            UpdateBonusTimers(PlayerCount);
{$ENDIF}
            End
         Else
             CheckPlayerStatusByte(PlayerCount);
End;

{
O.K. You've got to update the lasers (and special weapons later
on, perhaps)

}

Procedure MoveLasers;
var playercount: byte;
    LaserCount: byte;
    ItWrapped: boolean;

Begin
     If LasersFired <>0 Then
        Begin
        For LaserCount:=1 to MaxLasers do
            With LaserRec[LaserCount] do
            Begin

            If LaserType<>LaserFree Then
               Begin

               Inc(LaserTravel);

               If LaserTravel < MaxLaserTravel Then
                  Begin

                  Inc(LaserX, Round(Qcos[LaserAngle]*LaserSpeed));
                  Inc(LaserY, Round(QSin[LaserAngle]*LaserSpeed));


                  CheckBounds(LaserX,LaserY, LaserType = LaserWraps,ItWrapped);


                  If ItWrapped Then
                     Begin
                     Case LaserType of
                     NormalLaser:   Begin
                                    LaserType:=LaserFree;
                                    LastLaserIndex:=LaserCount;
                                    Dec(LasersFired);
                                    End;

                     LaserRebound:  LaserAngle:=Random(359);
                     End;
                     End;
                  End
               Else

                   Begin
                   LaserType:=LaserFree;
                   Dec(LasersFired);



                   LastLaserIndex:=LaserCount;

                   End;
               End;
            End;
        End;
End;

{$IFDEF BONUSES}


{
The Bonuses are not player controlled (of course) so therefore
the MoveBonuses routine should initiate some bonuses as well
as move them.

How will the CPU know when to initiate bonuses? Well as you
know, it can't so It'll have to be a purely random thingie.
}

Procedure MoveBonuses;
Var BonusCount: byte;
    SearchCount: byte;
    BonusDidWrap: boolean;

Begin
     If BonusesOnScreen <>0 Then
        For BonusCount:=1 to MaxBonuses do
        With BonusRec[BonusCount] do
             If BonusType <>0 Then
             Begin
             Inc(BonusX,BonusXIncrement);
             Inc(BonusY,BonusYIncrement);
             CheckBounds(BonusX,BonusY,true,BonusDidWrap);

             End;

     {
     Of course, some bonuses just have to be initialised as
     well !
     }

     If (BonusesOnScreen <= MaxBonuses) And (Random(80)=40) Then
        Begin
        SearchCount:=1;
        Repeat
              With BonusRec[SearchCount] do
              If BonusType = 0 Then
                   Begin
                   Inc(BonusesOnScreen);

                   BonusType:=1+(Random(NumberOfBonuses));

                   BonusX:=Random(319);

                   Case Random(3) of
                   0..1: BonusY:=-1;
                   2..3: BonusY:=200;
                   End;

                   Case Random(3) of
                   0..1: BonusXIncrement:=-1;
                   2..3: BonusXIncrement:=1;
                   End;

                   Case Random(3) of
                   0..1: BonusYIncrement:=-1;
                   2..3: BonusYIncrement:=1;
                   End;

                   SearchCount:=MaxBonuses;
              End;

        Inc(SearchCount);

        Until SearchCount > MaxBonuses;
     End;

End;

{$ENDIF}










Function Collision(X1,Y1,X2,Y2:integer;DistX,DistY:word): boolean; {Assembler;}
Begin
     Collision:=(Abs(X2-X1) < DistX) And (Abs(Y2-Y1) < DistY)
End;

{===================================================================

Guess what this routine does ?

}


Procedure UpdatePlayerScore(PlayerNo: byte; HowManyPoints: integer);
Begin
     With PlayerRec[PlayerNo] do
     Begin
     Inc(PlayerScore,HowManyPoints);
     If PlayerScore > $7FFFFFFF Then
        PlayerScore := $7FFFFFFF;
     End;
End;

{=====================================================

I'm gonna have to optimize this one day.. For now tho'
I'll leave it as it is so that the B.Sc chaps can suss
what's happening..
}

Procedure DoPlayerToLaser;
Var PlayerCount: byte;
    LaserCount: byte;
    Object1X: integer;
    Object2X: integer;
    Object1Y: integer;
    Object2Y: integer;

    TempLaserPower: byte;
    PersonWhoShot: byte;

Begin
     If LasersFired <>0 Then
        For PlayerCount:=1 to PlayersOn do
            With PlayerRec[PlayerCount] do
            If ((PlayerStatus AND Shootable)<>0) Then
               Begin
               Object2X:=PlayerX;
               Object2Y:=PlayerY;


               For LaserCount:=1 to MaxLasers do
               If (LaserRec[LaserCount].LaserType <> LaserFree) Then
                  Begin
                  With LaserRec[LaserCount] do
                       Begin
                       Object1X:=LaserX;
                       Object1Y:=LaserY;
                  End;

                  If Collision( Object1X,Object1Y,
                                Object2X,Object2Y,8,8) Then
                     Begin
                     PersonWhoShot:=LaserRec[LaserCount].FiredBy;

                     With PlayerRec[PersonWhoShot] do
                          Begin
                          Inc(PlayerScore,PointsForShooting);
                          If Playerscore > $7FFFFF Then
                             PlayerScore:= $7fffff;
                     End;

                     {
                     Player has been hit so make the missile
                     whack into the ships side and disappear
                     }


                     With PlayerRec[PlayerCount] do
                          If (InvulnerableTime <>0) Then
                             LaserRec[LaserCount].LaserAngle:=Random(359)
                          Else
                              Begin
                              Dec(LasersFired);
                              LaserRec[LaserCount].LaserType:=LaserFree;
                              TempLaserPower:=LaserRec[LaserCount].LaserPower;

                              If LaserRec[LaserCount].Firedby <> PlayerCount Then
                                 Begin
                                 Dec(PlayerEnergy,TempLaserPower);
                                 If PlayerEnergy <= 0 Then
                                    Begin
                                    PlayerStatus:=Exploding;
                                    ExplodeWidth:=0;
                                 End;
                              End;
                          End;
                     End;
                 End;
     End;
End;

{==========================================================

Guess what this does ?

}

Procedure SpinPlayer( PlayerBumped, PlayerWhoBumped: byte);
Var SpeedVar: byte;
    Ratio: byte;

begin
     With PlayerRec[PlayerBumped] do
        Begin
        PlayerStatus:=PlayerStatus OR Spinning;

        SpeedVar := PlayerRec[PlayerWhoBumped].WaitCount;
        Ratio    := PlayerRec[PlayerWhoBumped].MaxWaitCount - SpeedVar;

        WaitCount:=SpeedVar;

        SpinAngle:=PlayerRec[PlayerWhoBumped].PlayerAngle;
        SpinSpeed:= (Ratio SHR 2)+4;
        SpinCount:= (Ratio SHL 1)+4;

        UpDatePlayersSpin(PlayerBumped);
     End
End;

{

Check if two players did bump
}


{$IFDEF BUMPING }


Procedure CheckBump(PlayerCount1, PlayerCount2 : byte);
var
    PlayerSpeed1: byte;
    PlayerSpeed2: byte;

Begin

     If (PlayerRec[PlayerCount1].PlayerStatus = Exploding)
     Or (PlayerRec[PlayerCount2].PlayerStatus = Exploding) Then Exit;


     If (PlayerRec[PlayerCount1].BanzaiTime <>0) And
     (PlayerRec[PlayerCount2].InvulnerableTime = 0) Then
        With PlayerRec[PlayerCount2] do
           Begin
           PlayerStatus:=Exploding;
           ExplodeWidth:=0;
           Message:='AARGH etc. etc. !!';
           MessageTime:=NormalMessageTime;
           End
        Else
            Begin
            PlayerSpeed1:= PlayerRec[PlayerCount1].WaitCount;
            PlayerSpeed2:= PlayerRec[PlayerCount2].WaitCount;

            If (PlayerSpeed2 <= PlayerSpeed1) Then
               SpinPlayer(PlayerCount1,PlayerCount2)
            Else
                UpdatePlayerScore(PlayerCount1,PointsForBumping);
            End;
End;



{$ENDIF}

{$IFDEF BUMPING}

Procedure DoPlayerToPlayer;
Var PlayerCount1: byte;
    PlayerCount2: byte;
    Object1X: integer;
    Object2X: integer;
    Object1Y: integer;
    Object2Y: integer;


Begin
     For PlayerCount1:=1 to PlayersOn do
         If (PlayerRec[PlayerCount1].PlayerStatus AND Shootable =
         ShootAble) Then
            Begin
            With PlayerRec[PlayerCount1] do
                 Begin
                 Object1X:=PlayerX;
                 Object1Y:=PlayerY;
            End;



            {
            Check if the two ships have bumped into each other.
            Not too keen on what I wrote for this part but it works.
            As I said when me B.Sc is finished this part will be
            upgraded.
            }


            For PlayerCount2:=1 to PlayersOn do
                If (PlayerRec[PlayerCount2].PlayerStatus And
                Shootable = Shootable) And
                   (PlayerCount1 <> PlayerCount2) Then
                   Begin
                   {
                   Check if a collision has occurred.
                   }

                   With PlayerRec[PlayerCount2] do
                        Begin
                        Object2X:=PlayerX;
                        Object2Y:=PlayerY;
                   End;

                   {
                   Bumping?
                   }

                   If Collision(Object1X,Object1Y,Object2X,Object2Y,12,12)
                   Then
                      Begin
                      CheckBump(PlayerCount1, PlayerCount2);
                      CheckBump(PlayerCount2, PlayerCount1);
                   End;
                End;
         End;
End;

{$ENDIF}

Procedure Warp(PlayerNo:byte);
Begin
     With PlayerRec[PlayerNo] do
     Begin
          PlayerStatus:=Warping;
          ExplodeWidth:=MaxExplodeWidth;
          PlayerAngle:= Random(359);
          PlayerX:=Random(319);
          PlayerY:=Random(199);
     End;
End;

{$IFDEF BONUSES}

Procedure DoPlayerToBonuses;
Var PlayerCount: byte;
    BonusCount: byte;
    OtherCount: byte;
    Object1X: integer;
    Object2X: integer;
    Object1Y: integer;
    Object2Y: integer;




Begin
     For PlayerCount:=1 to PlayersOn do
         If (PlayerRec[PlayerCount].PlayerStatus And Shootable) = Shootable
            Then Begin

            With PlayerRec[PlayerCount] do
            Begin
                 Object1X:=PlayerX;
                 Object1Y:=PlayerY;
            End;

            For BonusCount:=1 to MaxBonuses do

                If (BonusRec[BonusCount].BonusType <>0 ) Then
                   Begin

                   With BonusRec[BonusCount] do
                        Begin
                        Object2X:=BonusX;
                        Object2Y:=BonusY;
                   End;


                   If collision( Object1X,Object1Y,
                                 Object2X,Object2Y,12,12) Then

                   With BonusRec[BonusCount] do
                   Begin

                        If BonusType = UnknownBonus Then
                           BonusType:= Random(NumberOfBonuses-2)+1;





                        Case BonusType Of
                        SlowDownBonus: begin
                                       With PlayerRec[PlayerCount] do
                                            Begin
                                            Inc(PlayerScore,SlowDownBonusPointsValue);
{$IFDEF MESSAGES}
                                            PlayerMessage:='PICKED UP A SLOWDOWN BONUS !';
                                            MessageTime:=NormalMessageTime;
{$ENDIF}
                                        End;

                                        For OtherCount:=1 to PlayersOn do
                                        If OtherCount <> PlayerCount Then
                                            With PlayerRec[OtherCount] do
                                                 Begin
                                                 If PlayerSpeed <>SlowestPlayerSpeed Then
                                                    Dec(PlayerSpeed);

                                                 Inc(SlowedDownTime,MaxSlowedDownTime);
                                            End;
                                        End;


                   EnergyBonus: With PlayerRec[PlayerCount] do
                                Begin
                                Inc(PlayerScore,EnergyBonusPointsValue);
                                Inc(PlayerEnergy,EnergyIncrement);

                                If PlayerEnergy >MaxPlayerEnergy Then
                                   Begin
                                   PlayerEnergy:=MaxPlayerEnergy;
{$IFDEF MESSAGES}
                                   PlayerMessage:='I DIDN''T NEED THE ENERGY !';
                                   MessageTime:=NormalMessageTime;
{$ENDIF}
{$IFDEF MESSAGES}
                                   End
                                Else
                                    If PlayerEnergy <= EnergyIncrement Then
                                       Begin
                                       PlayerMessage:='ENERGY JUST IN TIME, TOO !';
                                       MessageTime:=NormalMessageTime;
                                       End
                                    Else
                                        Begin
                                        PlayerMessage:='PICKED UP AN ENERGY BONUS !';
                                        messageTime:=NormalMessageTime;
                                    End;

{$ENDIF}
                                End;


                   FreezeBonus: Begin
                                With PlayerRec[PlayerCount] do
                                     Begin
                                     Inc(PlayerScore,FreezeBonusPointsValue);
{$IFDEF MESSAGES}
                                     PlayerMessage:='PICKED UP A FREEZE BONUS !';
                                     MessageTime:=NormalMessageTime;
{$ENDIF}
                                End;

                                For OtherCount:=1 to PlayersOn do
                                    If OtherCount <> PlayerCount Then
                                    With PlayerRec[OtherCount] do
                                    Begin
                                    PlayerStatus:=PlayerStatus OR Frozen;
                                    Inc(FrozenTime,MaxFrozenTime);
                                    WaitCount:=MaxWaitCount;
                                End;
                                End;


                   ReverseBonus: Begin
                                 With PlayerRec[PlayerCount] do
                                 Begin
                                      Inc(PlayerScore,ReverseBonusPointsValue);
{$IFDEF MESSAGES}
                                      PlayerMessage:='PICKED UP A REVERSE BONUS !';
                                      MessageTime:=NormalMessageTime;
{$ENDIF}
                                 End;

                                 For OtherCount:=1 to PlayersOn do
                                    If OtherCount <> PlayerCount Then
                                    With PlayerRec[OtherCount] do
                                         Begin
                                         Inc(KeyReverseTime,MaxKeyReverseTime);
                                         PlayerMessage:='OH NO! KEYS ARE REVERSED !';
                                         MessageTime:=NormalMessageTime;
                                    End;
                                 End;


                   DisableBonus: Begin
                                 With PlayerRec[PlayerCount] do
                                      Begin
                                      Inc(PlayerScore,DisableBonusPointsValue);
{$IFDEF MESSAGES}
                                      PlayerMessage:='PICKED UP A DISABLE BONUS !';
                                      MessageTime:=NormalMessageTime;
{$ENDIF}
                                 End;

                                 For OtherCount:=1 to PlayersOn do
                                 If OtherCount <> PlayerCount Then
                                    Inc(PlayerRec[OtherCount].DisableTime,MaxDisableTime);
                                 End;


                   InvulnerabilityBonus: Begin
                                         With PlayerRec[PlayerCount] do
                                              Begin
                                              EnemyLaserHurts:=False;
                                              InvulnerableTime:=MaxInvulnerableTime;

                                              Inc(PlayerScore,InvulnerabilityBonusPointsValue);
{$IFDEF MESSAGES}
                                              PlayerMessage:='YEAH! I AM INVULNERABLE !';
                                              MessageTime:=NormalMessageTime;
{$ENDIF}
                                         End;
                                         End;


                   AssFiringBonus:  Begin
                                     With PlayerRec[PlayerCount] do
                                          Begin
                                          Inc(PlayerScore,AssFiringBonusPointsValue);
{$IFDEF MESSAGES}
                                          PlayerMessage:='PICKED UP AN Ass FIRING BONUS !';
                                          MessageTime:=NormalMessageTime;
{$ENDIF}
                                     End;

                                     For OtherCount:=1 to PlayersOn do
                                         If OtherCount <> PlayerCount Then
                                            With PlayerRec[OtherCount] do
                                            Begin
                                            AssFiring:=True;
                                         End;
                                     End;


                   NormalBonus:    Begin
                                   With PlayerRec[Playercount] do
                                   Begin
                                        DisableTime:=1;
                                        KeyReverseTime:=1;
                                        SlowedDownTime:=1;
                                        PlayerSpeed:=NormalPlayerSpeed;
                                        CurrentLaserType:=NormalLaser;
                                        AssFiring:=False;

                                        Inc(PlayerScore,NormalBonusPointsValue);
{$IFDEF MESSAGES}
                                        PlayerMessage:='PICKED UP A NORMALITY BONUS.';
                                        MessageTime:=NormalMessageTime;
{$ENDIF}
                                   End;
                                   End;


                   ToodysBonus:    Begin
                                   With PlayerRec[PlayerCount] do
                                        begin
                                        Inc(BanzaiTime,MaxBanzaiTime);

                                        Inc(PlayerScore,ToodysBonusPointsValue);
{$IFDEF MESSAGES}
                                        PlayerMessage:='BANZAI THE OTHER PLAYERS !';
                                        MessageTime:=MaxBanzaiTime;
{$ENDIF}
                                        End;

                                   For OtherCount:=1 to PlayersOn do
                                   If OtherCount <> PlayerCount Then
                                       With PlayerRec[OtherCount] do
                                       Begin
{$IFDEF MESSAGES}
                                       PlayerMessage:='DO NOT BUMP PLAYER '+chr(48 + PlayerCount)+' !';
                                       MessageTime:=MaxBanzaiTime;
{$ENDIF}
                                       End
                                   End;


                   LaserBonus:     Begin
                                   With PlayerRec[PlayerCount] do
                                   If CurrentLaserPower < MaxLaserPower Then
                                      Begin
                                      Inc(CurrentlaserPower);

                                      Inc(PlayerScore,LaserBonusPointsValue);
{$IFDEF MESSAGES}
                                      PlayerMessage:='LASERS ENHANCED !';
                                      MessageTime:=NormalMessageTime;
{$ENDIF}
                                      End
                                    Else
                                        Begin
                                        PlayerMessage:='WRAP AROUND LASERS !';
                                        CurrentLaserType:=LaserWraps;
                                        MessageTime:=NormalMessageTime;
                                    End;
                                   End;

                   WarpBonus:      With PlayerRec[PlayerCount] do
                                   Begin
                                        Warp(PlayerCount);

                                        Inc(PlayerScore,WarpBonusPointsValue);

{$IFDEF MESSAGES}
                                        PlayerMessage:='WARPING !';
                                        MessageTime:=NormalMessageTime;
{$ENDIF}
                                   End;


            BounceLaserBonus:      With PlayerRec[PlayerCount] do
                                   Begin
                                        CurrentLaserType:= LaserRebound;
{$IFDEF MESSAGES}
                                        PlayerMessage:='OOH! BOUNCY LASERS!';
                                        MessageTime:=NormalMessageTime;
{$ENDIF}
                                   End;
                   End;


                   { Indicate bonus has been taken
                   }


                   BonusRec[BonusCount].BonusType:=0;
                   Dec(BonusesOnScreen);


                End;
         End;
     End;
End;
{$ENDIF}

Procedure DoCollisions;
Begin

     DoPlayerToLaser;

{$IFDEF BUMPING}
     DoPlayerToPlayer;
{$ENDIF}

{$IFDEF BONUSES}
     DoPlayerToBonuses;
{$ENDIF}
End;

Begin
     LoadGraphics;
     If (PlanetSeg <>0) And (titleBitmapSeg<>0)
     And (EmporerSeg<>0) And (ScratchSeg<>0) Then
        Begin


        Repeat

              InitVGAMode;
              SetAllPalette(titleBitmapPalette);

              SetUpPlayers;

              SetAllPalette(DestroyerPalette);
              SetPalette(253,63,63,63);
              SetPalette(254,63,0,0);
              SetPalette(255,63,63,0);

              HookKeyboardInt;


              SelectFont(1);

              Repeat
                    BitmapCopy(PlanetSeg,PlanetOfs);
                    DrawPlayerStuff;
                    DrawLasers;

{$IFDEF BONUSES}
                    DrawBonuses;
{$ENDIF}

                    Vwait(1);
                    CopySourceBitmap ;


                    MoveShips;
                    MoveLasers;

{$IFDEF BONUSES}
                    MoveBonuses;
{$ENDIF}

                    DoCollisions;

                    delay(1);

              Until (keydown[1]) or (PlayersAlive <= 1);


              { back to normal crap DOS key reading }

              UnHookKeyboardInt;

              If PlayersAlive <= 1 Then
                 Begin

                 Memw[$0040:$1a]:=Memw[$0040:$1c];

                 SetAllPalette(EmporerPalette);

                 BitMapCopy(EmporerSeg,EmporerOfs);
                 SelectFont(6);

                 SetColour(255);

                 {
                 El snido messago (Adjust to suit your peer group)
                 }

                 Case Random(20) of
                 0: Message:='Even Paul Langa has scored more !';
                 1: Message:='Stop drinking and you''ll shoot better !';
                 2: Message:='Next time, press the fire button !';
                 3: Message:='Are you sure that you weren''t cheating ?';
                 4: Message:='Come in and meet my daughter, son!';
                 5: Message:='Next time SHOOT the other players !!';
                 6: Message:='Would you like to see my puppies ?';
                 7: Message:='Ian Makin has eyebrows just like these !';
                 9: Message:='';
                10: Message:='What a waste of good hard disk space !';
                11: Message:='Does your maw know you''re here ?';
                12: Message:='I bet you''re one of Tunstall''s mates !';
                13: Message:='Your performance was pure f***ing crap !';
                14: Message:='Come up and see my etchings, young man !';
                15: Message:='You sure did kick some ass out there !';
                16: Message:='I bet you drink Carling Black Label !';
                17: Message:='Err... I love you.';
                18: Message:='I never liked Dune that much anyway !';
                19: Message:='Your mum looks like Yoda from Star Wars !';
                20: Message:='I''m buying the rounds tonight son !';
                End;

                 OutTextXY( ((40 - Length(Message))DIV 2) *8,160,Message);

                 CopySourceBitmap ;

                 Delay(2000);

                 Memw[$0040:$1a]:=Memw[$0040:$1c];
                 TempKey:=ReadKey;
              End;

        Until Keydown[1];  { Until key is definitely ESC }

        {
        Right, deallocate the memory required for the
        game & virtual screens.
        }

        FreeBitmap(PlanetSeg,PlanetOfs);

        FreeBitmap(titleBitmapSeg,TitleBitmapOfs);

        FreeBitmap(EmporerSeg, EmporerOfs);

        FreeBitmap(ScratchSeg,ScratchOfs);
        End
   Else
       Begin
       Writeln;
       Writeln('Memory allocation error! 400K bytes free on heap needed.');
   End;
End.

{ I love you all !!! ;) }