(*
 * -------------------------------------------------------------------------
 *
 *	:Program.	SternSimulation
 *	:Contents.	Simulation von Gravitationskräften.
 *	:Author.	Reiner Nix
 *	:Address.	Geranienhof 2, 5000 Köln 71 Seeberg
 *	:Copyright.	Public Domain
 *	:Language.	Modula-2
 *	:Translator.	M2Amiga A-L V3.3d
 *	:History.	V1.0	21.11.90
 *	:Imports.	IntuitionTools,		siehe diese Diskette
 *	:Imports.	AmigaGraphik,		siehe diese Diskette
 *	:Imports.	IntuitionTools,		siehe diese Diskette
 *
 * -------------------------------------------------------------------------
 *)
MODULE SternSimulation;

FROM	SYSTEM		IMPORT	ADR, LONGSET;
FROM	Arts		IMPORT	Assert, TermProcedure, Requester;
FROM	Exec		IMPORT	UByte, Byte,
                                Wait, GetMsg, ReplyMsg;
FROM	Layers		IMPORT	ScrollLayer;
FROM	Graphics	IMPORT  FontStyles, FontStyleSet,
				FontFlags, FontFlagSet,
				TextFontPtr, BitMapPtr,
				TextAttr;
FROM	Intuition	IMPORT	customScreen, gzzGadget, maxBody,
				IDCMPFlags, IDCMPFlagSet,
				WindowFlags, WindowFlagSet,
				GadgetFlags, GadgetFlagSet,
				PropInfoFlags, PropInfoFlagSet,
				ActivationFlags, ActivationFlagSet,
				WindowPtr, ScreenPtr, IntuiMessagePtr,
				NewScreen, NewWindow, IntuiMessage,
				AddGadget, RefreshGList,
				WindowToBack, WindowToFront,
				OpenWorkBench, CloseWorkBench;
FROM	IntuitionTools	IMPORT	GraphMode, XrelBreite, YrelHoehe,
				relBreite, relHoehe,
				initNewScreen, initNewWindow, initTextAttr,
				initPropInfo, openBitMap,
				selectGadget, deselectGadget,
				enableGadgets, disableGadgets,
				refreshOneGadget;
FROM	AmigaGraphik	IMPORT	OpenScreen, CloseScreen, UseScreen,
				OpenWindow,CloseWindow, UseWindow,
				OpenFont, CloseFont, UseFont,
				SetColourReg, SetAPen, SetBPen,
				Move, WriteString, WriteCard, WriteInt,
				WritePixel, FillRectangle;
FROM	IntuitionObjekte IMPORT ObjektTyp, BooleanTyp, ObjektEreignis,
				ObjektPtr,
				ObjektAktion, PruefeEingabe,
				setzeTextFarbe, setzeLinienFarbe,
				setzeRandFarbe, setzeEingabeFarbe,
				setzeAusrichtung, setzeGadgetTyp,
				setzeHPosition, setzeVPosition,
				erzeugeBooleanObjekt,
				erzeugeTextObjekt,
				erzeugeRealObjekt,
				erzeugeHPropObjekt, erzeugeVPropObjekt,
				findeObjekt, verbindeObjekte,
				verarbeiteNachricht,
				frageGadget, frageObjektNr, EingabeOk,
				aenderInfoSatz, erneuerObjekte,
				frageHPosition, frageVPosition,
				loescheAlleObjekte;
FROM	MathLib0	IMPORT	sqrt;

CONST	maxName		=21;
	maxKoerper	=12;
	xSchirmMax	=640;
	ySchirmMax	=256;
	superBreite	=704;
	superHoehe	=512;
	SchirmTitel	="Sternsimulation V1.0";
	EingabeTitel	="Eingabefenster";
	AusgabeTitel	="Ausgabefenster";
	keinSchirm	="Schlag mich! Konnte Schirm nicht öffnen.";
	keinFenster	="Tritt mich! Konnte Fenster nicht öffnen.";
	keineBitMap	="keine BitMap DA";

	NameID		= 1;
	PosID		= 2;
	aID		= 5;
	vID		= 8;
	MasseID		=11;
	ZeitID		=12;
	ZoomID		=13;
	FarbeID		=13;		(* Farbe+1 .. FarbeID+maxKoerper *)
	SimuID		=1000;
	LoeschenID	=1001;
	NeuID		=1004;
	KoerperID	=2004;
	AktivID		=2024;

	HochID		= 1;
	BreitID		= 2;

	g		=6.67E-11;


TYPE	TName		=ARRAY [1..maxName+2] OF CHAR;

	Vektor		=RECORD x, y, z		:REAL
				END;

	TKoerper	=RECORD Name		:TName;
				Position,
				AltPosition,
				Geschwindigkeit,
				Beschleunigung	:Vektor;
				Masse		:REAL;
				Farbe		:INTEGER;
				Aktiv		:BOOLEAN
				END;


VAR	Bildschirm		:ScreenPtr;
	EingabeFenster,
	AusgabeFenster		:WindowPtr;
	Times18, Topaz8		:TextFontPtr;
	Koerper			:ARRAY [0..maxKoerper] OF TKoerper;
	Planet			:INTEGER;
	t, Zoom, altZoom	:REAL;
	rechnenAn		:BOOLEAN;
	xAlt, yAlt		:CARDINAL;



PROCEDURE CleanUp;

BEGIN
loescheAlleObjekte (EingabeFenster);
loescheAlleObjekte (AusgabeFenster);
IF Times18 # Topaz8 THEN
  CloseFont (Times18)
  END;
CloseFont (Topaz8);
CloseWindow (AusgabeFenster);
CloseWindow (EingabeFenster);
CloseScreen (Bildschirm);
IF OpenWorkBench () # NIL THEN			(* Ergebnis unnötig *)
  END
END CleanUp;


PROCEDURE LoescheAusgabe;

BEGIN
UseWindow (AusgabeFenster);
SetAPen (14);
FillRectangle (0,0, 3000,3000)
END LoescheAusgabe;


PROCEDURE LoescheAktion		(    Ereignis		:ObjektEreignis;
				     objekt		:ObjektPtr);

BEGIN
LoescheAusgabe
END LoescheAktion;


PROCEDURE SystemAnpassen;

(* Aufgabe:	Bildschirm öffnen, Farben einstellen,
 *		EingabeFenster und AusgabeFenster öffnen
 *)

VAR	neuSchirm	:NewScreen;
	neuFenster	:NewWindow;
	BitMap		:BitMapPtr;
	Attribute	:TextAttr;

BEGIN
Bildschirm := NIL;
EingabeFenster := NIL;
AusgabeFenster := NIL;
Times18 := NIL;
Topaz8 := NIL;
TermProcedure (CleanUp);

IF CloseWorkBench () THEN			(* Ergebnis unnötig *)
  END;
initNewScreen (neuSchirm,
               0,0, xSchirmMax,ySchirmMax,
               4, 1,14, HiRes,
               customScreen,
               NIL,				(* Font *)
               ADR (SchirmTitel));
Bildschirm := OpenScreen (neuSchirm);
Assert (Bildschirm # NIL, ADR (keinSchirm));
UseScreen (Bildschirm);
SetColourReg ( 0, 0666H);
SetColourReg ( 1, 0FFFH);
SetColourReg ( 2, 0B60H);
SetColourReg ( 3, 0480H);
SetColourReg ( 4, 0FF0H);
SetColourReg ( 5, 0851H);
SetColourReg ( 6, 0988H);
SetColourReg ( 7, 000FH);
SetColourReg ( 8, 0F00H);
SetColourReg ( 9, 0F0FH);
SetColourReg (10, 0EA9H);
SetColourReg (11, 0966H);
SetColourReg (12, 0357H);
SetColourReg (13, 0868H);
SetColourReg (14, 0000H);
SetColourReg (15, 0F80H);
BitMap := openBitMap (superBreite, superHoehe, 4);
Assert (BitMap # NIL, ADR (keineBitMap));
initNewWindow (neuFenster,
               240,10, 400,246,
               14, 1,
               IDCMPFlagSet {newSize, sizeVerify},
               WindowFlagSet {windowDepth, windowSizing, windowDrag,
                              sizeBRight, sizeBBottom,
                              superBitMap, gimmeZeroZero, noCareRefresh},
               NIL, NIL,
               ADR (AusgabeTitel),
               Bildschirm,
               BitMap,
               170,50, -1,-1,
               customScreen);
AusgabeFenster := OpenWindow (neuFenster);
Assert (AusgabeFenster # NIL, ADR (keinFenster));
initNewWindow (neuFenster,
               0,10, 640,246,
               14, 1,
               IDCMPFlagSet {closeWindow},
               WindowFlagSet {windowDepth, windowClose, noCareRefresh},
               NIL,				(* kein Gadget *)
               NIL,				(* keine CheckMark *)
               ADR (EingabeTitel),
               Bildschirm,
               NIL,
               0,0, 0,0,			(* min, max *)
               customScreen);
EingabeFenster := OpenWindow (neuFenster);
Assert (EingabeFenster # NIL, ADR (keinFenster));
LoescheAusgabe;
initTextAttr (Attribute,
              ADR ("topaz.font"), 8, FontStyleSet {}, FontFlagSet {});
Topaz8 := OpenFont (Attribute);
initTextAttr (Attribute,
              ADR ("times.font"), 18, FontStyleSet {}, FontFlagSet {});
Times18 := OpenFont (Attribute);
IF Times18 = NIL THEN
  Assert (Requester ( ADR (SchirmTitel),
                      ADR ("Zeichensatz Times.18 nicht gefunden"),
                      ADR ("nimm Topaz.8"), ADR ("Programm abbrechen")),
           ADR ("Programmstop!"));
  Times18 := Topaz8
  END
END SystemAnpassen;


PROCEDURE WerteEinstellen;

VAR	i		:CARDINAL;


BEGIN
WITH Koerper[1] DO
  Name			:= "Sonne               ";
  Position.x		:= 0.0;
  Position.y		:= 0.0;
  Position.z		:= 0.0;
  Geschwindigkeit	:= Position;
  Beschleunigung	:= Position;
  Masse			:= 1.985E30;
  Farbe			:= 4;
  END;
FOR i := 2 TO maxKoerper DO
  Koerper[i]		:= Koerper[1];
  Koerper[i].Farbe	:= i+3
  END;
WITH Koerper[2] DO
  Name			:= "Merkur              ";
  Position.y		:= 5.79E10;
  Geschwindigkeit.x	:= 4.79E4;
  Masse			:= 3.169E23
  END;
WITH Koerper[3] DO
  Name			:= "Venus               ";
  Position.y		:= 1.08E11;
  Geschwindigkeit.x	:= 3.50E4;
  Masse			:= 4.873E24
  END;
WITH Koerper[4] DO
  Name			:= "Erde                ";
  Position.y		:= 1.496E11;
  Geschwindigkeit.x	:= 2.978E4;
  Masse			:= 5.979E24
  END;
WITH Koerper[5] DO
  Name			:= "Mars                ";
  Position.y		:= 2.279E11;
  Geschwindigkeit.x	:= 2.41E4;
  Masse			:= 6.398E23
  END;
WITH Koerper[6] DO
  Name			:= "Jupiter  (Jupp)     ";
  Position.y		:= 7.78E11;
  Geschwindigkeit.x	:= 1.31E4;
  Masse			:= 1.901E27
  END;
WITH Koerper[7] DO
  Name			:= "Saturn              ";
  Position.y		:= 1.427E12;
  Geschwindigkeit.x	:= 9.6E3;
  Masse			:= 5.693E26
  END;
WITH Koerper[8] DO
  Name			:= "Uranus              ";
  Position.y		:= 2.870E12;
  Geschwindigkeit.x	:= 6.8E3;
  Masse			:= 8.699E25
  END;
WITH Koerper[9] DO
  Name			:= "Neptun              ";
  Position.y		:= 4.496E12;
  Geschwindigkeit.x	:= 5.4E3;
  Masse			:= 1.030E26;
  END;
WITH Koerper[10] DO
  Name			:= "Pluto               ";
  Position.y		:= 5.946E12;
  Geschwindigkeit.x	:= 4.7E3;
  Masse			:= 2.319E22
  END;
FOR i := 11 TO maxKoerper DO
  WITH Koerper[i] DO
    Name := "                    ";
    Masse := 0.0
    END
  END;
FOR i := 1 TO maxKoerper DO
  WITH Koerper[i] DO
    AltPosition := Position;
    Aktiv := (Masse # 0.0)
    END
  END;
Planet 		:= 4;
Koerper[0]	:= Koerper[Planet];
t		:= 86400.0;
Zoom		:= 2.0E9;
altZoom		:= Zoom
END WerteEinstellen;


PROCEDURE StartStopAktion	(    Ereignis		:ObjektEreignis;
				     objekt		:ObjektPtr);

BEGIN
rechnenAn := NOT rechnenAn;
IF rechnenAn THEN
  Koerper[0].Aktiv := Koerper[Planet].Aktiv;
  Koerper[Planet] := Koerper[0];
  aenderInfoSatz (findeObjekt (EingabeFenster, Planet+KoerperID),
  		  Koerper[Planet].Name);
  objekt := findeObjekt (EingabeFenster, SimuID);
  aenderInfoSatz (objekt , "    Halt an!    ");
  selectGadget (EingabeFenster, frageGadget (objekt));
  objekt := findeObjekt (AusgabeFenster, SimuID);
  aenderInfoSatz (objekt , "    Halt an!    ");
  selectGadget (AusgabeFenster, frageGadget (objekt));
  disableGadgets (EingabeFenster,
                  LONGSET {NameID..MasseID, FarbeID+1..FarbeID+maxKoerper});
  WindowToFront (AusgabeFenster);
ELSE
  objekt := findeObjekt (EingabeFenster, SimuID);
  aenderInfoSatz (objekt , "  Mach weiter!  ");
  deselectGadget (EingabeFenster, frageGadget (objekt));
  objekt := findeObjekt (AusgabeFenster, SimuID);
  aenderInfoSatz (objekt , "  Mach weiter!  ");
  deselectGadget (AusgabeFenster, frageGadget (objekt));
  enableGadgets (EingabeFenster,
                 LONGSET {NameID..MasseID, FarbeID+1..FarbeID+maxKoerper});
  Koerper[0] := Koerper[Planet];
  erneuerObjekte (EingabeFenster, LONGSET {NameID..MasseID});
  WindowToFront (EingabeFenster);
  END
END StartStopAktion;


PROCEDURE KoerperAktion		(    Ereignis		:ObjektEreignis;
				     objekt		:ObjektPtr);

VAR	alt		:ObjektPtr;
	neuPlanet	:INTEGER;


BEGIN
IF frageObjektNr (objekt) # Planet+KoerperID THEN
  alt := findeObjekt (EingabeFenster, Planet+KoerperID);
  deselectGadget (EingabeFenster,
                  frageGadget (alt));
  selectGadget (EingabeFenster, frageGadget (objekt));
  IF NOT (rechnenAn) THEN
    Koerper[0].Aktiv := Koerper[Planet].Aktiv;
    Koerper[Planet] := Koerper[0]
    END;
  aenderInfoSatz (alt, Koerper[Planet].Name)
  END;

neuPlanet := frageObjektNr (objekt)-KoerperID;
IF Koerper[Planet].Farbe # Koerper[neuPlanet].Farbe THEN
  aenderInfoSatz ( findeObjekt (EingabeFenster,
                                Koerper[Planet].Farbe-3+FarbeID), "   ");
  aenderInfoSatz ( findeObjekt (EingabeFenster,
  			        Koerper[neuPlanet].Farbe-3+FarbeID), " * ")
  END;
IF (Planet = neuPlanet) AND (Koerper[Planet].Masse = 0.0)
   AND Koerper[Planet].Aktiv THEN
  Koerper[Planet].Aktiv := FALSE;
  aenderInfoSatz ( findeObjekt (EingabeFenster, Planet+AktivID), "   ")
  END;
Planet := neuPlanet;
Koerper[0] := Koerper[Planet];
erneuerObjekte (EingabeFenster, LONGSET {NameID..MasseID})
END KoerperAktion;


PROCEDURE UrAktion		(    Ereignis		:ObjektEreignis;
				     objekt		:ObjektPtr);

VAR	i		:INTEGER;
	Text		:ARRAY [1..maxName+2] OF CHAR;

BEGIN
aenderInfoSatz ( findeObjekt (EingabeFenster,
                              Koerper[Planet].Farbe-3+FarbeID), "   ");
deselectGadget (EingabeFenster,
                frageGadget (findeObjekt (EingabeFenster, Planet+KoerperID)));
WerteEinstellen;
aenderInfoSatz ( findeObjekt (EingabeFenster,
                              Koerper[Planet].Farbe-3+FarbeID), " * ");
selectGadget (EingabeFenster,
              frageGadget (findeObjekt (EingabeFenster, Planet+KoerperID)));
erneuerObjekte (EingabeFenster, LONGSET {NameID..ZoomID});
FOR i := 1 TO maxKoerper DO
  aenderInfoSatz (findeObjekt (EingabeFenster, i+KoerperID), Koerper[i].Name);
  IF Koerper[i].Aktiv THEN
    aenderInfoSatz ( findeObjekt (EingabeFenster, AktivID+i), " * ")
  ELSE
    aenderInfoSatz ( findeObjekt (EingabeFenster, AktivID+i), "   ")
    END
  END;
LoescheAusgabe
END UrAktion;


PROCEDURE AktivAktion		(    Ereignis		:ObjektEreignis;
				     objekt		:ObjektPtr);

VAR	i	:INTEGER;

BEGIN
i := frageObjektNr (objekt) - AktivID;
IF Koerper[i].Aktiv THEN
  Koerper[i].Aktiv := FALSE;
  aenderInfoSatz (objekt, "   ")
ELSIF ((Planet = i) AND (Koerper[0].Masse # 0.0)) OR
      ((Planet # i) AND (Koerper[i].Masse # 0.0)) THEN
  Koerper[i].Aktiv := TRUE;
  aenderInfoSatz (objekt, " * ")
  END
END AktivAktion;


PROCEDURE FarbAktion		(    Ereignis		:ObjektEreignis;
				     objekt		:ObjektPtr);

BEGIN
WITH Koerper[0] DO
  IF Farbe # (frageObjektNr (objekt)+3 - FarbeID) THEN
    aenderInfoSatz (findeObjekt (EingabeFenster, Farbe-3 + FarbeID), "   ");
    Koerper[0].Farbe := frageObjektNr (objekt)+3 - FarbeID;
    aenderInfoSatz (objekt, " * ")
    END
  END
END FarbAktion;


PROCEDURE pruefeMasse		(    objekt		:ObjektPtr) :BOOLEAN;

BEGIN
WITH Koerper[0] DO
  IF (Masse = 0.0) AND Koerper[Planet].Aktiv THEN
    Koerper[Planet].Aktiv := FALSE;
    aenderInfoSatz (findeObjekt (EingabeFenster, Planet+AktivID), "   ")
    END;
  RETURN Masse >= 0.0
  END
END pruefeMasse;


PROCEDURE pruefeZeit		(    objekt             :ObjektPtr) :BOOLEAN;

BEGIN
RETURN (t > 0.0)
END pruefeZeit;


PROCEDURE pruefeZoom		(    objekt		:ObjektPtr) :BOOLEAN;

BEGIN
IF (Zoom # altZoom) AND (Zoom > 0.0) THEN
  LoescheAusgabe;
  altZoom := Zoom
  END;
RETURN (Zoom > 0.0)
END pruefeZoom;


PROCEDURE HochAktion		(    Ereignis		:ObjektEreignis;
				     objekt		:ObjektPtr);

VAR	y	:CARDINAL;

BEGIN
y := CARDINAL ((LONGCARD (frageVPosition (objekt)) *
                LONGCARD (superHoehe - AusgabeFenster^.gzzHeight)) DIV
                 maxBody);
IF y # yAlt THEN
  ScrollLayer (AusgabeFenster^.wLayer, 0, LONGINT (y)-LONGINT (yAlt));
  yAlt := y
  END
END HochAktion;


PROCEDURE BreitAktion		(    Ereignis		:ObjektEreignis;
				     objekt		:ObjektPtr);

VAR	x	:CARDINAL;

BEGIN
x := CARDINAL ((LONGCARD (frageHPosition (objekt)) *
                LONGCARD (superBreite-AusgabeFenster^.gzzWidth)) DIV
                 maxBody);
IF x # xAlt THEN
  ScrollLayer (AusgabeFenster^.wLayer, LONGINT (x)-LONGINT (xAlt), 0);
  xAlt := x
  END
END BreitAktion;


PROCEDURE EingabeErzeugen;

VAR	i			:INTEGER;
	Text			:ARRAY [1..maxName+1] OF CHAR;
	objekt			:ObjektPtr;

BEGIN
UseWindow (EingabeFenster);
UseFont (Times18);
SetAPen (1);
Move ( 25,35); WriteString ("Himmelskörper");
Move (185,35); WriteString ("Aktiv");

setzeLinienFarbe  (15,-1);
setzeRandFarbe (14, -1);
FOR i := 1 TO maxKoerper DO
  setzeTextFarbe ( 1,  0);
  erzeugeBooleanObjekt (EingabeFenster,  23,30+i*10, Koerper[i].Name,
  			i+KoerperID, melden, KoerperAktion);
  IF i = Planet THEN
    selectGadget (EingabeFenster,
                  frageGadget (findeObjekt (EingabeFenster, Planet+KoerperID)))
    END;
  setzeTextFarbe ( 1, 8);
  IF Koerper[i].Masse # 0.0 THEN
    Koerper[i].Aktiv := TRUE;
    erzeugeBooleanObjekt (EingabeFenster, 196,30+i*10, " * ", i+AktivID,
                          melden, AktivAktion)
  ELSE
    erzeugeBooleanObjekt (EingabeFenster, 196,30+i*10, "   ", i+AktivID,
                          melden, AktivAktion)
    END
  END;

setzeTextFarbe ( 1, 0);
erzeugeRealObjekt (EingabeFenster, 143,170, "Zeitdifferenz:", ZeitID, -120,0,
                   10,3, TRUE, pruefeZeit ,t);
erzeugeRealObjekt (EingabeFenster, 143,185, "Zoomfaktor:   ", ZoomID, -120,0,
                   10,3, TRUE, pruefeZoom, Zoom);
erzeugeBooleanObjekt (EingabeFenster, 50,205, "   Urzustand    ", NeuID,
                      melden, UrAktion);
erzeugeBooleanObjekt (EingabeFenster, 50,215, " lösche Ausgabe ", LoeschenID,
                      melden, LoescheAktion);
erzeugeBooleanObjekt (EingabeFenster, 50,225, "    Fang an!    ", SimuID,
                      melden, StartStopAktion);

erzeugeRealObjekt (EingabeFenster, 490,170, "Masse:", MasseID, -184,0,
                   15,5, TRUE, pruefeMasse, Koerper[0].Masse);

erzeugeRealObjekt (EingabeFenster, 490,152, "                 z:", vID+2,-184,0,
                   15,5, TRUE, EingabeOk, Koerper[0].Geschwindigkeit.z);
erzeugeRealObjekt (EingabeFenster, 490,141, "                 y:", vID+1,-184,0,
                   15,5, TRUE, EingabeOk, Koerper[0].Geschwindigkeit.y);
erzeugeRealObjekt (EingabeFenster, 490,130, "Geschwindigkeit  x:", vID  ,-184,0,
                   15,5, TRUE, EingabeOk, Koerper[0].Geschwindigkeit.x);

erzeugeRealObjekt (EingabeFenster, 490,112, "                 z:", aID+2,-184,0,
                   15,5, TRUE, EingabeOk, Koerper[0].Beschleunigung.z);
erzeugeRealObjekt (EingabeFenster, 490,101, "                 y:", aID+1,-184,0,
                   15,5, TRUE, EingabeOk, Koerper[0].Beschleunigung.y);
erzeugeRealObjekt (EingabeFenster, 490, 90, "Beschleunigung   x:", aID  ,-184,0,
                   15,5, TRUE, EingabeOk, Koerper[0].Beschleunigung.x);

erzeugeRealObjekt (EingabeFenster, 490, 72, "                 z:",PosID+2,-184,0,
                   15,5, TRUE, EingabeOk, Koerper[0].Position.z);
erzeugeRealObjekt (EingabeFenster, 490, 61, "                 y:",PosID+1,-184,0,
                   15,5, TRUE, EingabeOk, Koerper[0].Position.y);
erzeugeRealObjekt (EingabeFenster, 490, 50, "Position         x:",PosID  ,-184,0,
                   15,5, TRUE, EingabeOk, Koerper[0].Position.x);

erzeugeTextObjekt (EingabeFenster, 370, 30, "Name:", NameID, -64,0,
                   maxName, maxName, EingabeOk, Koerper[0].Name);

Move (306, 220); UseFont (Topaz8);
WriteString ("Farbe:");
FOR i := 1 TO maxKoerper DO
  setzeTextFarbe (i+3, 1);
  setzeRandFarbe (14, -1);
  IF Koerper[0].Farbe = i+3 THEN
    erzeugeBooleanObjekt (EingabeFenster, 306+(i-1)*26,225, " * ",FarbeID+i,
                          melden, FarbAktion)
  ELSE
    erzeugeBooleanObjekt (EingabeFenster, 306+(i-1)*26,225, "   ",FarbeID+i,
                          melden, FarbAktion)
    END
  END;
setzeTextFarbe (1, 0);
verbindeObjekte (EingabeFenster, NameID,  -1,      PosID,   -1, -1);
verbindeObjekte (EingabeFenster, PosID,   NameID,  PosID+1, -1, -1);
verbindeObjekte (EingabeFenster, PosID+1, PosID,   PosID+2, -1, -1);
verbindeObjekte (EingabeFenster, PosID+2, PosID+1, aID,     -1, -1);
verbindeObjekte (EingabeFenster, aID,     PosID+2, aID+1,   -1, -1);
verbindeObjekte (EingabeFenster, aID+1,   aID,     aID+2,   -1, -1);
verbindeObjekte (EingabeFenster, aID+2,   aID+1,   vID,     -1, -1);
verbindeObjekte (EingabeFenster, vID,     aID+2,   vID+1,   -1, -1);
verbindeObjekte (EingabeFenster, vID+1,   vID,     vID+2,   -1, -1);
verbindeObjekte (EingabeFenster, vID+2,   vID+1,   MasseID, -1, -1);
verbindeObjekte (EingabeFenster, MasseID, vID+2,   -1,      -1, -1);
verbindeObjekte (EingabeFenster, ZeitID,  -1,      ZoomID,  -1, -1);
verbindeObjekte (EingabeFenster, ZoomID,  ZeitID,  -1,      -1, -1);
rechnenAn := FALSE;

setzeGadgetTyp (gzzGadget);
setzeAusrichtung ( GadgetFlagSet {YrelHoehe});
erzeugeBooleanObjekt (AusgabeFenster, 4,-8, "    Fang an!    ", SimuID,
                      melden, StartStopAktion);
setzeAusrichtung ( GadgetFlagSet {YrelHoehe, relBreite});
erzeugeHPropObjekt (AusgabeFenster, 134,-8, -153, 8,
                    maxBody DIV 2,
                    CARDINAL (maxBody * LONGCARD (AusgabeFenster^.gzzWidth) DIV
                     superBreite),
                    BreitID, wiederholen, BreitAktion);
setzeAusrichtung ( GadgetFlagSet {XrelBreite, relHoehe});
erzeugeVPropObjekt (AusgabeFenster, -16,11, 16,-21,
                    maxBody DIV 2,
                    CARDINAL (maxBody * LONGCARD (AusgabeFenster^.gzzHeight) DIV
                     superHoehe),
                    HochID, wiederholen, HochAktion);
setzeAusrichtung ( GadgetFlagSet {});
setzeGadgetTyp (0);
xAlt := (superBreite-AusgabeFenster^.gzzWidth) DIV 2;
yAlt := (superHoehe-AusgabeFenster^.gzzHeight) DIV 2;
ScrollLayer (AusgabeFenster^.wLayer, xAlt, yAlt);
END EingabeErzeugen;


(*----------------------------------------------------------------------------*)
   PROCEDURE Zeichnen;
(*----------------------------------------------------------------------------*)
VAR	i	:INTEGER;
	a,b	:REAL;
BEGIN
 FOR i := 1 TO maxKoerper DO
  WITH Koerper[i] DO
   IF Aktiv
    THEN (*-- Zeichnen -------------------------------------------------------*)
     	 a := (AltPosition.x / Zoom) * 2.0 + REAL (superBreite DIV 2);
	 b := AltPosition.y / Zoom + REAL (superHoehe DIV 2);
	 IF (a>0.0) AND (a<REAL(superBreite)) AND
	    (b>0.0) AND (b<REAL(superHoehe))
	  THEN SetAPen (Farbe);
	       WritePixel (INTEGER (a), INTEGER (b))
	 END; (* IF *)
	 a := (Position.x / Zoom) * 2.0 + REAL (superBreite DIV 2);
	 b := Position.y / Zoom + REAL (superHoehe DIV 2);
	 IF (a>0.0) AND (a<REAL(superBreite)) AND
	    (b>0.0) AND (b<REAL(superHoehe))
	  THEN SetAPen (8);
	       WritePixel (INTEGER (a), INTEGER (b))
	 END; (* IF *)
	 AltPosition := Position
   END (* IF *)
  END (* WITH Koerper[i] *)
 END (* FOR i *)
END Zeichnen;


(*----------------------------------------------------------------------------*)
   PROCEDURE Berechnung;
(*----------------------------------------------------------------------------*)
VAR	Dx, Dy, Dz, D, D2, A	:REAL;
	K1, K2 			:INTEGER;
	Kollision		:BOOLEAN;
	Text			:ARRAY [1..maxName+2] OF CHAR;
BEGIN
 UseWindow (AusgabeFenster);
 Kollision := FALSE;
 K1 := 1;
 WHILE K1 <= maxKoerper DO
  IF Koerper[K1].Aktiv
   THEN WITH Koerper[K1] DO

        (*-- Beschleunigung berechnen ----------------------------------------*)

         WITH Beschleunigung DO
          x := 0.0;
 	  y := 0.0;
 	  z := 0.0;
	 END; (* WITH *)

         K2 := 1;
         WHILE K2 <= maxKoerper DO
          IF (Koerper[K2].Aktiv) AND (K2 # K1)
           THEN Dx := Koerper [K2].AltPosition.x - AltPosition.x;
                Dy := Koerper [K2].AltPosition.y - AltPosition.y;
                Dz := Koerper [K2].AltPosition.z - AltPosition.z;
        	D2 := ABS (Dx*Dx + Dy*Dy + Dz*Dz);
        	D  := sqrt (D2);
		IF D < 1.0
		 THEN Name := "Gesteinsbrocken";
		      Masse := Masse + Koerper[K2].Masse;
		      Geschwindigkeit.x := Geschwindigkeit.x +
		      			   Koerper[K2].Geschwindigkeit.x;
		      Geschwindigkeit.y := Geschwindigkeit.y +
		      			   Koerper[K2].Geschwindigkeit.y;
		      Geschwindigkeit.z := Geschwindigkeit.z +
		      			   Koerper[K2].Geschwindigkeit.z;
		      aenderInfoSatz ( findeObjekt (EingabeFenster,
		                       KoerperID+K1), Name);
		      Koerper[K2].Name	:= '';
		      Koerper[K2].Masse := 0.0;
		      Koerper[K2].Aktiv := FALSE;
		      aenderInfoSatz ( findeObjekt (EingabeFenster,
		                      KoerperID + K2), Koerper[K2].Name);
		      aenderInfoSatz ( findeObjekt (EingabeFenster,
		      		      AktivID + K2) , "   ");
		      IF (Planet = K1) OR (Planet = K2)
		       THEN Koerper[0] := Koerper[Planet];
			    erneuerObjekte (EingabeFenster,
			                    LONGSET {NameID..MasseID})
		      END; (* IF *)
		      Kollision := TRUE;
		      K1 	:= maxKoerper;
		      K2	:= maxKoerper
		 ELSE A := g * Koerper[K2].Masse / (D2 * D);
        	      WITH Beschleunigung DO
        	       x := x + A * Dx;
        	       y := y + A * Dy;
        	       z := z + A * Dz
        	      END (* WITH *)
		END (* IF *)
          END; (* IF *)
          INC (K2)
         END; (* WHILE *)

        (*-- Geschwindigkeit berechnen --------------------------------------*)

         WITH Geschwindigkeit DO
          x := x + Beschleunigung.x * t;
          y := y + Beschleunigung.y * t;
          z := z + Beschleunigung.z * t
         END; (* WITH Geschwindigkeit *)

        (*-- Position berechnen ---------------------------------------------*)

         WITH Position DO
          x := AltPosition.x  + Geschwindigkeit.x * t;
          y := AltPosition.y  + Geschwindigkeit.y * t;
          z := AltPosition.z  + Geschwindigkeit.z * t;
	 END (* WITH Position *)

	END (* WITH Koerper[K1] *)
  END; (* IF *)
  INC (K1)
 END; (* WHILE K1 *)

 IF NOT Kollision
  THEN Zeichnen
 END (* IF *)
END Berechnung;


PROCEDURE sieheEreignisse;

VAR 	Ende, vergroessernAn	:BOOLEAN;
	Signal			:LONGSET;
	NachrichtPtr		:IntuiMessagePtr;
	Nachricht		:IntuiMessage;


PROCEDURE bearbeiteNachricht (    Fenster	:WindowPtr;
                              VAR Nachricht	:IntuiMessage);

VAR	objekt		:ObjektPtr;

BEGIN
verarbeiteNachricht (Fenster, Nachricht);
WITH Nachricht DO
  IF    sizeVerify IN class THEN
    vergroessernAn := TRUE
  ELSIF newSize IN class THEN
    vergroessernAn := FALSE;
    objekt := findeObjekt (AusgabeFenster, BreitID);
    setzeHPosition (objekt, frageHPosition (objekt),
                    CARDINAL (maxBody * LONGCARD (AusgabeFenster^.gzzWidth) DIV
                     superBreite));
    objekt := findeObjekt (AusgabeFenster, HochID);
    setzeVPosition (objekt, frageVPosition (objekt),
                    CARDINAL (maxBody * LONGCARD (AusgabeFenster^.gzzHeight) DIV
                     superHoehe));
    HochAktion (Start, findeObjekt (AusgabeFenster, HochID));
    BreitAktion (Start, findeObjekt (AusgabeFenster, BreitID))
  ELSIF closeWindow IN class THEN
    Ende := TRUE
  ELSE
    END
  END
END bearbeiteNachricht;


(* sieheEreignisse *)
BEGIN
UseWindow (AusgabeFenster);
Ende := FALSE;
vergroessernAn := FALSE;
WHILE NOT Ende DO
  IF rechnenAn THEN
    IF NOT vergroessernAn THEN
      Berechnung
      END
  ELSE
    Signal := Wait (LONGSET {EingabeFenster^.userPort^.sigBit,
                             AusgabeFenster^.userPort^.sigBit})
    END;
    REPEAT
    NachrichtPtr := GetMsg (EingabeFenster^.userPort);
    IF NachrichtPtr # NIL THEN
      Nachricht := NachrichtPtr^;
      ReplyMsg (NachrichtPtr);
      bearbeiteNachricht (EingabeFenster, Nachricht)
      END
    UNTIL NachrichtPtr = NIL;
    REPEAT
    NachrichtPtr := GetMsg (AusgabeFenster^.userPort);
    IF NachrichtPtr # NIL THEN
      Nachricht := NachrichtPtr^;
      ReplyMsg (NachrichtPtr);
      bearbeiteNachricht (AusgabeFenster, Nachricht)
      END
    UNTIL NachrichtPtr = NIL
  END
END sieheEreignisse;


(* HP *)
BEGIN
SystemAnpassen;
WerteEinstellen;
EingabeErzeugen;
sieheEreignisse
END SternSimulation.
