// Support undo last movement or shot with the backspace key

diff -u -r flying-6.20.orig/ball.C flying-6.20/ball.C
--- flying-6.20.orig/ball.C	1995-08-07 23:26:55.000000000 +0200
+++ flying-6.20/ball.C	2009-05-01 02:55:08.000000000 +0200
@@ -38,6 +38,7 @@
 	SetV(Vec2(vx, vy));
 	dyn_id = DynObj::id;				// aktuelle DynID ins Objekt kopieren
 	state=0;
+	BallStateList = NULL;
 }
 
 Ball::Ball( double x, double y, double vx, double vy, double r_in ) :
@@ -51,6 +52,7 @@
 	SetV(Vec2(vx, vy));
 	dyn_id = DynObj::id;				// aktuelle DynID ins Objekt kopieren
 	state=0;
+	BallStateList = NULL;
 }
 
 Ball::Ball( double x, double y, double vx, double vy ) :
@@ -67,6 +69,7 @@
 	SetV(Vec2(vx, vy));
 	dyn_id = DynObj::id;				// aktuelle DynID ins Objekt kopieren
 	state=0;
+	BallStateList = NULL;
 }
 
 Ball::Ball( const Vec2 &v_in, double r_in ) :
@@ -81,6 +84,7 @@
 	SetV(Vec2Zero);
 	dyn_id = DynObj::id;				// aktuelle DynID ins Objekt kopieren
 	state=0;
+	BallStateList = NULL;
 }
 
 Ball::Ball( const Vec2 &v_in, double r_in, double m_in ) :
@@ -95,6 +99,7 @@
 	SetV(Vec2Zero);
 	dyn_id = DynObj::id;				// aktuelle DynID ins Objekt kopieren
 	state=0;
+	BallStateList = NULL;
 }
 
 Ball::~Ball() {
@@ -596,3 +601,28 @@
 void Ball::Draw() {
 	state->Show();
 }
+
+void Ball::SavePosition() {
+	struct BallStateList *n = new struct BallStateList;
+	n->p = p;
+	n->v = v;
+	n->next = BallStateList;
+	BallStateList = n;
+}
+
+void Ball::RestorePosition() {
+	struct BallStateList *n = BallStateList;
+	if (n) {
+		BallStateList = n->next;
+		SetPV (n->p, n->v);
+		delete n;
+	}
+}
+
+void Ball::ClearSavedPositions() {
+	while (BallStateList) {
+		struct BallStateList *n = BallStateList;
+		BallStateList = n->next;
+		delete n;
+	}
+}
diff -u -r flying-6.20.orig/ball.h flying-6.20/ball.h
--- flying-6.20.orig/ball.h	2009-04-30 21:03:05.000000000 +0200
+++ flying-6.20/ball.h	2009-05-01 02:55:08.000000000 +0200
@@ -34,6 +34,11 @@
 class BallStateTop;		// forward
 class PBallTop;
 
+struct BallStateList {
+	struct BallStateList *next;
+	Vec2 p, v;
+};
+
 //
 // -------------------------------------------------------------------------
 //   class Ball:  Fliegende Kugeln
@@ -124,6 +129,13 @@
 
 		virtual void Draw();
 
+		virtual void SavePosition();
+		virtual void RestorePosition();
+		virtual void ClearSavedPositions();
+
+	private:
+		struct BallStateList *BallStateList;
+
 friend class PBallTop;
 friend class LineKeeper;
 friend class StackKeeper;
diff -u -r flying-6.20.orig/bugs.h flying-6.20/bugs.h
--- flying-6.20.orig/bugs.h	1995-08-07 23:26:55.000000000 +0200
+++ flying-6.20/bugs.h	2009-05-01 02:55:08.000000000 +0200
@@ -85,7 +85,9 @@
 	explizit als double in der Source auftauchen.
 
 
--  In xmover.C gibt es Schwierigkeiten bei der Macro-Ersetzung von 
+- This is no gcc bug, but correct ISO behaviour (token pasting not allowed):
+
+	In xmover.C gibt es Schwierigkeiten bei der Macro-Ersetzung von
 	YADDOP zu + in der Zeile  c YADDOP= dy_c (also: c += dy_c)
 
 => c YADDOP dy_c verwenden und direkt += zuordnen
diff -u -r flying-6.20.orig/carrom.C flying-6.20/carrom.C
--- flying-6.20.orig/carrom.C	2009-04-30 21:03:11.000000000 +0200
+++ flying-6.20/carrom.C	2009-05-01 02:55:08.000000000 +0200
@@ -64,6 +64,10 @@
 	queen_in_pocket   = 0;
 	whites_in_pocket  = 0;
 	blacks_in_pocket  = 0;
+	save_striker_in_pocket = NULL;
+	save_queen_in_pocket   = NULL;
+	save_whites_in_pocket  = NULL;
+	save_blacks_in_pocket  = NULL;
 
 	keeper = new StackKeeper(PocketWidth,PocketFrame,table_black);
 }
@@ -322,6 +326,22 @@
 
 //////////////////////////////////////////////////////////////////////////////
 
+void Carrom::SavePosition() {
+	SaveInt (&save_striker_in_pocket, striker_in_pocket);
+	SaveInt (&save_queen_in_pocket, queen_in_pocket);
+	SaveInt (&save_whites_in_pocket, whites_in_pocket);
+	SaveInt (&save_blacks_in_pocket, blacks_in_pocket);
+	Game::SavePosition();
+}
+
+void Carrom::RestorePosition() {
+	RestoreInt (&save_striker_in_pocket, &striker_in_pocket);
+	RestoreInt (&save_queen_in_pocket, &queen_in_pocket);
+	RestoreInt (&save_whites_in_pocket, &whites_in_pocket);
+	RestoreInt (&save_blacks_in_pocket, &blacks_in_pocket);
+	Game::RestorePosition();
+}
+
 void Carrom::InPocket( Ball *b ) {
 	Game::InPocket(b);
 	if (b==striker)		{	striker_in_pocket = 1;	return;	}
diff -u -r flying-6.20.orig/carrom.h flying-6.20/carrom.h
--- flying-6.20.orig/carrom.h	1995-08-07 23:26:55.000000000 +0200
+++ flying-6.20/carrom.h	2009-05-01 02:55:08.000000000 +0200
@@ -34,6 +34,9 @@
 		virtual void InitPlayground();
 		virtual void DrawBackground() const;
 
+		virtual void SavePosition();
+		virtual void RestorePosition();
+
 		virtual const Real AreaOffX() const;
 		virtual const Real AreaOffY() const;
 		virtual const Real AreaWidth() const;
@@ -114,6 +117,8 @@
 		int			queen_in_pocket;
 		int			whites_in_pocket;
 		int			blacks_in_pocket;
+		struct IntList *save_striker_in_pocket, *save_queen_in_pocket;
+		struct IntList *save_whites_in_pocket, *save_blacks_in_pocket;
 
 		Vec2		mid;				// Mittelpunktvektor
 		Vec2		base[4][2];		// Begrenzung der Grundlinien
diff -u -r flying-6.20.orig/dynobj.h flying-6.20/dynobj.h
--- flying-6.20.orig/dynobj.h	1995-08-07 23:26:55.000000000 +0200
+++ flying-6.20/dynobj.h	2009-05-01 02:55:08.000000000 +0200
@@ -56,6 +56,9 @@
 		virtual void	Move( Real );	// Verschiebung des Objektes
 		virtual void	Reset();			// Initialisierung des Slowsteps
 		virtual void	Redraw();		// Initiales Zeichnes des Objekts
+		virtual void    SavePosition() {}
+		virtual void    RestorePosition() {}
+		virtual void    ClearSavedPositions() {}
 
 		static void DynInitAll();		// alle Initialisierungsroutinen aufrufen
 		static void DynEndAll();
diff -u -r flying-6.20.orig/flying.man flying-6.20/flying.man
--- flying-6.20.orig/flying.man	2009-05-01 02:43:06.000000000 +0200
+++ flying-6.20/flying.man	2009-05-01 02:55:08.000000000 +0200
@@ -111,6 +111,10 @@
 toggle hint arrows (see the \fI-nohints\fP option);
 cannot be used while hints are being shown
 .PP
+.IP BACKSPACE 8
+undo last movement or shot (useful for training,
+and to replace the balls after a miss in snooker)
+.PP
 .SH OPTIONS
 .SS X11
 .TP 8
diff -u -r flying-6.20.orig/game.C flying-6.20/game.C
--- flying-6.20.orig/game.C	1995-08-07 23:26:55.000000000 +0200
+++ flying-6.20/game.C	2009-05-01 02:55:08.000000000 +0200
@@ -147,6 +147,22 @@
 
 void Game::ResetGame() {
 	if (keeper)		keeper->GameWasReset();
+	ClearSavedPositions ();
+}
+
+void Game::SavePosition() {
+	if (keeper) keeper->SavePosition();
+	DynObj::ForAllDyn(&DynObj::SavePosition);
+}
+
+void Game::RestorePosition() {
+	if (keeper) keeper->RestorePosition();
+	DynObj::ForAllDyn(&DynObj::RestorePosition);
+	DynObj::ForAllDyn(&DynObj::CollisionCalc);
+}
+
+void Game::ClearSavedPositions() {
+	DynObj::ForAllDyn(&DynObj::ClearSavedPositions);
 }
 
 #ifndef SHOW_INFO
@@ -223,3 +239,27 @@
 }
 
 #endif
+
+void SaveInt (struct IntList **list, int value) {
+	struct IntList*n = new struct IntList;
+	n->value = value;
+	n->next = *list;
+	*list = n;
+}
+
+void RestoreInt (struct IntList **list, int *value) {
+	struct IntList *n = *list;
+	if (n) {
+		*list = n->next;
+		*value = n->value;
+		delete n;
+	}
+}
+
+void ClearIntList (struct IntList **list) {
+	while (*list) {
+		struct IntList *n = *list;
+		*list = n->next;
+		delete n;
+	}
+}
diff -u -r flying-6.20.orig/game.h flying-6.20/game.h
--- flying-6.20.orig/game.h	1995-08-07 23:26:55.000000000 +0200
+++ flying-6.20/game.h	2009-05-01 02:55:08.000000000 +0200
@@ -13,6 +13,15 @@
 class XWall;
 class YWall;
 
+struct IntList {
+	struct IntList *next;
+	int value;
+};
+
+void SaveInt (struct IntList **list, int value);
+void RestoreInt (struct IntList **list, int *value);
+void ClearIntList (struct IntList **list);
+
 class Game {
 	public:
 		Game(double wx=100., double wy=80.);
@@ -51,6 +60,10 @@
 
 		virtual void ResetGame();
 
+		virtual void SavePosition();
+		virtual void RestorePosition();
+		virtual void ClearSavedPositions();
+
 		virtual void ShootBall( Ball *b );
 		virtual void PressedBall( Ball *b );
 		virtual void TouchedBall( Ball *b );
diff -u -r flying-6.20.orig/keeper.C flying-6.20/keeper.C
--- flying-6.20.orig/keeper.C	1995-08-07 23:26:56.000000000 +0200
+++ flying-6.20/keeper.C	2009-05-01 02:55:08.000000000 +0200
@@ -24,6 +24,7 @@
 	frame_col = frame_col_in;
 	table_col = table_col_in;
 	off_count = 0;
+	save_off_count = NULL;
 }
 
 Keeper::~Keeper() {}
@@ -49,6 +50,15 @@
 
 void Keeper::GameWasReset() {
 	off_count = 0;
+	ClearIntList (&save_off_count);
+}
+
+void Keeper::SavePosition() {
+	SaveInt (&save_off_count, off_count);
+}
+
+void Keeper::RestorePosition() {
+	RestoreInt (&save_off_count, &off_count);
 }
 
 ///////////////////////////////////////////////////////////
diff -u -r flying-6.20.orig/keeper.h flying-6.20/keeper.h
--- flying-6.20.orig/keeper.h	1995-08-07 23:26:56.000000000 +0200
+++ flying-6.20/keeper.h	2009-05-01 02:55:08.000000000 +0200
@@ -16,6 +16,8 @@
 
 		virtual void Draw() = 0;
 		virtual void GameWasReset();
+		virtual void SavePosition();
+		virtual void RestorePosition();
 
 		void TakeOffBoard(Ball *b);
 
@@ -26,6 +28,8 @@
 		virtual void PlaceOffBoard(Ball *b) = 0;
 
 		int		off_count;
+		struct IntList *save_off_count;
+
 		ColorId	frame_col;
 		ColorId	table_col;
 		Real		size;			// Hoehe oder Breite
diff -u -r flying-6.20.orig/main.C flying-6.20/main.C
--- flying-6.20.orig/main.C	2009-05-01 02:43:58.000000000 +0200
+++ flying-6.20/main.C	2009-05-01 02:55:55.000000000 +0200
@@ -460,6 +460,7 @@
 		if (pressed_key=='1')	enhanced_mover=1;		
 		if (pressed_key=='2')	enhanced_mover=2;
 #endif
+		if (pressed_key=='\b')	g->RestorePosition();
 
 		if (pressed_key==' ')	g->ResetGame();
 		if (pressed_key=='h' && !nohint_flag_in_use)	nohint_flag = !nohint_flag;
diff -u -r flying-6.20.orig/pball.C flying-6.20/pball.C
--- flying-6.20.orig/pball.C	2009-05-01 02:43:58.000000000 +0200
+++ flying-6.20/pball.C	2009-05-01 02:55:08.000000000 +0200
@@ -347,6 +347,8 @@
 void PBallTop::Shoot() {
 Vec2	dir = dest-cue->P();
 
+	g->SavePosition();
+
 	if (!dir.IsZero()) {
 		g->ShootBall( cue );				// neuen Schuß anzeigen
 		cue->TellPressed();				// Pressed-Kugel dem Game-Objekt mitteilen
@@ -377,6 +379,8 @@
 
 
 void PBallTop::StartPullMoving( Ball *cueball ) {
+	g->SavePosition();
+
 	if (cueball)					cue = cueball;
 	else								cue = FindCueBall();
 	if (cue&&cue->Lock(this))	cue=0;						// Lock erlaubt
@@ -390,6 +394,8 @@
 
 
 void PBallTop::StartMoving( Ball *cueball ) {
+	g->SavePosition();
+
 	if (cueball)		cue = cueball;
 	else					cue = FindCueBall();
 	if (!cue)			return;
diff -u -r flying-6.20.orig/pool.C flying-6.20/pool.C
--- flying-6.20.orig/pool.C	1995-08-07 23:26:56.000000000 +0200
+++ flying-6.20/pool.C	2009-05-01 02:55:08.000000000 +0200
@@ -66,6 +66,7 @@
 	keeper = new LineKeeper(PocketHeight,PocketFrame,inner_cushion_col,table_col);
 
 	cue_in_pocket = 0;
+	save_cue_in_pocket = NULL;
 }
 
 Pool::~Pool() {
@@ -142,9 +143,20 @@
 void Pool::ResetGame() {
 	cueball->SetPV( cuedef );
 	cue_in_pocket = 0;
+	ClearIntList (&save_cue_in_pocket);
 	Billard::ResetGame();
 }
 
+void Pool::SavePosition() {
+	SaveInt (&save_cue_in_pocket, cue_in_pocket);
+	Billard::SavePosition();
+}
+
+void Pool::RestorePosition() {
+	RestoreInt (&save_cue_in_pocket, &cue_in_pocket);
+	Billard::RestorePosition();
+}
+
 void Pool::InPocket( Ball *b ) {
 	Billard::InPocket(b);
 	if (b==cueball)	cue_in_pocket = 1;
diff -u -r flying-6.20.orig/pool.h flying-6.20/pool.h
--- flying-6.20.orig/pool.h	1995-08-07 23:26:56.000000000 +0200
+++ flying-6.20/pool.h	2009-05-01 02:55:08.000000000 +0200
@@ -30,6 +30,8 @@
 		virtual const Real & GetNormalBallSize() 		const;
 
 		virtual void ResetGame();
+		virtual void SavePosition();
+		virtual void RestorePosition();
 		virtual void InPocket( Ball *b );
 		virtual void AllBallsStopped();
 		virtual int  IsSelectable(Ball *b);
@@ -41,6 +43,7 @@
 		Vec2					tridef;				// Triangle-Position
 
 		int	cue_in_pocket;
+		struct IntList *save_cue_in_pocket;
 
 		void Triangle( double x, double y );
 						 Real po;					// Offset von KeeperLine
diff -u -r flying-6.20.orig/pool8.C flying-6.20/pool8.C
--- flying-6.20.orig/pool8.C	2009-04-30 21:03:11.000000000 +0200
+++ flying-6.20/pool8.C	2009-05-01 02:55:08.000000000 +0200
@@ -41,6 +41,7 @@
 
 	mh = 0;
 	balls_in_pocket = 0;
+	save_balls_in_pocket = NULL;
 	for (int i=0;i<15;i++)	ball[i]=NULL;
 }
 
@@ -142,9 +143,20 @@
 	for (int i=0;i<15;i++)
 		if (ball[i])				ball[i]->SetPV( ball_p[i] );
 	balls_in_pocket = 0;
+	ClearIntList (&save_balls_in_pocket);
 	Pool::ResetGame();
 }
 
+void Pool8::SavePosition() {
+	SaveInt (&save_balls_in_pocket, balls_in_pocket);
+	Pool::SavePosition();
+}
+
+void Pool8::RestorePosition() {
+	RestoreInt (&save_balls_in_pocket, &balls_in_pocket);
+	Pool::RestorePosition();
+}
+
 ////////////////////////////////////////////////////////////////////////////
 
 void Pool8::InPocket( Ball *b ) {
diff -u -r flying-6.20.orig/pool8.h flying-6.20/pool8.h
--- flying-6.20.orig/pool8.h	1995-08-07 23:26:57.000000000 +0200
+++ flying-6.20/pool8.h	2009-05-01 02:55:08.000000000 +0200
@@ -16,6 +16,8 @@
 		virtual void InitPlayground();
 		virtual void DrawBackground() const;
 		virtual void ResetGame();
+		virtual void SavePosition();
+		virtual void RestorePosition();
 
 		virtual void InPocket( Ball *b );
 		virtual int  IsSelectable(Ball *b);
@@ -32,6 +34,7 @@
 		Ball	*ball[15];		// 0-6 full // 7 black // 8-15 half
 		Vec2	ball_p[15];		// default positions for these balls
 		int	balls_in_pocket;
+		struct IntList *save_balls_in_pocket;
 };
 
 class Pool9 : public Pool8 {
diff -u -r flying-6.20.orig/snooker.C flying-6.20/snooker.C
--- flying-6.20.orig/snooker.C	1995-08-07 23:26:57.000000000 +0200
+++ flying-6.20/snooker.C	2009-05-01 02:55:08.000000000 +0200
@@ -51,6 +51,8 @@
 	cueball=0;
 	color_in_pocket = 0;
 	reds_in_pocket  = 0;
+	save_reds_in_pocket = NULL;
+	save_color_in_pocket = NULL;
 }
 
 
@@ -130,10 +132,24 @@
 
 	reds_in_pocket  = 0;
 	color_in_pocket = 0;
+	ClearIntList (&save_reds_in_pocket);
+	ClearIntList (&save_color_in_pocket);
 
 	Billard::ResetGame();
 }
 
+void Snooker::SavePosition() {
+	SaveInt (&save_reds_in_pocket, reds_in_pocket);
+	SaveInt (&save_color_in_pocket, color_in_pocket);
+	Pool::SavePosition();
+}
+
+void Snooker::RestorePosition() {
+	RestoreInt (&save_reds_in_pocket, &reds_in_pocket);
+	RestoreInt (&save_color_in_pocket, &color_in_pocket);
+	Pool::RestorePosition();
+}
+
 // -------------------------------------------------------------------------
 
 SnookerDemo::~SnookerDemo() {}
diff -u -r flying-6.20.orig/snooker.h flying-6.20/snooker.h
--- flying-6.20.orig/snooker.h	1995-08-07 23:26:57.000000000 +0200
+++ flying-6.20/snooker.h	2009-05-01 02:55:08.000000000 +0200
@@ -20,6 +20,8 @@
 		virtual void InitPlayground();
 		virtual void DrawBackground() const;
 		virtual void ResetGame();
+		virtual void SavePosition();
+		virtual void RestorePosition();
 		virtual const Real & GetNormalBallSize() const;
 
 		ColorId		red_col;
@@ -43,6 +45,7 @@
 
 		int	reds_in_pocket;
 		int	color_in_pocket;
+		struct IntList *save_reds_in_pocket, *save_color_in_pocket;
 };
 
 class SnookerDemo : public Snooker {
