Program GravityWars; { by Sohrab Ismail-Beigi Completed 4/23/89 SYSOP of The 3D Graphics BBS 300/1200/2400 baud, N-8-1 Full duplex (201) 444-4154} {Turbo Pascal 4.0 source code. Requires VGA 640x480x16 display.} {Note: pix=pixels in the comments} Uses Crt,Graph; Type spacecraft=Record {used for ships and pointer} coffx,coffy,r : longint; {center offsets and radius in pix} imagex,imagey : longint; {upper left of image} imagepointr : pointer; {pointer to image data} imagesize : word; {size in bytes} end; planettype=Record cx,cy,r : longint; {planet center and radius} d,GM : real; {density and G*M product} end; Const color : array[1..3] of byte=(Red,Green,LightBlue); {colors for planets} G=0.1; {gravity constant} bhr=15; {black hole radius} Esc=#27; {ASCII for Esc} Return=#13; { " " RETURN} Var ship : array[1..2] of spacecraft; {2 ships} tp,pointr : spacecraft; {tp is temporary, 1 pointer} pl : array[1..9] of planettype; {the 9 planets} screen : Record {the game area} sx,ex,sy,ey,cx,cy,lx,ly : longint; {start x/y, end x/y, center} end; {x/y, length x/y} np,GraphDriver,GraphMode : integer; {# of planets} criticaldist : real; {for escape velocity calc} playsong : boolean; {play the songs?} Procedure Init; {initialize everything} begin SetGraphBufSize(10); {make the buffer big enough for big floodfills} GraphDriver:=VGA; GraphMode:=VGAHi; InitGraph(GraphDriver,GraphMode,'c:\turbo4'); SetColor(LightGray); SetFillStyle(SolidFill,LightGray); {Hull of ships} Circle(100,100,9); FloodFill(100,100,LightGray); Bar(77,98,100,102); MoveTo(82,98); LineRel(-3,-8); LineRel(-13,0); LineRel(0,-3); LineRel(24,0); LineRel(0,3); LineRel(-7,0); LineRel(3,8); FloodFill(83,97,LightGray); MoveTo(82,101); LineRel(-3,8); LineRel(-13,0); LineRel(0,3); LineRel(24,0); LineRel(0,-3); LineRel(-7,0); LineRel(3,-8); FloodFill(83,103,LightGray); MoveTo(200,200); LineRel(5,-5); LineRel(5,5); LineRel(10,0); LineRel(5,-8); LineRel(15,0); LineRel(-6,9); LineRel(6,9); LineRel(-15,0); LineRel(-5,-7); LineRel(-10,0); LineRel(-5,5); LineRel(-6,-7); LineRel(2,-2); FloodFill(201,201,LightGray); SetColor(LightRed); SetFillStyle(SolidFill,LightRed); {Red lights on ships} Circle(100,100,2); FloodFill(100,100,LightRed); Bar(89,87,91,90); Bar(89,109,91,112); Bar(224,200,226,203); Bar(240,192,242,194); Bar(240,208,242,210); SetColor(Yellow); MoveTo(0,0); LineRel(0,10); MoveTo(0,0); LineRel(10,0); MoveTo(0,0); LineRel(15,15); {pointer} tp.imagesize:=ImageSize(0,0,16,16); {kludge to subdue compiler bug} GetMem(tp.imagepointr,tp.imagesize); GetImage(0,0,16,16,tp.imagepointr^); pointr.imagesize:=ImageSize(0,0,16,16); GetMem(pointr.imagepointr,pointr.imagesize); GetImage(0,0,16,16,pointr.imagepointr^); {get pointer} pointr.coffx:=7; pointr.coffy:=7; pointr.r:=9; ship[1].imagesize:=ImageSize(66,87,110,113); GetMem(ship[1].imagepointr,ship[1].imagesize); GetImage(66,87,110,113,ship[1].imagepointr^); {enterprise} ship[1].coffx:=22; ship[1].coffy:=13; ship[1].r:=26; ship[2].imagesize:=ImageSize(199,192,242,210); GetMem(ship[2].imagepointr,ship[2].imagesize); GetImage(199,192,242,210,ship[2].imagepointr^); {klingon} ship[2].coffx:=21; ship[2].coffy:=9; ship[2].r:=23; ClearDevice; screen.sx:=1; screen.ex:=638; screen.sy:=33; screen.ey:=478; screen.cx:=(screen.sx+screen.ex) div 2; {initialize screen} screen.cy:=(screen.sy+screen.ey) div 2; {bounds} screen.lx:=screen.ex-screen.sx+1; screen.ly:=screen.ey-screen.sy+1; criticaldist:=2.0*sqrt(sqr(screen.lx)+sqr(screen.ly)); {critical distance} playsong:=true; {for escape vel. calc} end; Procedure Finish; {free memory and end} begin FreeMem(ship[1].imagepointr,ship[1].imagesize); FreeMem(ship[2].imagepointr,ship[2].imagesize); FreeMem(pointr.imagepointr,pointr.imagesize); FreeMem(tp.imagepointr,tp.imagesize); CloseGraph; end; Function InBounds(cx,cy,r:longint):boolean; {is the point with radius} begin {completely in screen bounds?} InBounds:=true; if r<>0 then if (cx-r<=screen.sx) or (cx+r>=screen.ex) or (cy-r<=screen.sy) or (cy+r>=screen.ey) then InBounds:=false else if (cx-bhr<=screen.sx) or (cx+bhr>=screen.ex) or (cy-bhr<=screen.sy) or (cy+bhr>=screen.ey) then InBounds:=false; end; Procedure RandomSetup; {make a random setup} var i,j : integer; a,b : longint; ok : boolean; begin Randomize; np:=Random(9)+1; {random # of planets 1-9} for i:=1 to np do {pick planet positions} Repeat ok:=true; pl[i].cx:=Random(screen.lx)+screen.sx; pl[i].cy:=Random(screen.ly)+screen.sy; pl[i].d:=(Random(3)+2)/2.0; pl[i].r:=0; if Random>0.05 then pl[i].r:=Random(70)+20; {5% chance of blackhole} if pl[i].r<>0 then pl[i].GM:=G*2*pi*sqr(pl[i].r)*pl[i].d else pl[i].GM:=G*2*pi*sqr(30)*1.0; ok:=InBounds(pl[i].cx,pl[i].cy,pl[i].r); if (i>1) and (ok) then {any collisions with existing planets?} for j:=1 to i-1 do begin if sqrt(sqr(pl[i].cx-pl[j].cx)+sqr(pl[i].cy-pl[j].cy))<= pl[i].r+pl[j].r+2*bhr then ok:=false; end; Until ok; for i:=1 to 2 do {pick ship positions} Repeat ok:=true; ship[i].imagex:=Random(screen.lx div 2)+screen.sx; {enterprise to the} if i=2 then ship[2].imagex:=ship[i].imagex+screen.lx div 2; {left and} ship[i].imagey:=Random(screen.ly)+screen.sy; {klingon to the right} a:=ship[i].imagex+ship[i].coffx; b:=ship[i].imagey+ship[i].coffy; ok:=InBounds(a,b,ship[i].r); for j:=1 to np do {any collisions with planets?} if sqrt(sqr(a-pl[j].cx)+sqr(b-pl[j].cy))<=pl[j].r+ship[i].r+bhr then ok:=false; Until ok; end; Procedure DrawSetup; {draw current setup} var i,j : integer; begin ClearDevice; SetColor(White); Rectangle(screen.sx-1,screen.sy-1,screen.ex-1,screen.ey-1); {game box} for i:=1 to 2000 do {2000 random stars} PutPixel(Random(screen.lx)+screen.sx,Random(screen.ly)+screen.sy,White); for i:=1 to 2 do {2 ships} PutImage(ship[i].imagex,ship[i].imagey,ship[i].imagepointr^,NormalPut); for i:=1 to np do {np planets} if pl[i].r>0 then {normal} begin SetColor(color[trunc(pl[i].d*2-1)]); Circle(pl[i].cx,pl[i].cy,pl[i].r); SetFillStyle(SolidFill,color[trunc(pl[i].d*2-1)]); FloodFill(pl[i].cx,pl[i].cy,color[trunc(pl[i].d*2-1)]); end else {black hole} begin SetColor(Black); for j:=0 to bhr do Circle(pl[i].cx,pl[i].cy,j); end; end; Procedure ClearDialogBox; {clear text message area} begin SetFillStyle(SolidFill,Black); Bar(0,0,screen.ex-1,screen.sy-2); end; Function GetString:string; {get a string until RETURN is pressed} var s : string; c : char; begin s:=''; Repeat c:=ReadKey; if (c=chr(8)) and (length(s)>0) then {backspace key} begin delete(s,length(s),1); MoveRel(-8,0); {delete last char} SetFillStyle(SolidFill,Black); Bar(GetX,GetY,GetX+8,GetY+8); end else if c<>Return then begin s:=concat(s,c); {get and draw char} SetColor(LightGray); OutText(c); end; Until c=Return; GetString:=s; end; Procedure PlayGame; Const number_of_explosion_dots=20; {# dots for explosion with planet surface} Var vx,vy,vc,x,y,dt,ax,ay,dx,dy,dr,k : real; v0,angle : array[1..2] of real; s : string; ch : char; i,event,player,winner : integer; ok,donecritical,offscreen : boolean; buffer : array[1..number_of_explosion_dots] of Record {for explosion} x,y,color : integer; end; begin v0[1]:=0; v0[2]:=0; angle[1]:=0; angle[2]:=0; player:=1; donecritical:=false; Repeat {infinite loop} ClearDialogBox; SetColor(LightGray); str(player,s); s:=concat('Player ',s); {player #} OutTextXY(0,0,s); Repeat {get angle} MoveTo(0,10); str(angle[player]:3:5,s); s:=concat('Angle: [',s,']: '); OutText(s); s:=GetString; if (s[1]='Q') or (s[1]='q') then exit; i:=0; if s<>'' then Val(s,angle[player],i); SetFillStyle(SolidFill,Black); ok:=(i=0) and (angle[player]>=0.0) and (angle[player]<=360); if not ok then Bar(0,0,screen.ex-1,8); Until ok; Repeat {get initial velocity} MoveTo(0,20); str(v0[player]:2:5,s); s:=concat('Initial Velocity: [',s,']: '); OutText(s); s:=GetString; if (s[1]='Q') or (s[1]='q') then exit; i:=0; if s<>'' then Val(s,v0[player],i); SetFillStyle(SolidFill,Black); ok:=(i=0) and (v0[player]>=0.0) and (v0[player]<=10.0); if not ok then Bar(0,10,screen.ex-1,18); Until ok; k:=pi*angle[player]/180.0; {angle in radians} vx:=v0[player]*cos(k); vy:=-v0[player]*sin(k); x:=ship[player].imagex+ship[player].coffx+ship[player].r*cos(k); y:=ship[player].imagey+ship[player].coffy-ship[player].r*sin(k); ClearDialogBox; MoveTo(round(x),round(y)); SetColor(White); offscreen:=false; Repeat {calculate and draw trajectory} dt:=0.25; {time interval [vel. is in pix/time]} x:=x+vx*dt; y:=y+vy*dt; ax:=0; ay:=0; for i:=1 to np do {calc accel. due to gravity} begin dx:=x-pl[i].cx; dy:=y-pl[i].cy; dr:=sqrt(sqr(dx)+sqr(dy)); k:=1/(sqr(dr)*dr); if pl[i].r<>0 then {normal} begin ax:=ax-pl[i].GM*dx*k; ay:=ay-pl[i].GM*dy*k end else {black hole} begin ax:=ax-pl[i].GM*dx*(k+sqr(k*dr)); ay:=ay-pl[i].GM*dy*(k+sqr(k*dr)); end; end; vx:=vx+ax*dt; vy:=vy+ay*dt; event:=0; if keypressed then event:=1 else if (x>=screen.sx) and (x<=screen.ex) and {in screen bounds?} (y>=screen.sy) and (y<=screen.ey) then begin donecritical:=false; i:=GetPixel(round(x),round(y)); if (i=color[1]) or (i=color[2]) or (i=color[3]) or (i=LightRed) or (i=LightGray) then event:=2 else if offscreen then MoveTo(round(x),round(y)) else LineTo(round(x),round(y)); offscreen:=false; end {off screen} else if not donecritical then begin offscreen:=true; {offscreen and critical distance} dx:=x-screen.cx; dy:=y-screen.cy; dr:=sqrt(sqr(dx)+sqr(dy)); if dr>=criticaldist then begin vc:=(dx*vx+dy*vy)/dr; k:=0; for i:=1 to np do k:=k+pl[i].GM; if 0.5*sqr(vc)>=k/dr then {do we have escape velocity?} event:=3; end; end; Until event<>0; if event=1 then {a key was pressed for a break} begin ClearDialogBox; ch:=ReadKey; {one already in buffer} SetColor(LightGray); OutTextXY(0,0,'Break... Esc to break, any other key to continue'); ch:=ReadKey; if ch=Esc then exit; end else if event=3 then {missile escaped the universe} begin ClearDialogBox; SetColor(LightGray); OutTextXY(0,0,'Missile left the galaxy...'); delay(2000); end else {event=2} {hit something} begin if (i=color[1]) or (i=color[2]) or (i=color[3]) then {hit a planet} begin for i:=1 to number_of_explosion_dots do {draw explosion} begin buffer[i].x:=trunc(x+20*(Random-0.5)); buffer[i].y:=trunc(y+20*(Random-0.5)); buffer[i].color:=GetPixel(buffer[i].x,buffer[i].y); PutPixel(buffer[i].x,buffer[i].y,LightRed); delay(25); end; delay(1000); for i:=1 to number_of_explosion_dots do {erase explosion} PutPixel(buffer[i].x,buffer[i].y,buffer[i].color); end else {hit a ship!} begin if sqrt(sqr(x-ship[1].imagex-ship[1].coffx)+ {which one won?} sqr(y-ship[1].imagey-ship[1].coffy))<=ship[1].r+5 then winner:=2 else winner:=1; for event:=1 to 100 do {flash the screen} SetPalette(Black,Random(16)); SetPalette(Black,Black); for i:=1 to 1000 do {put some white and red points} begin k:=Random*2*pi; event:=Random(3); if event=0 then PutPixel(trunc(x+30*Random*cos(k)),trunc(y+30*Random*sin(k)),Black) else if event=1 then PutPixel(trunc(x+30*Random*cos(k)),trunc(y+30*Random*sin(k)),Red) else PutPixel(trunc(x+20*Random*cos(k)),trunc(y+20*Random*sin(k)),White); end; ClearDialogBox; SetColor(LightGray); str(winner,s); s:=concat('Player ',s,' wins!!!'); {announce} OutTextXY(0,0,s); if playsong then {play a tune} begin Sound(440); delay(150); Nosound; delay(50); Sound(440); delay(150); Sound(554); delay(150); Sound(659); delay(350); Sound(554); delay(150); Sound(659); delay(450); Nosound; delay(500); Sound(880); delay(800); Nosound; end; delay(3000); exit; end; end; {if event=3} Inc(player); if player=3 then player:=1; {next player} Until true=false; {infinite loop} end; Procedure PlayingtheGame; {playing the game menu} var option : char; begin Repeat ClearDialogBox; SetColor(LightGray); OutTextXY(0,0,'1. Random setup 2. Play game Esc quits menu'); OutTextXY(0,10,'Option: '); option:=ReadKey; Case option of '1' : begin ClearDialogBox; RandomSetup; DrawSetup; end; '2' : PlayGame; end; Until option=Esc; end; Procedure Options; {options menu} var option : char; begin Repeat ClearDialogBox; SetColor(LightGray); OutTextXY(0,0,'1. Redraw screen 2. Sound on/off Esc quits menu'); OutTextXY(0,10,'Option: '); option:=ReadKey; Case option of '1' : DrawSetUp; '2' : playsong:=not playsong; end; Until option=Esc; end; Procedure InterpKey(c:char; var x,y,coffx,coffy,r:longint; var jump:integer; var moveit:boolean); begin {interprets keys for movement of pointer, mainly to save} Case c of {space due to shared code in many Change routines} '+' : if jump<49 then Inc(jump,2); '-' : if jump>2 then Dec(jump,2); '8' : begin {up} Dec(y,jump); if InBounds(x+coffx,y+coffy,r) then moveit:=true else Inc(y,jump); end; '2' : begin {down} Inc(y,jump); if InBounds(x+coffx,y+coffy,r) then moveit:=true else Dec(y,jump); end; '4' : begin {left} Dec(x,jump); if InBounds(x+coffx,y+coffy,r) then moveit:=true else Inc(x,jump); end; '6' : begin {right} Inc(x,jump); if InBounds(x+coffx,y+coffy,r) then moveit:=true else Dec(x,jump); end; end; {case c of} end; Procedure MoveShip; {move a given ship to a new legal position} var c : char; s,jump,j : integer; x,y,xold,yold,a,b : longint; legal,moveit : boolean; begin ClearDialogBox; SetColor(LightGray); OutTextXY(0, 0,'Ships: 1. Enterprise 2. Klingon Esc aborts'); OutTextXY(0,10,'Which ship? '); {get the proper ship} Repeat c:=ReadKey; Until (c='1') or (c='2') or (c=Esc); if c=Esc then exit; if c='1' then s:=1 else s:=2; ClearDialogBox; OutTextXY(0, 0,'Use cursors to move ship. (Num Lock on) Esc aborts'); OutTextXY(0,10,'Enter to place, + and - to change size of jumps.'); jump:=30; x:=ship[s].imagex; y:=ship[s].imagey; Repeat {loop until Esc or somewhere legal} Repeat {loop until Esc or RETURN} Repeat c:=ReadKey; Until (c='4') or (c='8') or (c='6') or (c='2') or (c='+') or (c='-') or (c=Return) or (c=Esc); moveit:=false; xold:=x; yold:=y; InterpKey(c,x,y,ship[s].coffx,ship[s].coffy,ship[s].r,jump,moveit); if moveit then {if can move the image,} begin PutImage(xold,yold,ship[s].imagepointr^,XORPut); {erase old} PutImage(x,y,ship[s].imagepointr^,XORPut); {draw new} moveit:=false; end; Until (c=Return) or (c=Esc); if c=Esc then {abort} begin PutImage(x,y,ship[s].imagepointr^,XORPut); PutImage(ship[s].imagex,ship[s].imagey,ship[s].imagepointr^,NormalPut); exit; end; a:=x+ship[s].coffx; b:=y+ship[s].coffy; legal:=InBounds(a,b,ship[s].r); {in bounds?} for j:=1 to np do {in collision with any planets?} if sqrt(sqr(a-pl[j].cx)+sqr(b-pl[j].cy))<=pl[j].r+ship[s].r+bhr then legal:=false; if not legal then {oops! not legal!} begin SetPalette(Black,White); SetFillStyle(SolidFill,Black); Bar(0,20,screen.ex,screen.sy-2); delay(100); SetPalette(Black,Black); SetColor(LightGray); OutTextXY(0,20,'Illegal ship position!'); end; Until legal; ship[s].imagex:=x; ship[s].imagey:=y; {ok, place it there} end; Procedure MovePlanet; {move a planet} var c : char; i,p,jump : integer; x,y,xold,yold,minr,t,cxorig,cyorig : longint; moveit,legal : boolean; begin ClearDialogBox; if np=0 then {no planets!} begin OutTextXY(0,0,'No planets to move!'); delay(2000); exit; end; OutTextXY(0, 0,'Use cursors to move pointer. (Num Lock on) Esc aborts'); OutTextXY(0,10,'Enter to pick planet, + and - to change size of jumps.'); jump:=30; x:=100; y:=100; PutImage(x,y,pointr.imagepointr^,XORPut); Repeat {loop until Esc or RETURN} Repeat c:=ReadKey; Until (c='4') or (c='8') or (c='6') or (c='2') or (c='+') or (c='-') or (c=Return) or (c=Esc); moveit:=false; xold:=x; yold:=y; InterpKey(c,x,y,pointr.coffx,pointr.coffy,pointr.r,jump,moveit); if moveit then begin PutImage(xold,yold,pointr.imagepointr^,XORPut); PutImage(x,y,pointr.imagepointr^,XORPut); moveit:=false; end; Until (c=Return) or (c=Esc); PutImage(x,y,pointr.imagepointr^,XORPut); {erase pointer} if c=Esc then exit; p:=0; minr:=trunc(sqrt(sqr(screen.lx)+sqr(screen.ly))); for i:=1 to np do {find the closest planet/black hole} begin t:=trunc(sqrt(sqr(x-pl[i].cx)+sqr(y-pl[i].cy))); if tEsc then {ok, RETURN pressed} begin pl[p].cx:=-1000; pl[p].cy:=-1000; {so it won't collide with itself!} for i:=1 to np do {any collisions with other planets?} if sqrt(sqr(x-pl[i].cx)+sqr(y-pl[i].cy))<=pl[i].r+pl[p].r+2*bhr then legal:=false; for i:=1 to 2 do {any collisions with other ships?} if sqrt(sqr(x-ship[i].imagex-ship[i].coffx)+ sqr(y-ship[i].imagey-ship[i].coffy))<=pl[p].r+ship[i].r+bhr then legal:=false; end; if not legal then {oops!} begin SetPalette(Black,White); SetFillStyle(SolidFill,Black); Bar(0,20,screen.ex,screen.sy-2); delay(100); SetPalette(Black,Black); SetColor(LightGray); OutTextXY(0,20,'Illegal planet position!'); end; Until legal; pl[p].cx:=x; pl[p].cy:=y; {put it there} if c=Esc then {abort and restore} begin pl[p].cx:=cxorig; pl[p].cy:=cyorig; end; DrawSetUp; {redraw screen} end; Procedure MakePlanet; {make a planet given center and radius} var c : char; i,p,jump : integer; x,y,xold,yold : longint; moveit,legal : boolean; begin ClearDialogBox; if np=9 then {too many planets already!} begin OutTextXY(0,0,'Can not make any more planets!'); delay(2000); exit; end; OutTextXY(0, 0,'Use cursors to move pointer. (Num Lock on) Esc aborts'); OutTextXY(0,10,'Enter to place center, + and - to change size of jumps.'); jump:=30; x:=100; y:=100; PutImage(x,y,pointr.imagepointr^,XORPut); Repeat {loop until a legal center is picked or Esc} Repeat Repeat c:=ReadKey; Until (c='4') or (c='8') or (c='6') or (c='2') or (c='+') or (c='-') or (c=Return) or (c=Esc); moveit:=false; xold:=x; yold:=y; InterpKey(c,x,y,pointr.coffx,pointr.coffy,pointr.r,jump,moveit); if moveit then begin PutImage(xold,yold,pointr.imagepointr^,XORPut); PutImage(x,y,pointr.imagepointr^,XORPut); moveit:=false; end; Until (c=Return) or (c=Esc); if c=Esc then exit; legal:=true; for i:=1 to np do {any collisions with planets?} if sqrt(sqr(x-pl[i].cx)+sqr(y-pl[i].cy))<=pl[i].r+2*bhr then legal:=false; for i:=1 to 2 do {any collisions with ships?} if sqrt(sqr(x-ship[i].imagex-ship[i].coffx)+ sqr(y-ship[i].imagey-ship[i].coffy))<=ship[i].r+bhr then legal:=false; if not legal then {uh oh!} begin SetPalette(Black,White); SetFillStyle(SolidFill,Black); Bar(0,20,screen.ex,screen.sy-2); delay(100); SetPalette(Black,Black); SetColor(LightGray); OutTextXY(0,20,'Illegal planet center!'); end; Until legal; p:=np+1; pl[p].cx:=x; pl[p].cy:=y; {ok, store the info} ClearDialogBox; OutTextXY(0, 0,'Use cursors to move pointer. (Num Lock on) Esc aborts'); OutTextXY(0,10,'Enter to radius, + and - change size of jumps.'); jump:=30; Repeat {loop until a legal radius is entered or Esc} Repeat Repeat c:=ReadKey; Until (c='4') or (c='8') or (c='6') or (c='2') or (c='+') or (c='-') or (c=Return) or (c=Esc); moveit:=false; xold:=x; yold:=y; InterpKey(c,x,y,pointr.coffx,pointr.coffy,pointr.r,jump,moveit); if moveit then begin PutImage(xold,yold,pointr.imagepointr^,XORPut); PutImage(x,y,pointr.imagepointr^,XORPut); moveit:=false; end; Until (c=Return) or (c=Esc); if c=Esc then exit; legal:=true; pl[p].r:=round(sqrt(sqr(x-pl[p].cx)+sqr(y-pl[p].cy))); {find radius} for i:=1 to np do {planet collisions?} if sqrt(sqr(x-pl[i].cx)+sqr(y-pl[i].cy))<=pl[p].r+pl[i].r+2*bhr then legal:=false; for i:=1 to 2 do {ship collisions?} if sqrt(sqr(x-ship[i].imagex-ship[i].coffx)+ sqr(y-ship[i].imagey-ship[i].coffy))<=pl[p].r+ship[i].r+bhr then legal:=false; if not legal then {oh no!} begin SetPalette(Black,White); SetFillStyle(SolidFill,Black); Bar(0,20,screen.ex,screen.sy-2); delay(100); SetPalette(Black,Black); SetColor(LightGray); OutTextXY(0,20,'Illegal planet radius!'); end; Until legal; PutImage(x,y,pointr.imagepointr^,XORPut); {kill the pointer} Inc(np); {actually add the new planet info} pl[p].d:=1.0; pl[p].GM:=G*2*pi*sqr(pl[p].r)*1.0; {initialize it} SetColor(color[1]); {draw it} Circle(pl[p].cx,pl[p].cy,pl[p].r); SetFillStyle(SolidFill,color[1]); FloodFill(pl[p].cx,pl[p].cy,color[1]); end; Procedure ChangePlanet; {change density [color] of a planet} var c : char; {will not change black holes} i,p,jump : integer; x,y,xold,yold,minr,t : longint; moveit,legal : boolean; begin ClearDialogBox; legal:=false; if np>0 then {see if any non-black holes exist} for i:=1 to np do if pl[i].r<>0 then legal:=true; if (np=0) or (not legal) then {sorry!} begin OutTextXY(0,0,'No planets to change!'); delay(2000); exit; end; OutTextXY(0, 0,'Use cursors to move pointer. (Num Lock on) Esc aborts'); OutTextXY(0,10,'Enter to pick planet, + and - to change size of jumps.'); jump:=30; x:=100; y:=100; PutImage(x,y,pointr.imagepointr^,XORPut); Repeat {repeat until RETURN or Esc} Repeat c:=ReadKey; Until (c='4') or (c='8') or (c='6') or (c='2') or (c='+') or (c='-') or (c=Return) or (c=Esc); moveit:=false; xold:=x; yold:=y; InterpKey(c,x,y,pointr.coffx,pointr.coffy,pointr.r,jump,moveit); if moveit then begin PutImage(xold,yold,pointr.imagepointr^,XORPut); PutImage(x,y,pointr.imagepointr^,XORPut); moveit:=false; end; Until (c=Return) or (c=Esc); PutImage(x,y,pointr.imagepointr^,XORPut); {kill the pointer} if c=Esc then exit; p:=0; minr:=trunc(sqrt(sqr(screen.lx)+sqr(screen.ly))); for i:=1 to np do {find closest non-black hole planet} begin t:=trunc(sqrt(sqr(x-pl[i].cx)+sqr(y-pl[i].cy))); if (t0) then begin minr:=t; p:=i; end; end; ClearDialogBox; OutTextXY(0, 0,'Change to: 1. Red 2. Green 3. Blue Esc aborts'); OutTextXY(0,10,'Option: '); {get a density} Repeat c:=ReadKey; Until (c='1') or (c='2') or (c='3') or (c=Esc); if c=Esc then exit; i:=Ord(c)-48; pl[p].d:=(i+1)/2.0; {new density} SetColor(color[i]); {redraw} Circle(pl[p].cx,pl[p].cy,pl[p].r); SetFillStyle(SolidFill,color[i]); FloodFill(pl[p].cx,pl[p].cy,color[i]); end; Procedure DeletePlanet; {kill a planet/black hole} var c : char; i,p,jump : integer; x,y,xold,yold,minr,t : longint; moveit : boolean; begin ClearDialogBox; if np=0 then {nobody there!} begin OutTextXY(0,0,'No planets to delete!'); delay(2000); exit; end; OutTextXY(0, 0,'Use cursors to move pointer. (Num Lock on) Esc aborts'); OutTextXY(0,10,'Enter to pick planet, + and - to change size of jumps.'); jump:=30; x:=100; y:=100; PutImage(x,y,pointr.imagepointr^,XORPut); Repeat Repeat c:=ReadKey; Until (c='4') or (c='8') or (c='6') or (c='2') or (c='+') or (c='-') or (c=Return) or (c=Esc); moveit:=false; xold:=x; yold:=y; InterpKey(c,x,y,pointr.coffx,pointr.coffy,pointr.r,jump,moveit); if moveit then begin PutImage(xold,yold,pointr.imagepointr^,XORPut); PutImage(x,y,pointr.imagepointr^,XORPut); moveit:=false; end; Until (c=Return) or (c=Esc); PutImage(x,y,pointr.imagepointr^,XORPut); if c=Esc then exit; p:=0; minr:=trunc(sqrt(sqr(screen.lx)+sqr(screen.ly))); for i:=1 to np do {find the closest planet/black hole} begin t:=trunc(sqrt(sqr(x-pl[i].cx)+sqr(y-pl[i].cy))); if t