Index: code/branches/core5/data/levels/presentation_pong.oxw
===================================================================
--- code/branches/core5/data/levels/presentation_pong.oxw	(revision 5897)
+++ code/branches/core5/data/levels/presentation_pong.oxw	(revision 5898)
@@ -64,5 +64,5 @@
   <MovableEntity rotationrate=5 rotationaxis="0,0,1">
     <attached>
-      <PongCenterpoint name=pongcenter dimension="200,120" balltemplate=pongball battemplate=pongbat ballspeed=200 batspeed=130 batlength=0.25>
+      <PongCenterpoint name=pongcenter dimension="200,120" balltemplate=pongball battemplate=pongbat ballspeed=200 ballaccfactor=1.0 batspeed=130 batlength=0.25>
         <attached>
           <Model position="0,0,60" mesh="cube.mesh" scale3D="105,1,1" />
Index: code/branches/core5/src/modules/pong/Pong.cc
===================================================================
--- code/branches/core5/src/modules/pong/Pong.cc	(revision 5897)
+++ code/branches/core5/src/modules/pong/Pong.cc	(revision 5898)
@@ -76,4 +76,5 @@
             this->ball_->setFieldDimension(this->center_->getFieldDimension());
             this->ball_->setSpeed(0);
+            this->ball_->setAccelerationFactor(this->center_->getBallAccelerationFactor());
             this->ball_->setBatLength(this->center_->getBatLength());
 
@@ -172,4 +173,5 @@
             this->ball_->setPosition(Vector3::ZERO);
             this->ball_->setVelocity(Vector3::ZERO);
+            this->ball_->setAcceleration(Vector3::ZERO);
             this->ball_->setSpeed(0);
         }
Index: code/branches/core5/src/modules/pong/PongAI.cc
===================================================================
--- code/branches/core5/src/modules/pong/PongAI.cc	(revision 5897)
+++ code/branches/core5/src/modules/pong/PongAI.cc	(revision 5898)
@@ -49,4 +49,5 @@
         this->ballEndPosition_ = 0;
         this->randomOffset_ = 0;
+        this->bChangedRandomOffset_ = false;
         this->relHysteresisOffset_ = 0.02f;
         this->strength_ = 0.5f;
@@ -113,4 +114,5 @@
                 this->ballEndPosition_ = 0;
                 this->randomOffset_ = 0;
+                this->bChangedRandomOffset_ = false;
 
                 this->calculateRandomOffset();
@@ -129,4 +131,16 @@
                 this->bOscillationAvoidanceActive_ = false;
             }
+            
+            // If the ball is close enough, calculate another random offset to accelerate the ball
+            if (!this->bChangedRandomOffset_)
+            {
+                float timetohit = (-this->ball_->getPosition().x + this->ball_->getFieldDimension().x / 2 * sgn(this->ball_->getVelocity().x)) / this->ball_->getVelocity().x;
+                if (timetohit < 0.05)
+                {
+                    this->bChangedRandomOffset_ = true;
+                    if (rnd() < this->strength_)
+                        this->calculateRandomOffset();
+                }
+            }
 
             // Move to the predicted end position with an additional offset (to hit the ball with the side of the bat)
@@ -184,31 +198,98 @@
         Vector3 position = this->ball_->getPosition();
         Vector3 velocity = this->ball_->getVelocity();
+        Vector3 acceleration = this->ball_->getAcceleration();
         Vector2 dimension = this->ball_->getFieldDimension();
 
-        // calculate end-height: current height + slope * distance
-        this->ballEndPosition_ = position.z + velocity.z / velocity.x * (-position.x + dimension.x / 2 * sgn(velocity.x));
-
-        // Calculate bounces
-        for (float limit = 0.35f; limit < this->strength_ || this->strength_ > 0.99f; limit += 0.4f)
-        {
-            // Calculate a random prediction error, based on the vertical speed of the ball and the strength of the AI
-            float randomError = rnd(-1, 1) * dimension.y * (velocity.z / velocity.x / PongBall::MAX_REL_Z_VELOCITY) * (1 - this->strength_);
-
-            // Bounce from the lower bound
-            if (this->ballEndPosition_ > dimension.y / 2)
-            {
-                // Mirror the predicted position at the upper bound and add some random error
-                this->ballEndPosition_ = dimension.y - this->ballEndPosition_ + randomError;
-                continue;
-            }
-            // Bounce from the upper bound
-            if (this->ballEndPosition_ < -dimension.y / 2)
-            {
-                // Mirror the predicted position at the lower bound and add some random error
-                this->ballEndPosition_ = -dimension.y - this->ballEndPosition_ + randomError;
-                continue;
-            }
-            // No bounce - break
-            break;
+        // Calculate bounces. The number of predicted bounces is limited by the AIs strength
+        for (float limit = -0.05f; limit < this->strength_ || this->strength_ > 0.99f; limit += 0.4f)
+        {
+            // calculate the time until the ball reaches the other side
+            float totaltime = (-position.x + dimension.x / 2 * sgn(velocity.x)) / velocity.x;
+            
+            // calculate wall bounce position (four possible solutions of the equation: pos.z + vel.z*t + acc.z/2*t^2 = +/- dim.z/2)
+            float bouncetime = totaltime;
+            bool bUpperWall = false;
+            
+            if (acceleration.z == 0)
+            {
+                if (velocity.z > 0)
+                {
+                    bUpperWall = true;
+                    bouncetime = (dimension.y/2 - position.z) / velocity.z;
+                }
+                else if (velocity.z < 0)
+                {
+                    bUpperWall = false;
+                    bouncetime = (-dimension.y/2 - position.z) / velocity.z;
+                }
+            }
+            else
+            {
+                // upper wall
+                float temp = velocity.z*velocity.z + 2*acceleration.z*(dimension.y/2 - position.z);
+                if (temp >= 0)
+                {
+                    float t1 = (sqrt(temp) - velocity.z) / acceleration.z;
+                    float t2 = (sqrt(temp) + velocity.z) / acceleration.z * (-1);
+                    if (t1 > 0 && t1 < bouncetime)
+                    {
+                        bouncetime = t1;
+                        bUpperWall = true;
+                    }
+                    if (t2 > 0 && t2 < bouncetime)
+                    {
+                        bouncetime = t2;
+                        bUpperWall = true;
+                    }
+                }
+                // lower wall
+                temp = velocity.z*velocity.z - 2*acceleration.z*(dimension.y/2 + position.z);
+                if (temp >= 0)
+                {
+                    float t1 = (sqrt(temp) - velocity.z) / acceleration.z;
+                    float t2 = (sqrt(temp) + velocity.z) / acceleration.z * (-1);
+                    if (t1 > 0 && t1 < bouncetime)
+                    {
+                        bouncetime = t1;
+                        bUpperWall = false;
+                    }
+                    if (t2 > 0 && t2 < bouncetime)
+                    {
+                        bouncetime = t2;
+                        bUpperWall = false;
+                    }
+                }
+            }
+
+            if (bouncetime < totaltime)
+            {
+                // Calculate a random prediction error, based on the vertical speed of the ball and the strength of the AI
+                float randomErrorX = rnd(-1, 1) * dimension.y * (velocity.z / velocity.x / PongBall::MAX_REL_Z_VELOCITY) * (1 - this->strength_);
+                float randomErrorZ = rnd(-1, 1) * dimension.y * (velocity.z / velocity.x / PongBall::MAX_REL_Z_VELOCITY) * (1 - this->strength_);
+
+                // ball bounces after <bouncetime> seconds, update the position and continue
+                velocity.z = velocity.z + acceleration.z * bouncetime;
+                
+                if (bUpperWall)
+                {
+                    position.z = dimension.y / 2;
+                    velocity.z = -fabs(velocity.z) + fabs(randomErrorZ);
+                }
+                else
+                {
+                    position.z = -dimension.y / 2;
+                    velocity.z = fabs(velocity.z) - fabs(randomErrorZ);
+                }
+                    
+                position.x = position.x + velocity.x * bouncetime + randomErrorX;
+                this->ballEndPosition_ = position.z;
+            }
+            else
+            {
+                // ball doesn't bounce, calculate the end position and return
+                // calculate end-height: current height + slope * distance incl. acceleration
+                this->ballEndPosition_ = position.z + velocity.z * totaltime + acceleration.z / 2 * totaltime * totaltime;
+                return;
+            }
         }
     }
Index: code/branches/core5/src/modules/pong/PongAI.h
===================================================================
--- code/branches/core5/src/modules/pong/PongAI.h	(revision 5897)
+++ code/branches/core5/src/modules/pong/PongAI.h	(revision 5898)
@@ -62,4 +62,5 @@
             float ballEndPosition_;
             float randomOffset_;
+            bool bChangedRandomOffset_;
             float relHysteresisOffset_;
             float strength_;
Index: code/branches/core5/src/modules/pong/PongBall.cc
===================================================================
--- code/branches/core5/src/modules/pong/PongBall.cc	(revision 5897)
+++ code/branches/core5/src/modules/pong/PongBall.cc	(revision 5898)
@@ -46,4 +46,5 @@
 
         this->speed_ = 0;
+        this->accelerationFactor_ = 1.0f;
         this->bat_ = 0;
         this->batID_ = new unsigned int[2];
@@ -76,4 +77,5 @@
         Vector3 position = this->getPosition();
         Vector3 velocity = this->getVelocity();
+        Vector3 acceleration = this->getAcceleration();
 
         if (position.z > this->fieldHeight_ / 2 || position.z < -this->fieldHeight_ / 2)
@@ -102,4 +104,5 @@
                         velocity.x = -velocity.x;
                         velocity.z = distance * distance * sgn(distance) * PongBall::MAX_REL_Z_VELOCITY * this->speed_;
+                        acceleration = this->bat_[1]->getVelocity() * this->accelerationFactor_ * -1;
                         
                         this->fireEvent();
@@ -122,4 +125,5 @@
                         velocity.x = -velocity.x;
                         velocity.z = distance * distance * sgn(distance) * PongBall::MAX_REL_Z_VELOCITY * this->speed_;
+                        acceleration = this->bat_[0]->getVelocity() * this->accelerationFactor_ * -1;
 
                         this->fireEvent();
@@ -137,4 +141,6 @@
         }
 
+        if (acceleration != this->getAcceleration())
+            this->setAcceleration(acceleration);
         if (velocity != this->getVelocity())
             this->setVelocity(velocity);
Index: code/branches/core5/src/modules/pong/PongBall.h
===================================================================
--- code/branches/core5/src/modules/pong/PongBall.h	(revision 5897)
+++ code/branches/core5/src/modules/pong/PongBall.h	(revision 5898)
@@ -58,4 +58,9 @@
                 { return this->speed_; }
 
+            void setAccelerationFactor(float factor)
+                { this->accelerationFactor_ = factor; }
+            float getAccelerationFactor() const
+                { return this->accelerationFactor_; }
+
             void setBatLength(float batlength)
                 { this->batlength_ = batlength; }
@@ -72,4 +77,5 @@
             float fieldHeight_;
             float speed_;
+            float accelerationFactor_;
             float batlength_;
             PongBat** bat_;
Index: code/branches/core5/src/modules/pong/PongCenterpoint.cc
===================================================================
--- code/branches/core5/src/modules/pong/PongCenterpoint.cc	(revision 5897)
+++ code/branches/core5/src/modules/pong/PongCenterpoint.cc	(revision 5898)
@@ -44,4 +44,5 @@
         this->height_ = 120;
         this->ballspeed_ = 100;
+        this->ballaccfactor_ = 1.0;
         this->batspeed_ = 60;
         this->batlength_ = 0.25;
@@ -58,4 +59,5 @@
         XMLPortParam(PongCenterpoint, "battemplate", setBattemplate, getBattemplate, xmlelement, mode);
         XMLPortParam(PongCenterpoint, "ballspeed", setBallSpeed, getBallSpeed, xmlelement, mode);
+        XMLPortParam(PongCenterpoint, "ballaccfactor", setBallAccelerationFactor, getBallAccelerationFactor, xmlelement, mode);
         XMLPortParam(PongCenterpoint, "batspeed", setBatSpeed, getBatSpeed, xmlelement, mode);
         XMLPortParam(PongCenterpoint, "batlength", setBatLength, getBatLength, xmlelement, mode);
Index: code/branches/core5/src/modules/pong/PongCenterpoint.h
===================================================================
--- code/branches/core5/src/modules/pong/PongCenterpoint.h	(revision 5897)
+++ code/branches/core5/src/modules/pong/PongCenterpoint.h	(revision 5898)
@@ -68,4 +68,9 @@
                 { return this->ballspeed_; }
 
+            void setBallAccelerationFactor(float ballaccfactor)
+                { this->ballaccfactor_ = ballaccfactor; }
+            float getBallAccelerationFactor() const
+                { return this->ballaccfactor_; }
+
             void setBatSpeed(float batspeed)
                 { this->batspeed_ = batspeed; }
@@ -85,4 +90,5 @@
 
             float ballspeed_;
+            float ballaccfactor_;
             float batspeed_;
             float batlength_;
