Bug 183259 - autopilot and flight director for moon-lander-1.0-1023
Summary: autopilot and flight director for moon-lander-1.0-1023
Status: RESOLVED FIXED
Alias: None
Product: SUSE LINUX 10.0
Classification: openSUSE
Component: X11 Applications (show other bugs)
Version: unspecified
Hardware: x86-64 SuSE Linux 10.0
: P5 - None : Enhancement
Target Milestone: ---
Assignee: Ales Nosek
QA Contact: Stefan Dirsch
URL:
Whiteboard:
Keywords: Built, patch, UI, Usability
Depends on:
Blocks:
 
Reported: 2006-06-09 12:06 UTC by John Doe
Modified: 2006-09-04 06:42 UTC (History)
1 user (show)

See Also:
Found By: Customer
Services Priority:
Business Priority:
Blocker: ---
Marketing QA Status: ---
IT Deployment: ---


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description John Doe 2006-06-09 12:06:39 UTC
First submitted in 2002, I added a flight director and simplified autopilot to
moon-lander-1.0-1023, one of the BSD-derived Amusements/Games/Action/Arcade X11
applications.

Please find the following files inlined
        moon-lander.spec                     - new rpm script
        moon-lander-autopilot.dif            - new code patch
        moon-lander-autopilot.tar.bz2.base64 - new images
           images/beacon1.png                  autopilot indicator
           images/beacon2.png
           images/crosshairs1.png              flight director
           images/crosshairs2.png
Note the new images are mimencoded (like mail attachments)

b5f0594e685255f45735200704d61b76  /home/bob/tmp/moon-lander-autopilot.tar.bz2
ea91aca1106de618f1bf3d038ef506d5  /home/bob/tmp/moon-lander-autopilot.dif
30d3e65e12997f4b86b50499b4459fac  /home/bob/tmp/moon-lander.spec

        ---- moon-lander.spec ----
#
# spec file for package moon-lander (Version 1.0)
#
# Copyright (c) 2005 SUSE LINUX Products GmbH, Nuernberg, Germany.
# This file and all modifications and additions to the pristine
# package are under the same license as the package itself.
#
# Please submit bugfixes or comments via http://www.suse.de/feedback/
#

# norootforbuild
# neededforbuild  SDL-devel-packages SDL_image SDL_image-devel SDL_mixer-packages gpp libgpp libjpeg libpng-devel-packages xf86

BuildRequires: aaa_base acl attr bash bind-utils bison bzip2 coreutils cpio cpp cracklib cvs cyrus-sasl db devs diffutils e2fsprogs file filesystem fillup findutils flex gawk gdbm-devel gettext-devel glibc glibc-devel glibc-locale gpm grep groff gzip info insserv klogd less libacl libattr libcom_err libgcc libnscd libselinux libstdc++ libxcrypt libzio m4 make man mktemp module-init-tools ncurses ncurses-devel net-tools netcfg openldap2-client openssl pam pam-modules patch permissions popt procinfo procps psmisc pwdutils rcs readline sed strace sysvinit tar tcpd texinfo timezone unzip util-linux vim zlib zlib-devel SDL SDL-devel SDL_image SDL_image-devel SDL_mixer SDL_mixer-devel aalib aalib-devel alsa alsa-devel arts arts-devel audiofile audiofile-devel autoconf automake binutils esound esound-devel expat fontconfig fontconfig-devel gcc gcc-c++ gdbm gettext glib2 glib2-devel gnome-filesystem libjpeg libjpeg-devel libmikmod libogg libogg-devel libpng libpng-devel libstdc++-devel libtool libvorbis libvorbis-devel perl resmgr rpm slang slang-devel xorg-x11 xorg-x11-devel xorg-x11-libs

Name:         moon-lander
URL:          http://magigames.org/moonlander.html
License:      BSD
Group:        Amusements/Games/Action/Arcade
#Requires:     xforms
Autoreqprov:  on
Version:      1.0
Release:      1023af
Summary:      A 2D game of gravity
Source0:      %{name}-%{version}.tar.bz2
Source1:      %{name}-autopilot.tar.bz2
Patch0:       %{name}.dif
Patch1:       %{name}-destdir.patch
Patch2:       %{name}-overflow.patch
Patch3:       %{name}-autopilot.dif
BuildRoot:    %{_tmppath}/%{name}-%{version}-build

%description
Moon Lander is a 2D game of gravity.  Land your ship on the landing
pad. Don't go too fast or you will crash.



Authors:
--------
    David J. Blood <geekd@yahoo.com>
    Mike Heckman <mike@heckman.net>
    Ryan Daniels <pacmanfever@hotmail.com>
    Brian "Mo" Degenhardt <bmd@mp3.com>
    Garrett Banuk <mongoose@wpi.edu>
    Robert Meier <robert.meier@computer.org>

%debug_package
%prep
%setup -n %{name}
%setup -a 1 -n %{name}
%patch0 -p0
%patch1 -p1
%patch2 -p1
%patch3 -p1


%build
export RPM_OPT_FLAGS
make

%install
rm -rf $RPM_BUILD_ROOT
export DESTDIR=$RPM_BUILD_ROOT
make install
pushd $RPM_BUILD_ROOT/usr/share/games/moon-lander
for file in `ls -1d *`; do
	if test "$file" != moon-lander.bin && test -f $file; then
		rm $file
	fi
done
popd

%clean
rm -rf $RPM_BUILD_ROOT

%files
%defattr(-,root,root)
%doc README.txt
/usr/share/games/moon-lander
/usr/X11R6/bin/moon-lander

%changelog -n moon-lander
* Tue May 10 2005 - meissner@suse.de
- fixed buffer overflow.
* Mon Jan 12 2004 - adrian@suse.de
- added %%defattr
* Mon Jun 16 2003 - coolo@suse.de
- use BuildRoot
* Tue Apr 16 2002 - ro@suse.de
- link using g++ (for SDL_mixer)
* Fri Feb 01 2002 - ro@suse.de
- changed neededforbuild <libpng> to <libpng-devel-packages>
* Fri Oct 26 2001 - ro@suse.de
- use neededforbuild aliases: SDL_devel-pakages, SDL_mixer-packages
* Thu Aug 23 2001 - uli@suse.de
- initial package
        ---- moon-lander.spec ----

        ---- moon-lander=autopilot.dif ----
--- moon-lander/moon_lander.c	2006-06-09 06:11:51.000000000 -0400
+++ moon-lander/moon_lander.c	2006-06-09 06:09:19.000000000 -0400
@@ -14,6 +14,12 @@
 * 08/17/2001 - cleaned up some of the messy code, fixed last of the memory leaks,
 *  added ryan daniels' ship and thrusters
 *
+* 03/17/2002 - Dr. Robert Meier improved the autopilot to use minimum fuel
+*              trajectory from current position and velocity.
+*
+* 05/06/2005 - Dr. Robert Meier improved the autopilot to act as a
+*              flight director.
+*
 */
 
 
@@ -96,6 +102,7 @@
   int small_font;
   int demo_mode;
   int autopilot;
+  int flightdirector;
   int state;
   int ActualTime, LastTime;
   int landing_pad;
@@ -108,6 +115,10 @@
   Sprite thrustb;
   Sprite thrust_left;
   Sprite thrust_right;
+  Sprite crosshairs;
+  Sprite crosshairsb;
+  Sprite beacon;
+  Sprite beaconb;
   Sprite miniship;
   Sprite logo;
   Sprite gameover_screen;
@@ -195,7 +206,7 @@
     }
   
     while (!done){
-      if ( files[count] = readdir(dir) ){
+      if ( (files[count] = readdir(dir)) ){
       
 	//printf("I see - %d %s\n", count, files[count]->d_name);
 	count++;
@@ -883,6 +894,7 @@
     draw_score(game, 0);
     DT_DrawText("Arrow keys control the ship", game->screen, game->big_font, 100, 100 );
     DT_DrawText("Q quit   P pause   ESC options", game->screen, game->big_font, 75, 125 );
+    DT_DrawText("A autopilot   F flight director", game->screen, game->big_font, 75, 150 );
     DT_DrawText("Press ENTER to play", game->screen, game->big_font, 175, 170 );
 
     DT_DrawText("Score for each round = landing pad score + remaining fuel.", game->screen, game->small_font, 150, 280 );
@@ -1256,6 +1268,42 @@
 
 /************************************************/
 
+void gamefd( Game *game)
+{
+  /* ----------------------------------------------------------------
+     Flight Directory - written by Dr. Robert Meier 06/05/2006
+
+     During powered descent from low-phi (nearly parallel to the
+       horizon) orbit, the lunar module analog computer presented the
+       pilot with two oscilloscope displays.
+     One presented the predicted rate of climb and crosstrack speed
+       at the time that downrange speed was zero.
+     The second predicted altitude and crosstrack error at the time
+       that downrange speed was zero.
+     The pilot's goal was to keep the blip on each oscilloscope
+       centered as the predictions were updated according to radar.
+
+     As a similar presentation, use a point to indicate the lowest
+       altitude and further side motion if thrust is applied continously.
+
+     ---------------------------------------------------------------- */
+  const float G = game->gravity;
+  const float A = 0.10;
+  const float B = 0.07;
+  Sprite *ship = &game->ship;
+  float xi = ship->x + 0.5 * ship->w;
+  float yi = ship->y + ship->h;
+  float hi = ship->x_vel;
+  float vi = ship->y_vel;
+  float sgn = hi > 0 ? 1 : -1;
+  game->crosshairs.x = xi - 4 + sgn * hi * hi / (2 * B);
+  game->crosshairs.y = yi - 4 + vi * vi / (2 * (A-G));
+  game->crosshairsb.x = game->crosshairs.x;
+  game->crosshairsb.y = game->crosshairs.y;
+}
+
+/************************************************/
+
 void gameai( int *left, 
 	     int *right, 
 	     int *down, 
@@ -1275,7 +1323,203 @@
      velocity. 
      4 => Freefall with minor course changes
 
+     Game AI -- improved by Dr. Robert Meier 03/17/2002
+
+     The lunar lander powered descent from low-phi orbit was a
+       nonlinear problem well beyond autopilots until the 1970s.
+     Landing with perfect attitude control on a flat surface is
+       easy.
+
+     The minimum fuel course is called bang-bang control.
+
+     No vertical thrust until continuous vertical thrust will zero
+       descent rate at the pad.
+     Accelerate horizontally the minimum necessary to reach the pad.
+     Coast horizontally until continuous deceleration is required.
+     Decelerate continuously to reach zero groundspeed over the pad.
+
+     To avoid burning landing gear off with backblast, you should actually
+       shutdown and freefall when altitude and vertical speed are
+       low enough.
+
      ------------------------------------------------------------- */
+#if 1
+  // Find the nearest pad.
+  game->ai.pad = 0;
+  game->ai.distance = 9999;
+  float x = game->ship.x + game->ship.w/2;
+  for( count = 0; count < game->current_level.num_landings; count++ ) {
+    if( abs( x-game->current_level.landing_x[count] ) < game->ai.distance ) {
+      game->ai.distance = abs( x - game->current_level.landing_x[count] );
+      game->ai.pad = count;
+    }
+  }
+
+  // Find the target hovering point. (Allow .05 margin for error.)
+  int max_x = game->current_level.landing_x[game->ai.pad]
+            + game->current_level.landing_w[game->ai.pad]/2;
+  float max_v = game->current_level.landing_speed[game->ai.pad]-.05;
+  int max_y = game->current_level.landing_y[game->ai.pad];
+
+  // Let the user know which pad is in use
+  game->beacon.x = max_x;
+  game->beacon.y = max_y;
+  game->beaconb.x = max_x;
+  game->beaconb.y = max_y;
+
+  // Determine the time to target.
+  //   y(-i)  - freefall altitude that would result in current descent rate
+  //              (assumed freefall)
+  //   y(-t)  - altitude now
+  //   v(-t)  - descent rate now
+  //              (actual freefall)
+  //   y(0)   - altitude at burn
+  //              (continuous burn)
+  //   y(f)   - pad altitude
+  //
+  // Thanks to Galileo, we know
+  //   g      - gravity
+  //   a      - acceleration (thrust - gravity)
+  //   y(-i)  = y(0) - g i i / 2
+  //   y(-t)  = y(-i) + g (i-t) (i-t) / 2
+  //   v(-t)  = g (i-t)
+  //   y(f)   = y(0) + a f f / 2
+  //   a [y(f) - y(0)] = g [y(0) - y(-i)]
+  //   a f = g i
+  // We can now rewrite
+  //   y(-i)  = y(-t) - v(-t) v(-t) / 2 g
+  //   y(0)   = [a y(f) + g y(-i)] / (a + g)
+  //   i      = sqrt(2 [y(0) - y(-i)] / g)
+  //   f      = sqrt(2 [y(f) - y(0)] / a)
+  //   t      = i - v(-t) / g
+
+  float g = game->gravity;
+  float a = .10 - g;
+  float yt = game->ship.y + game->ship.h;
+  float vt = game->ship.y_vel;
+  float yf = max_y;
+  float yi = yt - vt * vt / (2 * g);
+  float y0 = (a * yf + g * yi) / (a + g);
+  float i = sqrt(2 * (y0 - yi) / g);
+  float f = sqrt(2 * (yf - y0) / a);
+  float t = i - vt / g;
+
+  // Thrust upward if continuous thrust will be just enough.
+  //   (Allow one frame margin for error.)
+  //   (Dont thrust if we are climbing.)
+  //   (Dont cancel pilot command.)
+  if( !*down && 0 < vt ) {
+    if( 2 > t ) {
+      *down = 1;
+      t = 0;
+    }
+  }
+
+//  printf( "ai-y: pad: %3d ship: %3f %5.2f g: %4.2f d: %d\n",
+//	  max_y, yt, vt, g, *down);
+
+  // Bang-bang control has an eigenfunction and three states.
+  //
+  // The eigenfunction is the phase space (position vs speed) trajectory
+  //   during continuous burn.
+  //   w      - acceleration
+  //   x(-b)  - position now
+  //   u(-b)  - groundspeed now
+  //   C      - position of zero groundspeed relative to speed direction
+  //   T      - time to coast and decelerate
+  // The eigenfunction, the position axis, and the time to target,
+  //   divide the space into three pairs of regions.
+  //   C = x(-b) sgn(u(-b)) + u(-b) u(-b) / 2 abs(w)
+  //   T = abs(x(-b)) / abs(u(-b)) + abs(u(-b)) / 2 abs(w)
+  //
+  //                  x 
+  //  . accelerating  :  decelerating
+  //  .               : 
+  //  .           <<<<: 
+  //  .        <<<    : 
+  //    . . .<<       : 
+  //    .     . .     : 
+  //    .coast    .   : 
+  //      .         . : 
+  //      .    v    . : 
+  //        .  v      :       
+  //          .v.     : 
+  //              . . + . .         --- v 
+  //                  :     . . 
+  //                  :  coast  . 
+  //                  : .         . 
+  //        >         : .         . 
+  //         >>       :   .         . 
+  //           >>>    :     . .     . 
+  //              >>>>:         . . . 
+  //                  :               . 
+  //                  :               . 
+  //  decelerating    :  accelerating . 
+  //                  :               . 
+  //
+  // State I: decelerating
+  //   C > 0           - condition
+  //   w               = -abs(w) sgn(u(-b))
+  // State I transitions to state II if actual acceleration is greater than w.
+  //
+  // State II: coasting
+  //   C < 0 & t+f > T - condition
+  //   w               = 0
+  // State II transitions to state I as C increases.
+  //
+  // State III: accelerating
+  //   C < 0 & t+f < T - condition
+  //   w               = abs(w) sgn(u(-b))
+  // State III transition to state II if actual acceleration is greater than w.
+  //
+
+  float xb = x - max_x;
+  float w  = .065;
+  float ub = game->ship.x_vel;
+  float C  = xb * (0 < ub ? 1 : 0 > ub ? -1 : 0) + ub * ub / (2 * fabs(w));
+  float T  = fabs(xb) / (fabs(ub) + .001) + fabs(ub) / (2 * fabs(w));
+
+  // Thrust if continuous thrust will be just enough.
+  //   (Dont cancel pilot command.)
+  //   (Dont thrust if close enough)
+  //   (Shutdown if altitude is low enough)
+  if( !*left && !*right ) {
+    *left = 0;
+    *right = 0;
+    if( .1 < fabs(ub) || 1 < fabs(xb) ) {
+      if( 0 < C ) {		/* State I: decelerating */
+        if( 0 < ub ) {
+	  *left = 1;		/* confirmed */
+	}
+	else{
+	  *right = 1;		/* confirmed */
+	}
+      }
+      else{
+	if( t + f > T ) {	/* State II: coasting */
+	}
+  	else{			/* State III: accelerating */
+          if( 0 < ub ) {
+	    *right = 1;
+	  }
+	  else{
+	    *left = 1;
+	  }
+	}
+      }
+    }
+    else{
+      float alt = game->current_level.landing_y[game->ai.pad] - yt;
+      if( 2 * g * alt + vt * vt < max_v * max_v ) {
+	*down = 0;		/* shutdown */
+      }
+    }
+  }
+
+//  printf( "ai-x: pad: %3d ship: %3f %5.2f C: %5.2f t+f: %5.2f T: %5.2f l: %d r: %d\n",
+//           max_x, xb+max_x, ub, C, t+f, T, *left, *right);
+
+#else /* 1 */
   *left = 0;
   *right = 0;
 
@@ -1397,6 +1641,7 @@
 	
     //printf( "4: game->ship.x=%f state=%d target=%f x_vel=%f y_vel=%f vdiff=%f\n", game->ship.x, game->ai.state, game->ai.target, game->ship.x_vel, game->ship.y_vel, game->ai.vdiff );
   }
+#endif /* 1 */
 
   return;
 }
@@ -1423,6 +1668,7 @@
   int pause = 0;
   int pressed = 0;
   int appressed = 0;
+  int fdpressed = 0;
   char display_string[100]; 
 
   game->ai.state = 0;
@@ -1474,7 +1720,7 @@
       // toggle
       if( !appressed ) {
 	game->autopilot = (game->autopilot)?0:1;
-	appressed++;
+	appressed = 1;
 	if( game->autopilot == 1 ) {
 	  game->ai.state = 0;
 	}
@@ -1485,6 +1731,19 @@
 	appressed = 0;
       }
     }
+
+    if (key_table[SDLK_f]){	
+      // toggle
+      if( !fdpressed ) {
+	game->flightdirector = (game->flightdirector)?0:1;
+	fdpressed = 1;
+      }
+    }
+    else{ 
+      if( fdpressed ) {
+	fdpressed = 0;
+      }
+    }
 	    
     if (key_table[SDLK_q]){
       exit(0);
@@ -1522,10 +1781,19 @@
 
     if( !pause ) {
 
-      if( game->demo_mode || game->autopilot ) {
+      if( game->demo_mode ) {
 	game->gravity = 0.05;
 	gameai( &left, &right, &down, game );
       }
+      else{
+        if( game->autopilot ) {
+	  gameai( &left, &right, &down, game );
+	}
+      }
+
+      if( game->flightdirector ) {
+        gamefd( game );
+      }
 
       if( game->fuel > 0 ) {
 	if( right == 1 ) {
@@ -1632,6 +1900,28 @@
 	draw_sprite(game->screen, game->thrust_left);
       }    
 
+      /* display flight director */
+
+      if (game->flightdirector) {
+	if ( (odd_even%2) == 0) {
+	  draw_sprite(game->screen, game->crosshairs);
+	}
+	else{
+	  draw_sprite(game->screen, game->crosshairsb);
+	}
+      }
+
+      /* display autopilot */
+
+      if (game->autopilot || game->demo_mode) {
+	if ( (odd_even%2) == 0) {
+	  draw_sprite(game->screen, game->beacon);
+	}
+	else{
+	  draw_sprite(game->screen, game->beaconb);
+	}
+      }
+
       /* display fuel  */
 
       draw_score(game, 1);
@@ -1801,6 +2091,18 @@
   sprintf(filename, "%simages/thrust2.png", DATAPATH);
   new_sprite(&(game.thrustb), filename, 0, 0, 1, 0);
 
+  sprintf(filename, "%simages/crosshairs1.bmp", DATAPATH);
+  new_sprite(&(game.crosshairs), filename, 0, 0, 1, 0);
+
+  sprintf(filename, "%simages/crosshairs2.bmp", DATAPATH);
+  new_sprite(&(game.crosshairsb), filename, 0, 0, 1, 0);
+
+  sprintf(filename, "%simages/beacon1.bmp", DATAPATH);
+  new_sprite(&(game.beacon), filename, 0, 0, 1, 0);
+
+  sprintf(filename, "%simages/beacon2.bmp", DATAPATH);
+  new_sprite(&(game.beaconb), filename, 0, 0, 1, 0);
+
   sprintf(filename, "%simages/thrust_left.bmp", DATAPATH);
   new_sprite(&(game.thrust_left), filename, 0, 0, 1, 0);
 
        ---- moon-lander=autopilot.dif ----

        ---- moon-lander=autopilot.tar.bz2.base64 ----
QlpoOTFBWSZTWUo27HgAAZv/jv+o9uBEQf+AEBMAEHrj3gAAAQABJgAADLABeAAwAAAAGgAA
AAAwAAAAGgAAAAAKoiaJpMk8kAbU0YE00aHpPQh+VNpR1MzVIljSI7TebjLgTffTCYiFdba1
oo3KRCqikN0zmoR1koQ0tCiBplMSiIipEohGwkt09Kp1EbOyi4qRcOgkI55abKBYrCkRHNHM
mKIKyhgeJQ1pOzGZ9pefTiCLz7O5QbZJtibDHheYxzpUL9XqaX3Y46NJgcWKMS4WmxJUuLWP
XqTSZnc6GiKnGYceEzU/pLvJbEm94nB5nmeDwMDgq7nvPIuKM8ss7MjQakmTrbS8q5DBYoSz
NbFQoZGZyIHa+pTv/ir8UpdWjK1y0x+bqRFoiE8N7OZzrWyM7r2c/8XckU4UJBKNux4A
        ---- moon-lander=autopilot.tar.bz2.base64 ----
Comment 1 Stefan Dirsch 2006-06-09 12:12:17 UTC
Thanks! I would suggest to build a package for these applications using our build service on opensuse.org.
Comment 2 Michael Gross 2006-06-09 13:06:20 UTC
I'll reassign it to the maintainer.
Comment 3 Ales Nosek 2006-08-24 15:06:08 UTC
(In reply to comment #0)
> First submitted in 2002, I added a flight director and simplified autopilot to
> moon-lander-1.0-1023, one of the BSD-derived Amusements/Games/Action/Arcade X11
> applications.
> 
> Please find the following files inlined
>         moon-lander.spec                     - new rpm script
>         moon-lander-autopilot.dif            - new code patch
>         moon-lander-autopilot.tar.bz2.base64 - new images
>            images/beacon1.png                  autopilot indicator
>            images/beacon2.png
>            images/crosshairs1.png              flight director
>            images/crosshairs2.png
> Note the new images are mimencoded (like mail attachments)
> 
> b5f0594e685255f45735200704d61b76  /home/bob/tmp/moon-lander-autopilot.tar.bz2
> ea91aca1106de618f1bf3d038ef506d5  /home/bob/tmp/moon-lander-autopilot.dif
> 30d3e65e12997f4b86b50499b4459fac  /home/bob/tmp/moon-lander.spec
> 
>         ---- moon-lander.spec ----
> #
> # spec file for package moon-lander (Version 1.0)
> #
> # Copyright (c) 2005 SUSE LINUX Products GmbH, Nuernberg, Germany.
> # This file and all modifications and additions to the pristine
> # package are under the same license as the package itself.
> #
> # Please submit bugfixes or comments via http://www.suse.de/feedback/
> #
> 
> # norootforbuild
> # neededforbuild  SDL-devel-packages SDL_image SDL_image-devel
> SDL_mixer-packages gpp libgpp libjpeg libpng-devel-packages xf86
> 
> BuildRequires: aaa_base acl attr bash bind-utils bison bzip2 coreutils cpio cpp
> cracklib cvs cyrus-sasl db devs diffutils e2fsprogs file filesystem fillup
> findutils flex gawk gdbm-devel gettext-devel glibc glibc-devel glibc-locale gpm
> grep groff gzip info insserv klogd less libacl libattr libcom_err libgcc
> libnscd libselinux libstdc++ libxcrypt libzio m4 make man mktemp
> module-init-tools ncurses ncurses-devel net-tools netcfg openldap2-client
> openssl pam pam-modules patch permissions popt procinfo procps psmisc pwdutils
> rcs readline sed strace sysvinit tar tcpd texinfo timezone unzip util-linux vim
> zlib zlib-devel SDL SDL-devel SDL_image SDL_image-devel SDL_mixer
> SDL_mixer-devel aalib aalib-devel alsa alsa-devel arts arts-devel audiofile
> audiofile-devel autoconf automake binutils esound esound-devel expat fontconfig
> fontconfig-devel gcc gcc-c++ gdbm gettext glib2 glib2-devel gnome-filesystem
> libjpeg libjpeg-devel libmikmod libogg libogg-devel libpng libpng-devel
> libstdc++-devel libtool libvorbis libvorbis-devel perl resmgr rpm slang
> slang-devel xorg-x11 xorg-x11-devel xorg-x11-libs
> 
> Name:         moon-lander
> URL:          http://magigames.org/moonlander.html
> License:      BSD
> Group:        Amusements/Games/Action/Arcade
> #Requires:     xforms
> Autoreqprov:  on
> Version:      1.0
> Release:      1023af
> Summary:      A 2D game of gravity
> Source0:      %{name}-%{version}.tar.bz2
> Source1:      %{name}-autopilot.tar.bz2
> Patch0:       %{name}.dif
> Patch1:       %{name}-destdir.patch
> Patch2:       %{name}-overflow.patch
> Patch3:       %{name}-autopilot.dif
> BuildRoot:    %{_tmppath}/%{name}-%{version}-build
> 
> %description
> Moon Lander is a 2D game of gravity.  Land your ship on the landing
> pad. Don't go too fast or you will crash.
> 
> 
> 
> Authors:
> --------
>     David J. Blood <geekd@yahoo.com>
>     Mike Heckman <mike@heckman.net>
>     Ryan Daniels <pacmanfever@hotmail.com>
>     Brian "Mo" Degenhardt <bmd@mp3.com>
>     Garrett Banuk <mongoose@wpi.edu>
>     Robert Meier <robert.meier@computer.org>
> 
> %debug_package
> %prep
> %setup -n %{name}
> %setup -a 1 -n %{name}
> %patch0 -p0
> %patch1 -p1
> %patch2 -p1
> %patch3 -p1
> 
> 
> %build
> export RPM_OPT_FLAGS
> make
> 
> %install
> rm -rf $RPM_BUILD_ROOT
> export DESTDIR=$RPM_BUILD_ROOT
> make install
> pushd $RPM_BUILD_ROOT/usr/share/games/moon-lander
> for file in `ls -1d *`; do
>         if test "$file" != moon-lander.bin && test -f $file; then
>                 rm $file
>         fi
> done
> popd
> 
> %clean
> rm -rf $RPM_BUILD_ROOT
> 
> %files
> %defattr(-,root,root)
> %doc README.txt
> /usr/share/games/moon-lander
> /usr/X11R6/bin/moon-lander
> 
> %changelog -n moon-lander
> * Tue May 10 2005 - meissner@suse.de
> - fixed buffer overflow.
> * Mon Jan 12 2004 - adrian@suse.de
> - added %%defattr
> * Mon Jun 16 2003 - coolo@suse.de
> - use BuildRoot
> * Tue Apr 16 2002 - ro@suse.de
> - link using g++ (for SDL_mixer)
> * Fri Feb 01 2002 - ro@suse.de
> - changed neededforbuild <libpng> to <libpng-devel-packages>
> * Fri Oct 26 2001 - ro@suse.de
> - use neededforbuild aliases: SDL_devel-pakages, SDL_mixer-packages
> * Thu Aug 23 2001 - uli@suse.de
> - initial package
>         ---- moon-lander.spec ----
> 
>         ---- moon-lander=autopilot.dif ----
> --- moon-lander/moon_lander.c   2006-06-09 06:11:51.000000000 -0400
> +++ moon-lander/moon_lander.c   2006-06-09 06:09:19.000000000 -0400
> @@ -14,6 +14,12 @@
>  * 08/17/2001 - cleaned up some of the messy code, fixed last of the memory
> leaks,
>  *  added ryan daniels' ship and thrusters
>  *
> +* 03/17/2002 - Dr. Robert Meier improved the autopilot to use minimum fuel
> +*              trajectory from current position and velocity.
> +*
> +* 05/06/2005 - Dr. Robert Meier improved the autopilot to act as a
> +*              flight director.
> +*
>  */
> 
> 
> @@ -96,6 +102,7 @@
>    int small_font;
>    int demo_mode;
>    int autopilot;
> +  int flightdirector;
>    int state;
>    int ActualTime, LastTime;
>    int landing_pad;
> @@ -108,6 +115,10 @@
>    Sprite thrustb;
>    Sprite thrust_left;
>    Sprite thrust_right;
> +  Sprite crosshairs;
> +  Sprite crosshairsb;
> +  Sprite beacon;
> +  Sprite beaconb;
>    Sprite miniship;
>    Sprite logo;
>    Sprite gameover_screen;
> @@ -195,7 +206,7 @@
>      }
> 
>      while (!done){
> -      if ( files[count] = readdir(dir) ){
> +      if ( (files[count] = readdir(dir)) ){
> 
>         //printf("I see - %d %s\n", count, files[count]->d_name);
>         count++;
> @@ -883,6 +894,7 @@
>      draw_score(game, 0);
>      DT_DrawText("Arrow keys control the ship", game->screen, game->big_font,
> 100, 100 );
>      DT_DrawText("Q quit   P pause   ESC options", game->screen,
> game->big_font, 75, 125 );
> +    DT_DrawText("A autopilot   F flight director", game->screen,
> game->big_font, 75, 150 );
>      DT_DrawText("Press ENTER to play", game->screen, game->big_font, 175, 170
> );
> 
>      DT_DrawText("Score for each round = landing pad score + remaining fuel.",
> game->screen, game->small_font, 150, 280 );
> @@ -1256,6 +1268,42 @@
> 
>  /************************************************/
> 
> +void gamefd( Game *game)
> +{
> +  /* ----------------------------------------------------------------
> +     Flight Directory - written by Dr. Robert Meier 06/05/2006
> +
> +     During powered descent from low-phi (nearly parallel to the
> +       horizon) orbit, the lunar module analog computer presented the
> +       pilot with two oscilloscope displays.
> +     One presented the predicted rate of climb and crosstrack speed
> +       at the time that downrange speed was zero.
> +     The second predicted altitude and crosstrack error at the time
> +       that downrange speed was zero.
> +     The pilot's goal was to keep the blip on each oscilloscope
> +       centered as the predictions were updated according to radar.
> +
> +     As a similar presentation, use a point to indicate the lowest
> +       altitude and further side motion if thrust is applied continously.
> +
> +     ---------------------------------------------------------------- */
> +  const float G = game->gravity;
> +  const float A = 0.10;
> +  const float B = 0.07;
> +  Sprite *ship = &game->ship;
> +  float xi = ship->x + 0.5 * ship->w;
> +  float yi = ship->y + ship->h;
> +  float hi = ship->x_vel;
> +  float vi = ship->y_vel;
> +  float sgn = hi > 0 ? 1 : -1;
> +  game->crosshairs.x = xi - 4 + sgn * hi * hi / (2 * B);
> +  game->crosshairs.y = yi - 4 + vi * vi / (2 * (A-G));
> +  game->crosshairsb.x = game->crosshairs.x;
> +  game->crosshairsb.y = game->crosshairs.y;
> +}
> +
> +/************************************************/
> +
>  void gameai( int *left, 
>              int *right, 
>              int *down, 
> @@ -1275,7 +1323,203 @@
>       velocity. 
>       4 => Freefall with minor course changes
> 
> +     Game AI -- improved by Dr. Robert Meier 03/17/2002
> +
> +     The lunar lander powered descent from low-phi orbit was a
> +       nonlinear problem well beyond autopilots until the 1970s.
> +     Landing with perfect attitude control on a flat surface is
> +       easy.
> +
> +     The minimum fuel course is called bang-bang control.
> +
> +     No vertical thrust until continuous vertical thrust will zero
> +       descent rate at the pad.
> +     Accelerate horizontally the minimum necessary to reach the pad.
> +     Coast horizontally until continuous deceleration is required.
> +     Decelerate continuously to reach zero groundspeed over the pad.
> +
> +     To avoid burning landing gear off with backblast, you should actually
> +       shutdown and freefall when altitude and vertical speed are
> +       low enough.
> +
>       ------------------------------------------------------------- */
> +#if 1
> +  // Find the nearest pad.
> +  game->ai.pad = 0;
> +  game->ai.distance = 9999;
> +  float x = game->ship.x + game->ship.w/2;
> +  for( count = 0; count < game->current_level.num_landings; count++ ) {
> +    if( abs( x-game->current_level.landing_x[count] ) < game->ai.distance ) {
> +      game->ai.distance = abs( x - game->current_level.landing_x[count] );
> +      game->ai.pad = count;
> +    }
> +  }
> +
> +  // Find the target hovering point. (Allow .05 margin for error.)
> +  int max_x = game->current_level.landing_x[game->ai.pad]
> +            + game->current_level.landing_w[game->ai.pad]/2;
> +  float max_v = game->current_level.landing_speed[game->ai.pad]-.05;
> +  int max_y = game->current_level.landing_y[game->ai.pad];
> +
> +  // Let the user know which pad is in use
> +  game->beacon.x = max_x;
> +  game->beacon.y = max_y;
> +  game->beaconb.x = max_x;
> +  game->beaconb.y = max_y;
> +
> +  // Determine the time to target.
> +  //   y(-i)  - freefall altitude that would result in current descent rate
> +  //              (assumed freefall)
> +  //   y(-t)  - altitude now
> +  //   v(-t)  - descent rate now
> +  //              (actual freefall)
> +  //   y(0)   - altitude at burn
> +  //              (continuous burn)
> +  //   y(f)   - pad altitude
> +  //
> +  // Thanks to Galileo, we know
> +  //   g      - gravity
> +  //   a      - acceleration (thrust - gravity)
> +  //   y(-i)  = y(0) - g i i / 2
> +  //   y(-t)  = y(-i) + g (i-t) (i-t) / 2
> +  //   v(-t)  = g (i-t)
> +  //   y(f)   = y(0) + a f f / 2
> +  //   a [y(f) - y(0)] = g [y(0) - y(-i)]
> +  //   a f = g i
> +  // We can now rewrite
> +  //   y(-i)  = y(-t) - v(-t) v(-t) / 2 g
> +  //   y(0)   = [a y(f) + g y(-i)] / (a + g)
> +  //   i      = sqrt(2 [y(0) - y(-i)] / g)
> +  //   f      = sqrt(2 [y(f) - y(0)] / a)
> +  //   t      = i - v(-t) / g
> +
> +  float g = game->gravity;
> +  float a = .10 - g;
> +  float yt = game->ship.y + game->ship.h;
> +  float vt = game->ship.y_vel;
> +  float yf = max_y;
> +  float yi = yt - vt * vt / (2 * g);
> +  float y0 = (a * yf + g * yi) / (a + g);
> +  float i = sqrt(2 * (y0 - yi) / g);
> +  float f = sqrt(2 * (yf - y0) / a);
> +  float t = i - vt / g;
> +
> +  // Thrust upward if continuous thrust will be just enough.
> +  //   (Allow one frame margin for error.)
> +  //   (Dont thrust if we are climbing.)
> +  //   (Dont cancel pilot command.)
> +  if( !*down && 0 < vt ) {
> +    if( 2 > t ) {
> +      *down = 1;
> +      t = 0;
> +    }
> +  }
> +
> +//  printf( "ai-y: pad: %3d ship: %3f %5.2f g: %4.2f d: %d\n",
> +//       max_y, yt, vt, g, *down);
> +
> +  // Bang-bang control has an eigenfunction and three states.
> +  //
> +  // The eigenfunction is the phase space (position vs speed) trajectory
> +  //   during continuous burn.
> +  //   w      - acceleration
> +  //   x(-b)  - position now
> +  //   u(-b)  - groundspeed now
> +  //   C      - position of zero groundspeed relative to speed direction
> +  //   T      - time to coast and decelerate
> +  // The eigenfunction, the position axis, and the time to target,
> +  //   divide the space into three pairs of regions.
> +  //   C = x(-b) sgn(u(-b)) + u(-b) u(-b) / 2 abs(w)
> +  //   T = abs(x(-b)) / abs(u(-b)) + abs(u(-b)) / 2 abs(w)
> +  //
> +  //                  x 
> +  //  . accelerating  :  decelerating
> +  //  .               : 
> +  //  .           <<<<: 
> +  //  .        <<<    : 
> +  //    . . .<<       : 
> +  //    .     . .     : 
> +  //    .coast    .   : 
> +  //      .         . : 
> +  //      .    v    . : 
> +  //        .  v      :       
> +  //          .v.     : 
> +  //              . . + . .         --- v 
> +  //                  :     . . 
> +  //                  :  coast  . 
> +  //                  : .         . 
> +  //        >         : .         . 
> +  //         >>       :   .         . 
> +  //           >>>    :     . .     . 
> +  //              >>>>:         . . . 
> +  //                  :               . 
> +  //                  :               . 
> +  //  decelerating    :  accelerating . 
> +  //                  :               . 
> +  //
> +  // State I: decelerating
> +  //   C > 0           - condition
> +  //   w               = -abs(w) sgn(u(-b))
> +  // State I transitions to state II if actual acceleration is greater than w.
> +  //
> +  // State II: coasting
> +  //   C < 0 & t+f > T - condition
> +  //   w               = 0
> +  // State II transitions to state I as C increases.
> +  //
> +  // State III: accelerating
> +  //   C < 0 & t+f < T - condition
> +  //   w               = abs(w) sgn(u(-b))
> +  // State III transition to state II if actual acceleration is greater than
> w.
> +  //
> +
> +  float xb = x - max_x;
> +  float w  = .065;
> +  float ub = game->ship.x_vel;
> +  float C  = xb * (0 < ub ? 1 : 0 > ub ? -1 : 0) + ub * ub / (2 * fabs(w));
> +  float T  = fabs(xb) / (fabs(ub) + .001) + fabs(ub) / (2 * fabs(w));
> +
> +  // Thrust if continuous thrust will be just enough.
> +  //   (Dont cancel pilot command.)
> +  //   (Dont thrust if close enough)
> +  //   (Shutdown if altitude is low enough)
> +  if( !*left && !*right ) {
> +    *left = 0;
> +    *right = 0;
> +    if( .1 < fabs(ub) || 1 < fabs(xb) ) {
> +      if( 0 < C ) {            /* State I: decelerating */
> +        if( 0 < ub ) {
> +         *left = 1;            /* confirmed */
> +       }
> +       else{
> +         *right = 1;           /* confirmed */
> +       }
> +      }
> +      else{
> +       if( t + f > T ) {       /* State II: coasting */
> +       }
> +       else{                   /* State III: accelerating */
> +          if( 0 < ub ) {
> +           *right = 1;
> +         }
> +         else{
> +           *left = 1;
> +         }
> +       }
> +      }
> +    }
> +    else{
> +      float alt = game->current_level.landing_y[game->ai.pad] - yt;
> +      if( 2 * g * alt + vt * vt < max_v * max_v ) {
> +       *down = 0;              /* shutdown */
> +      }
> +    }
> +  }
> +
> +//  printf( "ai-x: pad: %3d ship: %3f %5.2f C: %5.2f t+f: %5.2f T: %5.2f l: %d
> r: %d\n",
> +//           max_x, xb+max_x, ub, C, t+f, T, *left, *right);
> +
> +#else /* 1 */
>    *left = 0;
>    *right = 0;
> 
> @@ -1397,6 +1641,7 @@
> 
>      //printf( "4: game->ship.x=%f state=%d target=%f x_vel=%f y_vel=%f
> vdiff=%f\n", game->ship.x, game->ai.state, game->ai.target, game->ship.x_vel,
> game->ship.y_vel, game->ai.vdiff );
>    }
> +#endif /* 1 */
> 
>    return;
>  }
> @@ -1423,6 +1668,7 @@
>    int pause = 0;
>    int pressed = 0;
>    int appressed = 0;
> +  int fdpressed = 0;
>    char display_string[100]; 
> 
>    game->ai.state = 0;
> @@ -1474,7 +1720,7 @@
>        // toggle
>        if( !appressed ) {
>         game->autopilot = (game->autopilot)?0:1;
> -       appressed++;
> +       appressed = 1;
>         if( game->autopilot == 1 ) {
>           game->ai.state = 0;
>         }
> @@ -1485,6 +1731,19 @@
>         appressed = 0;
>        }
>      }
> +
> +    if (key_table[SDLK_f]){    
> +      // toggle
> +      if( !fdpressed ) {
> +       game->flightdirector = (game->flightdirector)?0:1;
> +       fdpressed = 1;
> +      }
> +    }
> +    else{ 
> +      if( fdpressed ) {
> +       fdpressed = 0;
> +      }
> +    }
> 
>      if (key_table[SDLK_q]){
>        exit(0);
> @@ -1522,10 +1781,19 @@
> 
>      if( !pause ) {
> 
> -      if( game->demo_mode || game->autopilot ) {
> +      if( game->demo_mode ) {
>         game->gravity = 0.05;
>         gameai( &left, &right, &down, game );
>        }
> +      else{
> +        if( game->autopilot ) {
> +         gameai( &left, &right, &down, game );
> +       }
> +      }
> +
> +      if( game->flightdirector ) {
> +        gamefd( game );
> +      }
> 
>        if( game->fuel > 0 ) {
>         if( right == 1 ) {
> @@ -1632,6 +1900,28 @@
>         draw_sprite(game->screen, game->thrust_left);
>        }    
> 
> +      /* display flight director */
> +
> +      if (game->flightdirector) {
> +       if ( (odd_even%2) == 0) {
> +         draw_sprite(game->screen, game->crosshairs);
> +       }
> +       else{
> +         draw_sprite(game->screen, game->crosshairsb);
> +       }
> +      }
> +
> +      /* display autopilot */
> +
> +      if (game->autopilot || game->demo_mode) {
> +       if ( (odd_even%2) == 0) {
> +         draw_sprite(game->screen, game->beacon);
> +       }
> +       else{
> +         draw_sprite(game->screen, game->beaconb);
> +       }
> +      }
> +
>        /* display fuel  */
> 
>        draw_score(game, 1);
> @@ -1801,6 +2091,18 @@
>    sprintf(filename, "%simages/thrust2.png", DATAPATH);
>    new_sprite(&(game.thrustb), filename, 0, 0, 1, 0);
> 
> +  sprintf(filename, "%simages/crosshairs1.bmp", DATAPATH);
> +  new_sprite(&(game.crosshairs), filename, 0, 0, 1, 0);
> +
> +  sprintf(filename, "%simages/crosshairs2.bmp", DATAPATH);
> +  new_sprite(&(game.crosshairsb), filename, 0, 0, 1, 0);
> +
> +  sprintf(filename, "%simages/beacon1.bmp", DATAPATH);
> +  new_sprite(&(game.beacon), filename, 0, 0, 1, 0);
> +
> +  sprintf(filename, "%simages/beacon2.bmp", DATAPATH);
> +  new_sprite(&(game.beaconb), filename, 0, 0, 1, 0);
> +
>    sprintf(filename, "%simages/thrust_left.bmp", DATAPATH);
>    new_sprite(&(game.thrust_left), filename, 0, 0, 1, 0);
> 
>         ---- moon-lander=autopilot.dif ----
> 
>         ---- moon-lander=autopilot.tar.bz2.base64 ----
> QlpoOTFBWSZTWUo27HgAAZv/jv+o9uBEQf+AEBMAEHrj3gAAAQABJgAADLABeAAwAAAAGgAA
> AAAwAAAAGgAAAAAKoiaJpMk8kAbU0YE00aHpPQh+VNpR1MzVIljSI7TebjLgTffTCYiFdba1
> oo3KRCqikN0zmoR1koQ0tCiBplMSiIipEohGwkt09Kp1EbOyi4qRcOgkI55abKBYrCkRHNHM
> mKIKyhgeJQ1pOzGZ9pefTiCLz7O5QbZJtibDHheYxzpUL9XqaX3Y46NJgcWKMS4WmxJUuLWP
> XqTSZnc6GiKnGYceEzU/pLvJbEm94nB5nmeDwMDgq7nvPIuKM8ss7MjQakmTrbS8q5DBYoSz
> NbFQoZGZyIHa+pTv/ir8UpdWjK1y0x+bqRFoiE8N7OZzrWyM7r2c/8XckU4UJBKNux4A
>         ---- moon-lander=autopilot.tar.bz2.base64 ----
> 

Comment 4 Ales Nosek 2006-08-25 06:16:09 UTC
I tried to copy the patch (moon-lander-autopilot.dif) from the web, but it is malformed. Please could you send it as an email attachment? The other files are OK. Thank you!
Comment 5 Ales Nosek 2006-09-04 06:42:22 UTC
Thank you for autopilot and flight director. They will be included in Factory.