--- xast.c.orig	2026-06-25 14:22:08 UTC
+++ xast.c
@@ -3,6 +3,14 @@
 	goetz@cs.buffalo.EDU
 	Version 5, 9 Feb 93
 
+	Changes after version 5.0:
+        
+		Improved cursor-hiding.
+		Arrow keys.
+		ANSI-C cleanups.
+		Use usleep() instead of a delay loop.
+		Add prototypes.
+
 	Changes from version 4.3:
 
 		High score script.
@@ -27,16 +35,27 @@
 			Pat Ryan <pat@jaameri.gsfc.nasa.gov>
 			Craig Smith <csmith@cscs.UUCP>
 			Doug Merritt <doug@netcom.com>
+			Stephen McCamant <alias@mcs.com>
 			Makefile by James Berg <berg@plains>
 			Hi score script by Chris Moore <moore@src.bae.co.uk>
 			Man page by David Partain <dpl@ida.liu.se>
 */
 #include <stdio.h>		/* For NULL	*/
+#include <stdlib.h>		/* For malloc(), rand() etc */
+#include <string.h>		/* For srtlen() */
+#include <time.h>		/* For time() */
 #include <X11/Xlib.h>
 #include <X11/Xutil.h>
-#include <X11/cursorfont.h>	/* For erasing cursor - not important	*/
+#include <X11/keysym.h>
 #include <math.h>
+#include <unistd.h>
 
+#ifndef __STDC__
+define void
+#endif
+
+#define rand(rndint) rand() /* ??? */
+
 /* Indexes for 1st dimension of obj	*/
 /* The order they are in is important	*/
 #define	AST	0
@@ -68,10 +87,10 @@
 #define M_BULLET 0.1
 
 /* Keys		*/
-#define FIRE		'p'
-#define PAUSE		27	/* escape	*/
-#define SHIELD		'`'
-#define THRUST		'o'
+#define FIRE		XK_p
+#define PAUSE		XK_Escape	/* escape	*/
+#define SHIELD		XK_grave	/* ` */
+#define THRUST		XK_o
 
 #define BMAX		300	/* Max particles in a "boom" + 1	*/
 #define letheight	20	/* height of font	*/
@@ -121,6 +140,7 @@ int	width, height,
 	shapesize[LASTSHAPE+1]	= {44, 21, 10, 2, 1, SHIPSIZE+1, 35, 20},
 	shield_on;
 
+void
 initasts()
 {	int i;
 	extern Objtype obj[SHIP+1];
@@ -143,6 +163,7 @@ initasts()
 		obj[i].mass = M_BULLET;
 }	}
 
+void
 makeasts()
 {	int i;
 	extern Objtype obj[SHIP+1];
@@ -163,7 +184,7 @@ makeasts()
 		if (a >  63)
 			obj[i].y = (double) a;
 			else obj[i].y = (double) height - a;
-		a = rand(rndint); a = 4 - a>>5;
+		a = rand(rndint); a = 4 - (a>>5);
 		obj[i].rot = (double) a;
 		a = rand(rndint);
 		obj[i].rotvel = ((double) a)/2048;
@@ -177,6 +198,7 @@ makeasts()
 	numasts = i;
 }
 
+void
 makeenemy()	/* Start an enemy ship	*/
 {	extern Objtype obj[SHIP+1];
 	extern int height, level, rndint;
@@ -199,9 +221,9 @@ int nextast()	/* Find next unused asteroid object	*/
 	return i;
 }
 
-int collide(i, j)	/* Returns non-zero if i collided with j	*/
+int collide(int i, int j)
+			/* Returns non-zero if i collided with j	*/
 			/* Ship must be j!  (See below)			*/
-	int i, j;
 {	extern Objtype obj[SHIP+1];
 	extern int shapesize[LASTSHAPE+1];
 	extern double drawscale;
@@ -258,15 +280,17 @@ Loopend:		jx1 = jx2; jy1 = jy2;
 	return 0;
 }
 
-blastpair(i, j)		/* Generate random velocity vector v.	*/
-	int i, j ;	/* Add v to i, -v to j.			*/
+void
+blastpair(int i, int j)
+			/* Generate random velocity vector v.	*/
+			/* Add v to i, -v to j.			*/
 {	extern int rndint;
 	extern Objtype obj[SHIP+1];
 	unsigned char c;	/* for rand	*/
 	double vx, vy;
 	c = rand(rndint);
 /*	c = 4 - c>>5;	if you need angles from -3 to 4		*/
-	c>>2;		/* possibly save some time on sin/cos	*/
+	c >>= 2;		/* possibly save some time on sin/cos	*/
 	vx = cos((double) c); vy = sin((double) c);
 	obj[i].xvel = obj[i].xvel + vx;
 	obj[i].yvel = obj[i].yvel + vy;
@@ -282,8 +306,8 @@ blastpair(i, j)		/* Generate random velocity vector v.
 #define rotinert(i)	(double) (obj[i].mass*shapesize[obj[i].shape]*shapesize[obj[i].shape])
 
 /* cause two objects to collide elastically	*/
-bounce(i, j)
-int	i,j;
+void
+bounce(int i, int j)
 {
 double	rotrat, temp;
 extern	Objtype obj[SHIP+1];
@@ -345,10 +369,9 @@ obj[j].rotvel = temp;
 obj[j].rotvel = temp;
 }
 
-botline(disp, window, gc)	/* Print status line text	*/
-	Display *disp;
-	Drawable window;
-	GC gc;
+void
+botline(Display *disp, Drawable window, GC gc)
+			/* Print status line text	*/
 {	extern int highscore, ships, score;
 	char text[70];
 	sprintf(text, "Ships:%2d   Score:%6d   Shield:        High:%6d",
@@ -357,10 +380,9 @@ botline(disp, window, gc)	/* Print status line text	*/
 			text, strlen(text));
 }
 
-printss(disp, window, gc)	/* Print ships and score	*/
-	Display *disp;
-	Drawable window;
-	GC gc;
+void
+printss(Display *disp, Drawable window, GC gc)
+			/* Print ships and score	*/
 {	extern int height, highscore, oldscore, ships, score;
 	extern Objtype obj[SHIP+1];	/* to kill ship	*/
 	char sstring[30];
@@ -389,18 +411,17 @@ printss(disp, window, gc)	/* Print ships and score	*/
 	XClearArea(disp, window, 340+(energy>>1), height+8, 8, 10, False);
 }
 
-upscore(killer, up)	/* Only award score for things the player shot */
-	int killer, up;
+void
+upscore(int killer, int up)
+		/* Only award score for things the player shot */
 {	extern int score;
 	if (killer != ENEMYBUL && killer != SHIP)
 		score = score + up;
 }
 
 /* boom, movebooms, drawbooms all by Peter Phillips */
-boom(ob, particles, duration)
-int ob;
-int particles;
-int duration;
+void
+boom(int ob, int particles, int duration)
 { extern int rndint;
   int i;
   unsigned int r1, r2;
@@ -429,6 +450,7 @@ int duration;
 }
 
 /* move the various booms that are active */
+void
 movebooms()
 {
   int i;
@@ -461,10 +483,8 @@ movebooms()
 }
 
 /* Draw the various booms */
-drawbooms(disp, window, gc)
-     Display *disp;
-     Drawable window;
-     GC gc;
+void
+drawbooms(Display *disp, Drawable window, GC gc)
 {
   int i;
   Boom b;
@@ -481,6 +501,7 @@ drawbooms(disp, window, gc)
   }
 }
 
+void
 deletebooms()	/* delete all booms */
 {	Boom b;
 
@@ -490,11 +511,11 @@ deletebooms()	/* delete all booms */
 		b = b->next;
 }	}
 
-killast(killer, i)
-	int killer, i;		/* i = Asteroid # to kill	*/
+void
+killast(int killer, int i)	/* i = Asteroid # to kill	*/
 {	extern Objtype obj[SHIP+1];
 	extern int numasts;
-	int k, na, oldna;
+	int k, na = 0, oldna;
 
 	if (obj[i].shape == ASTSHAPE1)
 	{	na = nextast();		/* Could put 6 lines in a sub */
@@ -543,8 +564,9 @@ killast(killer, i)
 	{	boom(i, 9, 7);
 		obj[i].alive = 0; upscore(killer, 500);}
 }
-moveobjs(crash)
-	int *crash;
+
+void
+moveobjs(int *crash)
 {	extern Objtype obj[SHIP+1];
 	extern int ships;
 	extern double speedscale;
@@ -585,6 +607,7 @@ moveobjs(crash)
 	    }
 }
 
+void
 fire()
 {	extern Objtype obj[SHIP+1];
 	extern int width, nextbul;
@@ -603,6 +626,7 @@ fire()
 	nextbul++; if (nextbul == LASTBUL+1) nextbul = FBUL;
 }
 
+void
 hyper()
 {	extern Objtype obj[SHIP+1];
 	extern int width, height, rndint;
@@ -617,13 +641,9 @@ hyper()
 	obj[SHIP].y = (double) i;
 }
 
-vdraw(disp, window, gc, shape, x, y, rot)
-	Display *disp;
-	Drawable window;
-	GC gc;
-	int shape;
-	double x, y, rot;
-
+void
+vdraw(Display *disp, Drawable window, GC gc,
+    int shape, double x, double y, double rot)
 {	int line;
 	extern PolarPair shapes[LASTSHAPE+1][11];
 	extern int numpairs[LASTSHAPE+1];
@@ -639,9 +659,8 @@ vdraw(disp, window, gc, shape, x, y, rot)
 	XDrawLines (disp, window, gc, figure, numpairs[shape], CoordModePrevious);
 }
 
-main(argc, argv)
-	int argc;
-	char **argv;
+int
+main(int argc, char *argv[])
 {	Colormap cmap;
 	Cursor cursor;
 	Display *disp;
@@ -663,8 +682,8 @@ main(argc, argv)
 	extern int level, numasts, rndint, ships, score, oldscore;
 	extern Objtype obj[SHIP+1];
 	unsigned char c;	/* for rand	*/
-	double *temp, dx, dy, dist;
-	int crashed, flashon, len, pause = 0, delay = 64,
+	double dx, dy, dist;
+	int crashed, flashon, pause = 0, delay = 16384,
 		enemycount, counter, counterstart = 1,
 		i,	/* index for drawing objs, counting bullets */
 		r;	/* radius of shield circle	*/
@@ -704,11 +723,30 @@ main(argc, argv)
 		KeyPressMask | KeyReleaseMask | StructureNotifyMask);
 	XMapRaised (disp, window);
 
-	/* Erase cursor. Just delete next 5 lines if any error.	*/
+	/* Make cursor invisible. Just delete chunk if any error.	*/
 	cmap = XDefaultColormap(disp, screen);
 	XAllocNamedColor(disp, cmap, "Black", &exact, &black);
+#if 0   /* Easy way, but can leave a black spot */
+#include <X11/cursorfont.h>
 	cursor = XCreateFontCursor(disp, XC_dot);
 	XRecolorCursor(disp, cursor, &black, &black);
+#else   /* Hard, good way */
+	{	unsigned wd, ht;
+		Pixmap pm, maskpm;
+		GC cleargc;
+		XQueryBestCursor(disp, window, 1, 1, &wd, &ht);
+		pm = XCreatePixmap(disp, window, wd, ht, 1);
+		maskpm = XCreatePixmap(disp, window, wd, ht, 1);
+		cleargc = XCreateGC(disp, pm, 0, 0);
+		XFillRectangle(disp, pm, cleargc, 0, 0, wd, ht); 
+		XFillRectangle(disp, maskpm, cleargc, 0, 0, wd, ht); 
+		cursor = XCreatePixmapCursor(disp, pm, maskpm, 
+						&black, &black, 1, 1);
+		XFreePixmap(disp, pm);
+		XFreePixmap(disp, maskpm);
+		XFreeGC(disp, cleargc);
+	}
+#endif
 	XDefineCursor(disp, window, cursor);
 
 	XFillRectangle (disp, pixmap, pmgc, 0, 0, width, height);
@@ -746,7 +784,7 @@ Newship:    botline(disp, window, gc);
 		{   XNextEvent(disp, &event);
 		    switch (event.type)
 		    {	case MappingNotify:
-			    XRefreshKeyboardMapping (&event);
+			    XRefreshKeyboardMapping ((XMappingEvent *)&event);
 			    break;
 			case ConfigureNotify:
 			    width = event.xconfigure.width;
@@ -757,28 +795,29 @@ Newship:    botline(disp, window, gc);
 			    botline(disp, window, gc);
 			    break;
 			case KeyPress:
-			    len = XLookupString (&event, text, 10, &key, 0);
-			    if (len == 1 && !shield_on) switch (text[0])
-			    {	case 'e':
+			    key = XLookupKeysym ((XKeyEvent *)&event, 0);
+			    if (!shield_on) switch (key)
+			    {	case XK_Left: case XK_e:
 				    obj[SHIP].rotvel = obj[SHIP].rotvel - .1; break;
-				case 'r':
+				case XK_Right: case XK_r:
 				    obj[SHIP].rotvel = obj[SHIP].rotvel + .1; break;
-				case 'w':
+				case XK_w:
 				    obj[SHIP].rot -= pi/4; break;
-				case 't':
+				case XK_t:
 				    obj[SHIP].rot += pi/4; break;
-				case 'd':
+				case XK_d:
 				    obj[SHIP].rotvel = obj[SHIP].rotvel - .02; break;
-				case 'f':
+				case XK_f:
 				    obj[SHIP].rotvel = obj[SHIP].rotvel + .02; break;
-				case THRUST:
+				case XK_Up: case THRUST:
 				    obj[SHIP].xvel += cos(obj[SHIP].rot);
 				    obj[SHIP].yvel += sin(obj[SHIP].rot);
 				    obj[SHIP].shape = SHIPTHRSHAPE;
 				    break;
+				case XK_Control_L: case XK_Control_R:
 				case FIRE:
 				    if (obj[SHIP].alive) fire(); break;
-				case ' ':
+				case XK_space:
 				    if (obj[SHIP].alive)
 				    {	hyper(); flashon = 1;
 /*				    NOT XSetForeground (disp, gc, bg);
@@ -787,52 +826,55 @@ Newship:    botline(disp, window, gc);
 					XFillRectangle (disp, pixmap, pmgc, 0, 0, width, height);
 				    }
 				    break;
-				case SHIELD:
+				case XK_Down: case SHIELD:
 				    if (energy)
 				    {	shield_on = 1;
 					obj[SHIP].shape = SHIPSHAPE;}
 					break;
-				case '.':	/* decrease delay	*/
+				case XK_period:	/* decrease delay	*/
 				    if (delay > 1) delay >>=1; break;
-				case ',':	/* increase delay	*/
+				case XK_comma:	/* increase delay	*/
 				    delay <<=1; break;
-				case 'm':	/* decrease drawscale - may go negative */
+				case XK_m:	/* decrease drawscale - may go negative */
 				    drawscale -= .1; break;
-				case 'n':	/* increase drawscale	*/
+				case XK_n:	/* increase drawscale	*/
 				    drawscale += .1; break;
-				case '2':	/* increase speedscale	*/
+				case XK_2:	/* increase speedscale	*/
 				    speedscale += .1; break;
-				case '1':	/* decrease speedscale	*/
+				case XK_1:	/* decrease speedscale	*/
 				    speedscale -= .1; break;
-				case 'b':	/* increase moves/update */
+				case XK_b:	/* increase moves/update */
 				    counterstart++; break;
-				case 'v':	/* decrease moves/update */
+				case XK_v:	/* decrease moves/update */
 				    if (counterstart > 1) counterstart--;
 				    break;
 				case PAUSE:	/* pause	*/
 				    pause = 1 - pause; break;
-				case '+':	/* cheat	*/
+				case XK_plus:	/* cheat	*/
 				    ships++; botline(disp, window, gc); break;
-				case 'Q':	/* quit		*/
-				    goto End;
-				case 's':	/* start new ship */
-				    if (!obj[SHIP].alive)
+				case XK_q:	/* quit		*/
+				    if (event.xkey.state & ShiftMask)
+					goto End;
+				    break;
+				case XK_s:	/* start new ship */
+				    if (!obj[SHIP].alive) {
 					if (ships < 1) goto Newgame;
 					else goto Newship;
+				    }
 				    break;
 			    }
 			    break;
 			case KeyRelease:
-			    len = XLookupString(&event, text, 10, &key, 0);
-			    if (len == 1) switch (text[0])
-			    {	case 'e':
+			    key = XLookupKeysym((XKeyEvent *)&event, 0);
+			    switch (key)
+			    {	case XK_Left: case XK_e:
 				    obj[SHIP].rotvel = 0; break;
-				case 'r':
+				case XK_Right: case XK_r:
 				    obj[SHIP].rotvel = 0; break;
-				case THRUST:
+				case XK_Up: case THRUST:
 				    obj[SHIP].shape = SHIPSHAPE;
 				    break;
-				case SHIELD:
+				case XK_Down: case SHIELD:
 				    shield_on = 0; break;
 			    }
 /*			    break;		*/
@@ -850,7 +892,7 @@ Newship:    botline(disp, window, gc);
 			    botline(disp, window, gc);
 			}
 			/* Write copyright notice	*/
-			if (!ships && blist == NULL)
+			if (!ships)
 			{   sprintf(text, "Xasteroids");
 			    XDrawImageString (disp, pixmap, gc,
 				width/2-50, height/2-2*letheight,
@@ -917,7 +959,8 @@ Newship:    botline(disp, window, gc);
 			}
 			else	obj[ENEMYBUL].alive = 0;
 		    }
-		    for (i = 0; i < delay; i++);
+
+		    usleep(delay);
 		}
 	    }
 	}
