Index: source/tools/atlas/AtlasUI/ScenarioEditor/Tools/TransformObject.cpp
===================================================================
--- source/tools/atlas/AtlasUI/ScenarioEditor/Tools/TransformObject.cpp	(revision 16234)
+++ source/tools/atlas/AtlasUI/ScenarioEditor/Tools/TransformObject.cpp	(working copy)
@@ -300,16 +300,9 @@
 
 				return true;
 			}
-			else if (g_SelectedObjects.size() == 1 && ((evt.Dragging() && evt.RightIsDown()) || evt.RightDown()))
+			else if (!g_SelectedObjects.empty() && ((evt.Dragging() && evt.RightIsDown()) || evt.RightDown()))
 			{
-				// TODO: Rotation of selections with multiple objects?
-
-				// Dragging with right mouse button -> rotate objects to look
-				// at mouse
-				Position pos(evt.GetPosition());
-				for (size_t i = 0; i < g_SelectedObjects.size(); ++i)
-					POST_COMMAND(RotateObject, (g_SelectedObjects[i], true, pos, 0.f));
-
+				SET_STATE(Rotating);
 				return true;
 			}
 			else if (evt.Moving())
@@ -556,6 +550,63 @@
 		}
 	}
 	Pasting;
+
+	struct sRotating : public State
+	{
+		bool rotateFromCenterPoint;
+
+		void OnEnter(TransformObject* WXUNUSED(obj))
+		{
+			rotateFromCenterPoint = true;
+		}
+
+		bool OnMouse(TransformObject* obj, wxMouseEvent& evt)
+		{
+			if (evt.RightUp())
+			{
+				POST_MESSAGE(ResetSelectionColor, ());
+				SET_STATE(Waiting);
+				return true;
+			}
+			else if (evt.Dragging())
+			{
+				bool newRotateFromCenterPointAndObjectItself = !evt.ControlDown() && !evt.ShiftDown();
+				bool newRotateFromCenterPoint = evt.ShiftDown() || newRotateFromCenterPointAndObjectItself;
+				if (newRotateFromCenterPoint != rotateFromCenterPoint)
+				{
+					ScenarioEditor::GetCommandProc().FinaliseLastCommand();
+					rotateFromCenterPoint = newRotateFromCenterPoint;
+				}
+
+				Position pos(evt.GetPosition());
+
+				if (rotateFromCenterPoint)
+					POST_COMMAND(RotateObjectsFromCenterPoint, (g_SelectedObjects, pos, newRotateFromCenterPointAndObjectItself));
+				else
+					POST_COMMAND(RotateObject, (g_SelectedObjects, pos));
+
+				return true;
+			}
+
+			return false;
+		}
+
+		bool OnKey(TransformObject* obj, wxKeyEvent& evt, KeyEventType type)
+		{
+			if (type == KEY_UP && evt.GetKeyCode() == WXK_ESCAPE)
+			{
+				// Cancel move action
+				ScenarioEditor::GetCommandProc().FinaliseLastCommand();
+				ScenarioEditor::GetCommandProc().Undo();
+				SET_STATE(Waiting);
+
+				return true;
+			}
+
+			return false;
+		}
+	}
+	Rotating;
 };
 
 IMPLEMENT_DYNAMIC_CLASS(TransformObject, StateDrivenTool<TransformObject>);
Index: source/tools/atlas/GameInterface/Handlers/ObjectHandlers.cpp
===================================================================
--- source/tools/atlas/GameInterface/Handlers/ObjectHandlers.cpp	(revision 16234)
+++ source/tools/atlas/GameInterface/Handlers/ObjectHandlers.cpp	(working copy)
@@ -811,40 +813,188 @@
 };
 END_COMMAND(MoveObjects)
 
+BEGIN_COMMAND(RotateObjectsFromCenterPoint)
+{
+	typedef std::map<entity_id_t, CVector3D> ObjectPositionMap;
+	typedef std::map<entity_id_t, float> ObjectAngleMap;
+	ObjectPositionMap m_PosOld, m_PosNew;
+	ObjectAngleMap m_AngleOld, m_AngleNew;
+	CVector3D m_CenterPoint;
+	float m_AngleInitialRotation;
 
+	void Do()
+	{
+		std::vector<entity_id_t> ids = *msg->ids;
+
+		CVector3D minPos;
+		CVector3D maxPos;
+
+		//getting min position and max position
+		for (size_t i = 0; i < ids.size(); ++i)
+		{
+			entity_id_t id = ids[i];
+
+			CmpPtr<ICmpPosition> cmpPosition(*g_Game->GetSimulation2(), id);
+			if (!cmpPosition)
+				continue;
+
+			CVector3D pos = cmpPosition->GetPosition();
+
+			m_PosOld[id] = cmpPosition->GetPosition();
+			m_AngleOld[id] = cmpPosition->GetRotation().Y.ToFloat();
+
+			if (i == 0) {
+				minPos = pos;
+				maxPos = pos;
+				m_CenterPoint.Y = pos.Y;
+				continue;
+			}
+
+			if (pos.X < minPos.X)
+				minPos.X = pos.X;
+
+			if (pos.X > maxPos.X)
+				maxPos.X = pos.X;
+
+			if (pos.Z < minPos.Z)
+				minPos.Z = pos.Z;
+
+			if (pos.Z > maxPos.Z)
+				maxPos.Z = pos.Z;
+		}
+
+		//Calculate objects center point
+		m_CenterPoint.X = maxPos.X - ((maxPos.X - minPos.X) * 0.5);
+		m_CenterPoint.Z = maxPos.Z - ((maxPos.Z - minPos.Z) * 0.5);
+
+		CVector3D target = msg->target->GetWorldSpace(m_CenterPoint.Y);
+		m_AngleInitialRotation = atan2(target.X-m_CenterPoint.X, target.Z-m_CenterPoint.Z);
+	}
+
+	void SetPos(ObjectPositionMap position)
+	{
+		ObjectPositionMap::iterator it;
+		for (it = position.begin(); it != position.end(); ++it)
+		{
+			entity_id_t id = it->first;
+			CmpPtr<ICmpPosition> cmpPosition(*g_Game->GetSimulation2(), id);
+			if (!cmpPosition)
+				return;
+
+			// Set 2D position, ignoring height
+			CVector3D pos = it->second;
+			cmpPosition->JumpTo(entity_pos_t::FromFloat(pos.X), entity_pos_t::FromFloat(pos.Z));
+
+			if (msg->rotateObject)
+				cmpPosition->SetYRotation(entity_angle_t::FromFloat(m_AngleNew[id]));
+
+		}
+
+		for (it = position.begin(); it != position.end(); ++it)
+			CheckObstructionAndUpdateVisual(it->first);
+	}
+
+	void Redo()
+	{
+		SetPos(m_PosNew);
+	}
+
+	void RecalculateRotation(Position newPoint)
+	{
+		std::vector<entity_id_t> ids = *msg->ids;
+
+		CVector3D target = newPoint.GetWorldSpace(m_CenterPoint.Y);
+		float newAngle = atan2(target.X-m_CenterPoint.X, target.Z-m_CenterPoint.Z);
+
+		float globalAngle = m_AngleInitialRotation - newAngle;
+
+		//Recalculate positions
+		for (size_t i = 0; i < ids.size(); ++i)
+		{
+			entity_id_t id = ids[i];
+
+			CVector3D pos = m_PosOld[id];
+			float angle = atan2(pos.X - m_CenterPoint.X, pos.Z - m_CenterPoint.Z);
+			float localAngle = angle + (globalAngle - angle);
+			float xCos = cosf(localAngle);
+			float xSin = sinf(localAngle);
+
+			pos.X -= m_CenterPoint.X;
+			pos.Z -= m_CenterPoint.Z;
+
+			float newX = pos.X * xCos - pos.Z * xSin;
+			float newZ = pos.X * xSin + pos.Z * xCos;
+
+			pos.X = newX + m_CenterPoint.X;
+			pos.Z = newZ + m_CenterPoint.Z;
+
+			m_PosNew[id] = pos;
+
+			m_AngleNew[id] = m_AngleOld[id] - globalAngle;
+		}
+
+		SetPos(m_PosNew);
+	}
+
+	void Undo()
+	{
+		SetPos(m_PosOld);
+	}
+
+	void MergeIntoPrevious(cRotateObjectsFromCenterPoint* prev)
+	{
+		// TODO: do something valid if prev unit != this unit
+		ENSURE(*prev->msg->ids == *msg->ids);
+		m_PosOld = prev->m_PosOld;
+		m_AngleInitialRotation = prev->m_AngleInitialRotation;
+		m_AngleOld = prev->m_AngleOld;
+		m_CenterPoint = prev->m_CenterPoint;
+
+		RecalculateRotation(msg->target);
+	}
+};
+END_COMMAND(RotateObjectsFromCenterPoint)
+
 BEGIN_COMMAND(RotateObject)
 {
-	float m_AngleOld, m_AngleNew;
+	typedef std::map<entity_id_t, float> ObjectAngleMap;
+	ObjectAngleMap m_AngleOld, m_AngleNew;
 
 	void Do()
 	{
-		CmpPtr<ICmpPosition> cmpPosition(*g_Game->GetSimulation2(), (entity_id_t)msg->id);
-		if (!cmpPosition)
-			return;
+		std::vector<entity_id_t> ids = *msg->ids;
 
-		m_AngleOld = cmpPosition->GetRotation().Y.ToFloat();
-		if (msg->usetarget)
+		for (size_t i = 0; i < ids.size(); ++i)
 		{
+			entity_id_t id = (entity_id_t)ids[i];
+
+			CmpPtr<ICmpPosition> cmpPosition(*g_Game->GetSimulation2(), id);
+			if (!cmpPosition)
+				return;
+
+			m_AngleOld[id] = cmpPosition->GetRotation().Y.ToFloat();
+
 			CMatrix3D transform = cmpPosition->GetInterpolatedTransform(0.f);
 			CVector3D pos = transform.GetTranslation();
 			CVector3D target = msg->target->GetWorldSpace(pos.Y);
-			m_AngleNew = atan2(target.X-pos.X, target.Z-pos.Z);
+			m_AngleNew[id] = atan2(target.X-pos.X, target.Z-pos.Z);
 		}
-		else
-		{
-			m_AngleNew = msg->angle;
-		}
 
 		SetAngle(m_AngleNew);
 	}
 
-	void SetAngle(float angle)
+	void SetAngle(ObjectAngleMap angles)
 	{
-		CmpPtr<ICmpPosition> cmpPosition(*g_Game->GetSimulation2(), (entity_id_t)msg->id);
-		if (!cmpPosition)
-			return;
+		ObjectAngleMap::iterator it;
+		for (it = angles.begin(); it != angles.end(); ++it)
+		{
+			entity_id_t id = (entity_id_t)it->first;
+			CmpPtr<ICmpPosition> cmpPosition(*g_Game->GetSimulation2(), id);
+			if (!cmpPosition)
+				return;
 
-		cmpPosition->SetYRotation(entity_angle_t::FromFloat(angle));
+			cmpPosition->SetYRotation(entity_angle_t::FromFloat(it->second));
+		}
 	}
 
 	void Redo()
@@ -860,7 +1010,7 @@
 	void MergeIntoPrevious(cRotateObject* prev)
 	{
 		// TODO: do something valid if prev unit != this unit
-		ENSURE(prev->msg->id == msg->id);
+		ENSURE(*prev->msg->ids == *msg->ids);
 		prev->m_AngleNew = m_AngleNew;
 	}
 };
Index: source/tools/atlas/GameInterface/Messages.h
===================================================================
--- source/tools/atlas/GameInterface/Messages.h	(revision 16234)
+++ source/tools/atlas/GameInterface/Messages.h	(working copy)
@@ -581,11 +596,15 @@
 		((Position, pos))
 		);
 
+COMMAND(RotateObjectsFromCenterPoint, MERGE,
+		((std::vector<ObjectID>, ids))
+		((Position, target))
+		((bool, rotateObject))
+		);
+
 COMMAND(RotateObject, MERGE,
-		((ObjectID, id))
-		((bool, usetarget)) // true => use 'target' for orientation; false => use 'angle'
+		((std::vector<ObjectID>, ids))
 		((Position, target))
-		((float, angle))
 		);
 
 COMMAND(DeleteObjects, NOMERGE,
