Index: source/ps/Hotkey.cpp
===================================================================
--- source/ps/Hotkey.cpp	(revision 8124)
+++ source/ps/Hotkey.cpp	(working copy)
@@ -74,6 +74,7 @@
 	{ HOTKEY_WIREFRAME, "wireframe", SDLK_w, 0 },
 	{ HOTKEY_TOGGLEFULLSCREEN, "togglefullscreen", 0, 0 },
 	{ HOTKEY_CAMERA_RESET, "camera.reset", 0, 0 },
+	{ HOTKEY_CAMERA_FOLLOW, "camera.follow", 0, 0 },
 	{ HOTKEY_CAMERA_ZOOM_IN, "camera.zoom.in", SDLK_PLUS, SDLK_KP_PLUS },
 	{ HOTKEY_CAMERA_ZOOM_OUT, "camera.zoom.out", SDLK_MINUS, SDLK_KP_MINUS },
 	{ HOTKEY_CAMERA_ZOOM_WHEEL_IN, "camera.zoom.wheel.in", MOUSE_WHEELUP, 0 },
Index: source/ps/Hotkey.h
===================================================================
--- source/ps/Hotkey.h	(revision 8124)
+++ source/ps/Hotkey.h	(working copy)
@@ -55,6 +55,7 @@
 	HOTKEY_WIREFRAME,
 	HOTKEY_TOGGLEFULLSCREEN,
 	HOTKEY_CAMERA_RESET,
+	HOTKEY_CAMERA_FOLLOW,
 	HOTKEY_CAMERA_ZOOM_IN,
 	HOTKEY_CAMERA_ZOOM_OUT,
 	HOTKEY_CAMERA_ZOOM_WHEEL_IN,
Index: source/gui/scripting/ScriptFunctions.cpp
===================================================================
--- source/gui/scripting/ScriptFunctions.cpp	(revision 8124)
+++ source/gui/scripting/ScriptFunctions.cpp	(working copy)
@@ -72,6 +72,16 @@
 	g_GUI->PopPage();
 }
 
+/**
+ * Start / stop camera following mode
+ * @param entityid unit id to follow for. If zero - stop following mode
+ */
+void CameraFollow(void* UNUSED(cbdata), entity_id_t entityid)
+{
+	if(g_Game && g_Game->GetView())
+		g_Game->GetView()->CameraFollow(entityid);
+}
+
 bool IsNewSimulation(void* UNUSED(cbdata))
 {
 	return true; // XXX: delete this function
@@ -313,6 +323,7 @@
 	scriptInterface.RegisterFunction<void, std::wstring, CScriptVal, &PushGuiPage>("PushGuiPage");
 	scriptInterface.RegisterFunction<void, std::wstring, CScriptVal, &SwitchGuiPage>("SwitchGuiPage");
 	scriptInterface.RegisterFunction<void, &PopGuiPage>("PopGuiPage");
+	scriptInterface.RegisterFunction<void, entity_id_t, &CameraFollow>("CameraFollow");
 
 	// Simulation<->GUI interface functions:
 	scriptInterface.RegisterFunction<bool, &IsNewSimulation>("IsNewSimulation");
Index: source/graphics/GameView.cpp
===================================================================
--- source/graphics/GameView.cpp	(revision 8124)
+++ source/graphics/GameView.cpp	(working copy)
@@ -52,6 +52,7 @@
 #include "scripting/ScriptableObject.h"
 #include "simulation/LOSManager.h"
 #include "simulation2/Simulation2.h"
+#include "simulation2/components/ICmpPosition.h"
 
 extern int g_xres, g_yres;
 
@@ -273,7 +274,8 @@
 }
 
 CGameView::CGameView(CGame *pGame):
-	m(new CGameViewImpl(pGame))
+	m(new CGameViewImpl(pGame)),
+	m_cameraFollowingEntity(0)
 {
 	SViewPort vp;
 	vp.m_X=0;
@@ -529,7 +531,6 @@
 	g_Renderer.GetWaterManager()->UnloadWaterTextures();
 }
 
-
 static void ClampDistance(CGameViewImpl* m, bool smooth)
 {
 	if (!m->ConstrainCamera)
@@ -603,48 +604,84 @@
 	if (hotkeys[HOTKEY_CAMERA_ROTATE_DOWN])
 		m->RotateX.AddSmoothly(m->ViewRotateXSpeed * DeltaTime);
 
-	float moveRightward = 0.f;
-	float moveForward = 0.f;
-
-	if (hotkeys[HOTKEY_CAMERA_PAN])
+	// Process camera movements only if it is not in following mode
+	if(m_cameraFollowingEntity == 0)
 	{
-		moveRightward += m->ViewDragSpeed * mouse_dx;
-		moveForward += m->ViewDragSpeed * -mouse_dy;
-	}
+		float moveRightward = 0.f;
+		float moveForward = 0.f;
 
-	if (g_mouse_active)
-	{
-		if (g_mouse_x >= g_xres - 2 && g_mouse_x < g_xres)
-			moveRightward += m->ViewScrollSpeed * DeltaTime;
-		else if (g_mouse_x <= 3 && g_mouse_x >= 0)
-			moveRightward -= m->ViewScrollSpeed * DeltaTime;
+		if (hotkeys[HOTKEY_CAMERA_PAN])
+		{
+			moveRightward += m->ViewDragSpeed * mouse_dx;
+			moveForward += m->ViewDragSpeed * -mouse_dy;
+		}
 
-		if (g_mouse_y >= g_yres - 2 && g_mouse_y < g_yres)
-			moveForward -= m->ViewScrollSpeed * DeltaTime;
-		else if (g_mouse_y <= 3 && g_mouse_y >= 0)
-			moveForward += m->ViewScrollSpeed * DeltaTime;
-	}
+		if (g_mouse_active)
+		{
+			if (g_mouse_x >= g_xres - 2 && g_mouse_x < g_xres)
+				moveRightward += m->ViewScrollSpeed * DeltaTime;
+			else if (g_mouse_x <= 3 && g_mouse_x >= 0)
+				moveRightward -= m->ViewScrollSpeed * DeltaTime;
 
-	if (hotkeys[HOTKEY_CAMERA_PAN_KEYBOARD])
+			if (g_mouse_y >= g_yres - 2 && g_mouse_y < g_yres)
+				moveForward -= m->ViewScrollSpeed * DeltaTime;
+			else if (g_mouse_y <= 3 && g_mouse_y >= 0)
+				moveForward += m->ViewScrollSpeed * DeltaTime;
+		}
+
+		if (hotkeys[HOTKEY_CAMERA_PAN_KEYBOARD])
+		{
+			if (hotkeys[HOTKEY_CAMERA_RIGHT])
+				moveRightward += m->ViewScrollSpeed * DeltaTime;
+			if (hotkeys[HOTKEY_CAMERA_LEFT])
+				moveRightward -= m->ViewScrollSpeed * DeltaTime;
+			if (hotkeys[HOTKEY_CAMERA_UP])
+				moveForward += m->ViewScrollSpeed * DeltaTime;
+			if (hotkeys[HOTKEY_CAMERA_DOWN])
+				moveForward -= m->ViewScrollSpeed * DeltaTime;
+		}
+
+		if (moveRightward || moveForward)
+		{
+			float s = sin(m->RotateY.GetSmoothedValue());
+			float c = cos(m->RotateY.GetSmoothedValue());
+			m->PosX.AddSmoothly(c * moveRightward);
+			m->PosZ.AddSmoothly(-s * moveRightward);
+			m->PosX.AddSmoothly(s * moveForward);
+			m->PosZ.AddSmoothly(c * moveForward);
+		}
+	} // if(m_cameraFollowingEntity == 0)
+
+	/**
+	 * if camera is in following mode (m_cameraFollowingEntity > 0)
+	 * follow the unit, do not process camera movement actions
+	 * see http://trac.wildfiregames.com/ticket/56 for more description
+	 */
+	else
 	{
-		if (hotkeys[HOTKEY_CAMERA_RIGHT])
-			moveRightward += m->ViewScrollSpeed * DeltaTime;
-		if (hotkeys[HOTKEY_CAMERA_LEFT])
-			moveRightward -= m->ViewScrollSpeed * DeltaTime;
-		if (hotkeys[HOTKEY_CAMERA_UP])
-			moveForward += m->ViewScrollSpeed * DeltaTime;
-		if (hotkeys[HOTKEY_CAMERA_DOWN])
-			moveForward -= m->ViewScrollSpeed * DeltaTime;
-	}
+		debug_assert(m && m->Game && m->Game->GetSimulation2());
 
-	if (moveRightward || moveForward)
-	{
-		float s = sin(m->RotateY.GetSmoothedValue());
-		float c = cos(m->RotateY.GetSmoothedValue());
-		m->PosX.AddSmoothly(c * moveRightward);
-		m->PosZ.AddSmoothly(-s * moveRightward);
-		m->PosX.AddSmoothly(s * moveForward);
-		m->PosZ.AddSmoothly(c * moveForward);
+		CmpPtr<ICmpPosition> cmpPosition(*(m->Game->GetSimulation2()), m_cameraFollowingEntity);
+		if (!cmpPosition.null() && cmpPosition->IsInWorld())
+		{
+			CVector3D pos = cmpPosition->GetInterpolatedTransform(m->Game->GetSimulation2()->GetLastFrameOffset(), false).GetTranslation();
+			// move the camera after unit
+			// use smoothed values of rotation around X and Y, since we need to hold user's rotation done
+			// in this function above
+			CCamera targetCam = m->ViewCamera;
+			targetCam.m_Orientation.SetIdentity();
+			targetCam.m_Orientation.RotateX(m->RotateX.GetSmoothedValue());
+			targetCam.m_Orientation.RotateY(m->RotateY.GetSmoothedValue());
+			targetCam.m_Orientation.Translate(m->PosX.GetValue(), m->PosY.GetValue(), m->PosZ.GetValue());
+
+			CVector3D pivot = targetCam.GetFocus();
+			CVector3D delta = pos - pivot;
+			m->PosX.AddSmoothly(delta.X);
+			m->PosY.AddSmoothly(delta.Y);
+			m->PosZ.AddSmoothly(delta.Z);
+		}
+		else
+			m_cameraFollowingEntity = 0;
 	}
 
 	if (hotkeys[HOTKEY_CAMERA_ZOOM_IN])
@@ -758,6 +795,7 @@
 	}
 	*/
 
+
 	m->RotateY.Wrap(-(float)M_PI, (float)M_PI);
 
 	// Update the camera matrix
@@ -824,6 +862,7 @@
 	m->RotateY.SetValueSmoothly(DEGTORAD(m->ViewRotateYDefault));
 }
 
+
 InReaction game_view_handler(const SDL_Event_* ev)
 {
 	// put any events that must be processed even if inactive here
Index: source/graphics/GameView.h
===================================================================
--- source/graphics/GameView.h	(revision 8124)
+++ source/graphics/GameView.h	(working copy)
@@ -23,6 +23,7 @@
 extern float g_YMinOffset;
 
 #include "renderer/Scene.h"
+#include "simulation2/system/Entity.h"
 
 #include "lib/input.h" // InReaction - can't forward-declare enum
 
@@ -46,6 +47,7 @@
 private:
 	static const float cameraPivotMargin;
 	CGameViewImpl* m;
+	entity_id_t m_cameraFollowingEntity;
 
 	// Check whether lighting environment has changed and update vertex data if necessary
 	void CheckLightEnv();
@@ -85,6 +87,7 @@
 	void MoveCameraTarget(const CVector3D& target);
 	void ResetCameraTarget(const CVector3D& target);
 	void ResetCameraAngleZoom();
+	void CameraFollow(entity_id_t entityid) { m_cameraFollowingEntity = entityid; }
 
 	CCamera *GetCamera();
 	CCinemaManager* GetCinema();
Index: source/simulation2/Simulation2.cpp
===================================================================
--- source/simulation2/Simulation2.cpp	(revision 8124)
+++ source/simulation2/Simulation2.cpp	(working copy)
@@ -277,7 +277,8 @@
 ////////////////////////////////////////////////////////////////
 
 CSimulation2::CSimulation2(CUnitManager* unitManager, CTerrain* terrain) :
-	m(new CSimulation2Impl(unitManager, terrain))
+	m(new CSimulation2Impl(unitManager, terrain)),
+	m_frameOffset(0.0f)
 {
 }
 
@@ -367,6 +368,7 @@
 
 void CSimulation2::Interpolate(float frameLength, float frameOffset)
 {
+	m_frameOffset = frameOffset;
 	m->Interpolate(frameLength, frameOffset);
 }
 
Index: source/simulation2/Simulation2.h
===================================================================
--- source/simulation2/Simulation2.h	(revision 8124)
+++ source/simulation2/Simulation2.h	(working copy)
@@ -155,9 +155,13 @@
 	std::string GenerateSchema();
 
 private:
+	float m_frameOffset;
 	CSimulation2Impl* m;
 
 	NONCOPYABLE(CSimulation2);
+
+public:
+	float GetLastFrameOffset() const { return m_frameOffset; }
 };
 
 #endif // INCLUDED_SIMULATION2
Index: binaries/data/mods/public/maps/scenarios/Combat_demo.xml
===================================================================
--- binaries/data/mods/public/maps/scenarios/Combat_demo.xml	(revision 8124)
+++ binaries/data/mods/public/maps/scenarios/Combat_demo.xml	(working copy)
@@ -372,4 +372,4 @@
 		</Entity>
 	</Entities>
 	<Paths/>
-</Scenario>
\ No newline at end of file
+</Scenario>
Index: binaries/data/mods/public/gui/session_new/session.xml
===================================================================
--- binaries/data/mods/public/gui/session_new/session.xml	(revision 8124)
+++ binaries/data/mods/public/gui/session_new/session.xml	(working copy)
@@ -62,6 +62,11 @@
 		<object hotkey="killUnit">
 			<action on="Press">performCommand(g_Selection.toList()[0], "delete");</action>
 		</object>
+
+		<!-- camera.follow mode - follow the first unit in the selection -->
+		<object hotkey="camera.follow">
+			<action on="Press">performCommand(g_Selection.toList()[0], "camera.follow");</action>
+		</object>
 		
 		<!-- ================================  ================================ -->
 		<!-- Developer / Debug items -->
Index: binaries/data/mods/public/gui/session_new/input.js
===================================================================
--- binaries/data/mods/public/gui/session_new/input.js	(revision 8124)
+++ binaries/data/mods/public/gui/session_new/input.js	(working copy)
@@ -24,6 +24,9 @@
 var placementPosition;
 var placementEntity;
 
+// the unit camera is following for
+var followingEntity = 0;
+
 var mouseX = 0;
 var mouseY = 0;
 var mouseIsOverObject = false;
@@ -730,6 +733,7 @@
 // Performs the specified command (delete, town bell, repair, etc.)
 function performCommand(entity, commandName)
 {
+	// entity depending commands
 	if (entity)
 	{
 		switch (commandName)
@@ -741,4 +745,25 @@
 			break;
 		}
 	}
+
+	// common commands
+	if(commandName == "camera.follow")
+	{
+		var l_followingEntity = 0;
+
+		if(entity)
+		{
+			// stop following mode if it is performing for the same unit
+			var entState = GetEntityState(entity);
+			if (entState && isUnit(entState) && (followingEntity != entity))
+				l_followingEntity = entity;
+		}
+
+		// calling that function with followingEntity = 0 will stop following mode
+		if(l_followingEntity != followingEntity)
+		{
+			followingEntity = l_followingEntity;
+			Engine.CameraFollow(followingEntity);
+		}
+	}
 }
Index: binaries/data/config/default.cfg
===================================================================
--- binaries/data/config/default.cfg	(revision 8124)
+++ binaries/data/config/default.cfg	(working copy)
@@ -113,6 +113,7 @@
 
 ; > CAMERA SETTINGS
 hotkey.camera.reset = "H"					; Reset camera rotation to default.
+hotkey.camera.follow = "F"							; Follow the first unit in the selection
 hotkey.camera.reset.origin = "Ctrl+H"				; Reset camera to origin.
 hotkey.camera.zoom.in = Plus, Equals, NumPlus			; Zoom camera in.
 hotkey.camera.zoom.out = Minus, NumMinus			; Zoom camera out.

