← ST-Magazin 03 / 1990

Tips & Tricks für Programmierer

ST-Expertenforum

Ein tapferer Krieger

Alle, die sich mit Krieg der Kerne (siehe auch [1]) beschäftigen, sollten einmal unser Programm »Cat Can« (Listing 2) ausprobieren. Denn trotz seines einfachen Prinzips ist es fast nicht zu besiegen. Cat Can stoppt gegnerische Programme, indem es deren Rechenzeit für sinnlose Aktionen verschwendet. Split-Befehle reduzieren die Rechenzeit der noch intakten gegnerischen Programme drastisch und legen sie im Idealfall völlig lahm. Sobald der Feind auf diese Weise gestoppt ist, zerstört Cat Can die letzten Gegner mit Datenbomben.

Beachten Sie beim Austesten, daß die Größe des Speicherrings durch acht teilbar sein muß. Wir verwendeten beispielsweise 2048 Speicherzellen. An dieser Stelle sei auch auf einen Fehler in dem Programm »Corewars« hingewiesen: Der letzte »JMN«-Befehl dient dazu, Cat Can sich nicht selbst umbringen zu lassen. Da jedoch Corewars die indirekte Adressierung mit pre-dekrement falsch bearbeitet, funktioniert diese Methode nicht. Denn sobald ein Überlauf stattfindet, setzt Corewars die Adresse nicht auf Null zurück, sondern erniedrigt sie weiter. Derselbe Fehler findet sich auch bei der »DJN«-Anweisung. Damit ist Cat Can unter »Corewars« nur bedingt lauffähig. Mit »Krieg der Kerne« funktioniert es dagegen problemlos.

(Alexander Kirchner/ba)

[1] »Duell im Computer«, ST-Magazin 1/90, Seite 58 f.

Pop-Up-Menüs in GFA-Basic

Die Menüleiste des GEM ist sehr komfortabel. Denn statt die Befehle mühselig einzutippen oder über schwer nachzuvollziehbare Tastaturkürzel aufzurufen, fahren Sie einfach mit der Maus in die Menüleiste und wählen den gewünschten Menüpunkt aus. Diese Art Menüs heißt Pull-Down-Menüs (zu deutsch etwa »Klappmenüs«). Eine weitere, noch komfortablere Art stellt das Pop-Up-Menü dar. Dieses erscheint auf Mausknopfdruck auf dem Bildschirm nahe beim Cursor. Der Vorteil liegt auf der Hand: Das lästige Anfahren des Menüs entfällt, da das Pop-Up-Menü beim Mauscursor erscheint. Leider unterstützt das AES keine Pop-Up-Menüs. Dazu bedarf es einer kleinen Routine, die Sie in Listing 1 Finden. Wir haben sie der besseren Verständlichkeit wegen in GFA-Basic 3.0 formuliert.

In den Programmzeilen 1 bis 9 demonstrieren wir den Aufruf der Pop-Up-Prozedur »menu«, die Sie ab Zeile 12 finden, »menu« benötigt vier Parameter: Einen Zeiger auf die Rückgabevariable (*num), in der »menu« am Ende die Nummer des ausgewählten Menüpunkts bzw. den Wert -1 (kein ausgewählter Menüpunkt) speichert. Als zweiten Parameter benötigt »menu« ein Stringarray, in dem die Menüpunkte bezeichnet sind (siehe Programmzeilen drei bis acht). Die letzten beiden Parameter geben die X- und Y-Koordinate der linken oberen Ecke des Pop-Up-Menüs an. Es liegt also an Ihnen, wo das Menü erscheint. Sinnvoll sind z. B. die X- und Y-Koordinate der Maus als Bezugspunkt. (Christoph Falk/ba)

.n4 DIM a$(100) a$(1)="Menu" a$(2)="Menu" a$(3)="Menu" a$(4)="Menu" a$(5)=MMenu" a$(6)="Menu" menu(*num,*a$(),10,50) ' ' PROCEDURE menu(nura,lp,x,y) LOCAL lang,a,b,n,ly,lx.bild$ DIM menu$(100) SWAP *lp,menu$() n=1 REPEAT INC n UNTIL menu$(n)="" DEC n GRAPHMODE 1 b=-1 lang=0 ly=n*16 FOR i=1 TO n IF LEN(menu$(i))>lang THEN lang=LEN(menuS(i)) ENDIF NEXT i lx=(lang+2)*8 IF (x+lx)<635 AND (y+ly)<395 and x>5 AND y>5 fy=INT(ly/n) DEFFILL 0,1,1 GET x-4.y-9,x+lx+3,y+ly+4,bild$ PBOX x-4,y-9,x+lx+3,y+ly+2 BOX x-4,y-5,x+lx+3,y+y+2 BOX x-1,y-2,x+lx,y+ly-1 PBOX x-4,y-9,x+lx+3,y-2 BOX x-4,y-9,x+lx+3,y-2 BOX x-2,y-6,x+lx+2,y-5 FOR s=1 TO n TEXT x+6,y+s*16-4,menu$(s) NEXT s ' GRAPHMODE 3 DEFFILL 1,1,1 REPEAT IF FN in(x,y+9,lx,ly-l4)=1 yk=MOUSEY a=INT((yk-y)/fy)*fy IF b<>a IF b>=0 AND b<n*16 DEFFILL 0,1,1 PBOX x-3,b+y-1,x+lx+2,y+b+16 ENDIF DEFFILL 1,1,1 PBOX x-3,a+y-1,x+lx+2,y+a+l6 b=a ENDIF ENDIF UNTIL MOUSEK=1 IF FN in(x,y,lx,ly)=l *num=a/l6+1 ELSE *num=-1 ENDIF ' PUT x-4,y-9,bild$ ELSE *num=-1 ENDIF SWAP *lp,menu$() ERASE menu$() DEFFN in{x,y,lx,ly)=ABS(MOUSEX>x AND MOUSEY>y AND MOUSEX<(x+lx) AND MOUSEY<(y+ly)) RETURN ' ' Pop-Up Menü ' ' Geschrieben von FALK CHRISTOPH ' ' 15.11.1989 '

Listing 1. Stellen auch Sie komfortable Pop-Up-Menüs unter GFA-Basic 3.0 dar

Joystickabfrage in C

Turbo-C ist sicherlich eine der mächtigsten Programmiersprachen für den ST. Die Bibliotheken sind schnell und lassen im Funktionsumfang fast keine Wünsche mehr offen. Besonders die Spieleprogrammierer vermissen aber eine Routine zur unkomplizierten Joystickabfrage. Mittlerweile gibt es zwar eine Vielzahl von Vorschlägen zur Abfrage des Joysticks, aber entweder sind diese Routinen zu lang oder zu unhandlich. Um diesen Mißstand zu beseitigen, stellen wir eine kurze, universelle Joystickabfrage in Turbo-C und Assembler vor.

Der Kern, die Assembler-Routine (Listing 4), speichern Sie unter dem Namen JOYSTICK.S. Die Headerdatei (Listing 2) sollten Sie JOYSTICK.H benennen. Das C-Programm im Listing 3 demonstriert den Einsatz der Joystickroutinen. In Listing 4 finden Sie eine vorgefertigte Projektdatei, die ein ablauffertiges Programm erzeugt.

Beachten Sie, daß wir darin das Assembler-Programm mit ».S« aufgenommen haben. Damit geben wir Turbo-C an, JOYSTICK.S mit dem MAS.TTP zu assemblieren. Besitzer eines anderen Assemblers sollten die Assembler-Routine separat assemblieren und eine DRI-Objektdatei erzeugen. Um diese in die Projektdatei einzubinden, ersetzen Sie einfach das ».S« durch ».O«.

Die Joystick-Abfrage schalten Sie mit »j_on()« ein. Von nun an werden Sie von den beiden globalen Variablen »joyst1« und »joyst2« über den Status der Joysticks in Port 1 und 2 informiert. Jede Bewegung verändert den Wert der Variablen. Ein erneuter Aufruf von »j_on()« ist nicht nötig. Um die Joystick-Abfrage wieder abzuschalten, rufen Sie »j_off()« auf.

Die Werte, die die Variablen »joyst1« und »joyst2« annehmen können, finden Sie in der Textbox.

(Ulrich Eckartz/ba)

Listings 1-4

Diese Werte nehmen die beiden Variablen »joyst1« und »joyst2« an. Kombinationen sind möglich:

oben
5 1 9
links 4 0 8 rechts
6 2 10
unten
Fire + 128

Bildverwaltung in ST-Basic

Bilder sagen oft mehr als tausend Worte. Und Programme, die sich der Bildersprache bedienen, sind doppelt so attraktiv. Doch dabei stellt sich vielen Programmierern ein Problem in den Weg: Wie erzeugt, lädt, verwaltet und zeigt man Bilder? In Listing 3 finden Sie drei Prozeduren für Omikron-Basic, die Ihnen diese Last abnehmen.

Die Prozedur »Bild_Speichern« (Programmzeile 49 ff.) erlaubt Ihnen, einen beliebigen Bildschirmausschnitt zu speichern. Dazu übergeben Sie fünf Parameter: den Bildnamen, die X- und die Y-Koordinate des linken oberen Ecks sowie die Breite und Höhe des Ausschnitts. Um den kompletten Bildschirm im monochromen Modus zu speichern, geben Sie beispielsweise die Parameter »"HIRES ",0,0,640,400« an. In diesem Beispiel sind die beiden Koordinaten x und y Null, die Breite des Ausschnitts beträgt 640 und die Höhe 400 Pixel.

Um ein Bild zu laden, rufen Sie die Prozedur »Bild_Laden« auf, die Sie ab Programmzeile 57 finden. Sie verlangt zwei Parameter: den Bildnamen und die Bildnummer. Die Bildnummer ist eine Art ID, mit dessen Hilfe Sie später erneut auf das Bild zurückgreifen können.

Ein geladenes Bild zeigen Sie mit der letzten Prozedur »Bild_Zeigen« an. Hierzu übergeben Sie die X- und Y-Koordinate der oberen linken Ecke, den Zeichenmodus (siehe Handbuch) und die Bildnummer. Er eignet sich besonders gut, da er aus einem Bildschirmausschnitt einen zusammenhängenden Block mit einem Header (Breite und Höhe) macht.

Die Prozeduren bedienen sich des »BITBLT«-Befehls, um Bildausschnitte für das Speichern vorzubereiten und darzustellen.

Mit den Befehlen »BSAVE« und »BLOAD« speichern und laden die Prozeduren den BITBLT-Block. Ein Anwendungsbeispiel der drei Prozeduren finden Sie in den Zeilen 0 bis 43.

(Peter Kraiczy/ba)

; CAT CAN ; ; Written by A. Kirchner with help from J. Tenzer ; and W. Rohmann ; start MOV grab, @dest MOV prog, <dest SUB #7, dest JMN start, dest SUB #4, dest kill MOV dest, <dest JMN kill, dest prog SPL 0 grab JMP -1 deat DAT -16

Listing 2. Ein fast unbesiegbares Kampfprogramm nach den Regeln von »Krieg der Kerne

0 PRINT CHR$(27)+"f" 1 CLIP 0,0,639,399 2 REPEAT 3 MODE = 1 4 CLS 5 FOR A= 1 TO 30 6 X= RND(640) 7 Y= RND(400) 8 Radius= RND(50)*20 9 Stil= RND(1)*2 10 Index= RND(22) 11 FILL STYLE= Stil, Index 12 PCIRCLE X,Y,Radius 13 NEXT A 14 TEXT 200,200,"Bitte Ausschnitt wählen..." 15 MODE= 3 16 MOUSEON 17 REPEAT 18 Maus_X= MOUSEX 19 Maus_Y= MOUSEY 20 UNTIL MOUSEBUT= 1 21 MOUSEOFF 22 REPEAT 23 Hoehe= ABS(Maus_Y-MOUSEY) 24 Breite= ABS(Maus_X-MOUSEX) 25 BOX Maus_X,Maus_Y,Breite.Hoehe 26 BOX Maus_X,Maus_Y,Breite,Hoehe 27 UNTIL MOUSE8UT= 0 28 MODE= 1 29 MOUSEON 30 FORM_ALERT(2,"[3][ Bitte Diskette elnlegen. | Ich speichere den Ausschnitt | Jetzt ab. ][ OK | ABBRUCH ]",Button) 31 MOUSEOFF 32 IF Button= 2 THEN 33 EXIT TO Ende 34 ENDIF 35 Bild_Speichern("Bild",Maus_X,Maus_Y,Breite,Hoehe) 36 CLS 37 PRINT @(11,3);"Ich lade Jetzt den abgespeicherten Ausschnitt auf die Position (0.0)" 38 WAIT 4 39 CLS 40 Bild_Laden("Bild",1) 41 Bild_Zeigen(0,0,3,1) 42 REPEAT UNTIL MOUSEBUT 43 UNTIL 0 44 ' 45 -Ende 46 CLS 47 END 48 ' 49 DEF PROC Bild_Speichern(File_Name$,X,Y,Breite,Hoehe) 50 LOCAL Adresse,Speicher 51 Speicher= (Breite*15)/16*Hoehe*2+6 52 Adresse= MEMORY(Speicher) 53 BITBLT X,Y,Breite,Hoehe TO Adresse 54 BSAVE File_Name$+".BLD",Adresse,Speicher 55 RETURN 56 ' 57 DEF PROC Bild_Laden(File_Name$,Bild_Nummer) 58 LOCAL Bild_Laden_Flag 59 IF Bild_Laden_Flag= 0 THEN 60 DIM Adresse(10) 61 Bild_Laden_Flag= 1 62 ENDIF 63 File_Name$= File_Name$+".BLD" 64 GEMDOS(Dta_Buffer,$2f) 65 File_Name= LPEEK(SEGPTR+28)+LPEEK(VARPTR(File_Name$)) 66 GEMDOS(.$4e,HIGH(File_Name),LOW(File_Name),$3f) 67 Datei_Laenge= LPEHC(DtaBuffer-26) 68 Adresse(Bild_Nummer)= MEMORY(Datei_Laenge) 69 BLOAD File_Name$,Adresse(Bild_Nummer) 70 RETURN 71 ' 72 DEF PROC Bild_Zeigen(X,Y,Modus,Bild_Nummer) 73 Breite= WPEEK(Adresse(Bild_Nummer)+2) 74 Hoehe= WPEEK(Adresse(Bild_Nummer)+4) 75 BITBLT Adresse(Bild_Nummer) TO X,Y,Breite,Hoehe,Modus 76 RETURN

Listing 3. Drei Prozeduren und ein Anwendungsbeispiel zur komfortablen Blldschlrmverwaltung unter Omikron-Basic

xdef myjoy xref joyst1,joyst2 text ; Für DEVPAC 2.0: section text myjoy: movem.l a0-a1,-(a7) addq.l #1,a0 move.b (a0)+,joyst1 move.b (a0),joyst2 movea.l (a7)+,a0-a1 rts

Listing 4. Der Kern der Joystickabfrage Ist Assembler. Nennen Sie diese Datei JOYSTICKS.

/* Variablendef. */ long oldjoy ; char code = 0x14 ; char mausan[] = { 0x15. 0x8 ); unsigned char joyst1, joyst2; KBDVBASE *kvb; /* Prototypen */ extern void myjoy(void); void j_on(void); void j_off(void); /* Joystick an */ void j_on(void) ( kvb = Kbdvbase() ; oldjoy = (long)kvb->kb_joyvec: /* Alte Routine sichern */ kvb->kb_joyvec = myjoy; /* Neue setzen */ Ikbdws(0, &code);/* An Tastaturprozessor: Joysticks an */ } /* Joystick aus */ void jo_ff(void) { Ikbdws(1, mausan); /* Joysticks aus und Maus an */ kvb->kb_joyvec = (void *)oldjoy; /* Alte Routine zurück */ }

Listing 5. Um In den Genuß unserer komfortablen Joystickabfrage zu kommen, binden Sie diese Headerdatei In Ihren C-Quelltext ein

#include <stdio.h> #include <tos.h> #include <joystick.h> void main(void) { j_on(); /* Joystickroutine elnschalten */ while (!Bconstat(2)) /* ...bis Taste gedrückt wird */ printf("%d %d\n",joyst1, joyst2) ; j_off(); /* Joystickroutine auaachalten */ }

Listing 6. Ein Anwendungsbelsplel für die Joystickabfrage In Turbo-C

; PRJ-Datei JOYSTICK.PRJ: *; name of executable program is topmost window = ; list of modules follows... TCSTART.O ; startup code JOYSTICK.S * ; compile topmost window TCFLTLIB.LIB TCSTDLIB.LIB TCEXTLIB.LIB TCTOSLIB.LIB

Listing 7. Mit dieser Projektdatel erzeugen Sie ein ablauftertiges Programm aus den Listings 4 bis 6