Index: source/tools/atlas/AtlasUI/ScenarioEditor/Tools/SmoothElevation.cpp
===================================================================
--- source/tools/atlas/AtlasUI/ScenarioEditor/Tools/SmoothElevation.cpp	(revision 0)
+++ source/tools/atlas/AtlasUI/ScenarioEditor/Tools/SmoothElevation.cpp	(revision 0)
@@ -0,0 +1,140 @@
+/* Copyright (C) 2009 Wildfire Games.
+ * This file is part of 0 A.D.
+ *
+ * 0 A.D. is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 0 A.D. is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with 0 A.D.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "precompiled.h"
+
+#include "ScenarioEditor/ScenarioEditor.h"
+#include "Common/Tools.h"
+#include "Common/Brushes.h"
+#include "GameInterface/Messages.h"
+
+
+using AtlasMessage::Position;
+
+class SmoothElevation : public StateDrivenTool<SmoothElevation>
+{
+	DECLARE_DYNAMIC_CLASS(SmoothElevation);
+
+	int m_Direction; // +1 = smoother, -1 = rougher
+	Position m_Pos;
+
+public:
+	SmoothElevation()
+	{
+		SetState(&Waiting);
+	}
+
+
+	void OnEnable()
+	{
+		g_Brush_Elevation.MakeActive();
+	}
+
+	void OnDisable()
+	{
+		POST_MESSAGE(BrushPreview, (false, Position()));
+	}
+
+
+	struct sWaiting : public State
+	{
+		bool OnMouse(SmoothElevation* obj, wxMouseEvent& evt)
+		{
+			if (evt.LeftDown())
+			{
+				obj->m_Pos = Position(evt.GetPosition());
+				SET_STATE(Smoothing);
+				return true;
+			}
+			else if (evt.RightDown())
+			{
+				obj->m_Pos = Position(evt.GetPosition());
+				SET_STATE(Roughing);
+				return true;
+			}
+			else if (evt.Moving())
+			{
+				POST_MESSAGE(BrushPreview, (true, Position(evt.GetPosition())));
+				return true;
+			}
+			else
+			{
+				return false;
+			}
+		}
+	}
+	Waiting;
+
+
+	struct sSmoothing_common : public State
+	{
+		void OnEnter(SmoothElevation* obj)
+		{
+			POST_MESSAGE(BrushPreview, (true, obj->m_Pos));
+		}
+
+		void OnLeave(SmoothElevation*)
+		{
+			ScenarioEditor::GetCommandProc().FinaliseLastCommand();
+		}
+
+		bool OnMouse(SmoothElevation* obj, wxMouseEvent& evt)
+		{
+			if (IsMouseUp(evt))
+			{
+				SET_STATE(Waiting);
+				return true;
+			}
+			else if (evt.Dragging())
+			{
+				wxPoint pos = evt.GetPosition();
+				obj->m_Pos = Position(pos);
+				POST_MESSAGE(BrushPreview, (true, obj->m_Pos));
+				return true;
+			}
+			else
+			{
+				return false;
+			}
+		}
+
+		void OnTick(SmoothElevation* obj, float dt)
+		{
+			POST_COMMAND(SmoothElevation, (obj->m_Pos, dt*4096.f*GetDirection()*g_Brush_Elevation.GetStrength()));
+			obj->m_Pos = Position::Unchanged();
+		}
+
+		virtual bool IsMouseUp(wxMouseEvent& evt) = 0;
+		virtual int GetDirection() = 0;
+	};
+
+	struct sSmoothing : public sSmoothing_common
+	{
+		bool IsMouseUp(wxMouseEvent& evt) { return evt.LeftUp(); }
+		int GetDirection() { return +1; }
+	}
+	Smoothing;
+
+	struct sRoughing : public sSmoothing_common
+	{
+		bool IsMouseUp(wxMouseEvent& evt) { return evt.RightUp(); }
+		int GetDirection() { return -1; }
+	}
+	Roughing;
+};
+
+IMPLEMENT_DYNAMIC_CLASS(SmoothElevation, StateDrivenTool<SmoothElevation>);
Index: source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Terrain/Terrain.cpp
===================================================================
--- source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Terrain/Terrain.cpp	(revision 7843)
+++ source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Terrain/Terrain.cpp	(working copy)
@@ -56,6 +56,7 @@
 	{
 		wxSizer* sizer = new wxStaticBoxSizer(wxHORIZONTAL, this, _("Elevation tools"));
 		sizer->Add(new ToolButton(scenarioEditor.GetToolManager(), this, _("Modify"), _T("AlterElevation"), wxSize(50,20)));
+		sizer->Add(new ToolButton(scenarioEditor.GetToolManager(), this, _("Smooth"), _T("SmoothElevation"), wxSize(50,20)));
 		sizer->Add(new ToolButton(scenarioEditor.GetToolManager(), this, _("Flatten"), _T("FlattenElevation"), wxSize(50,20)));
 //		sizer->Add(new ToolButton(scenarioEditor.GetToolManager(), this, _("Smooth"), _T(""), wxSize(50,20)));
 //		sizer->Add(new ToolButton(scenarioEditor.GetToolManager(), this, _("Sample"), _T(""), wxSize(50,20)));
Index: source/tools/atlas/AtlasUI/ScenarioEditor/ScenarioEditor.cpp
===================================================================
--- source/tools/atlas/AtlasUI/ScenarioEditor/ScenarioEditor.cpp	(revision 7843)
+++ source/tools/atlas/AtlasUI/ScenarioEditor/ScenarioEditor.cpp	(working copy)
@@ -474,6 +474,7 @@
 	toolbar->AddToolButton(_("Default"),       _("Default"),                   _T("default.png"),          _T(""),                 _T(""));
 	toolbar->AddToolButton(_("Move"),          _("Move/rotate object"),        _T("moveobject.png"),       _T("TransformObject"),  _T("")/*_T("ObjectSidebar")*/);
 	toolbar->AddToolButton(_("Elevation"),     _("Alter terrain elevation"),   _T("alterelevation.png"),   _T("AlterElevation"),   _T("")/*_T("TerrainSidebar")*/);
+	toolbar->AddToolButton(_("Smooth"),        _("Smooth terrain elevation"),   _T("alterelevation.png"),   _T("SmoothElevation"),   _T("")/*_T("TerrainSidebar")*/);
 	toolbar->AddToolButton(_("Flatten"),       _("Flatten terrain elevation"), _T("flattenelevation.png"), _T("FlattenElevation"), _T("")/*_T("TerrainSidebar")*/);
 	toolbar->AddToolButton(_("Paint Terrain"), _("Paint terrain texture"),     _T("paintterrain.png"),     _T("PaintTerrain"),     _T("")/*_T("TerrainSidebar")*/);
 
Index: source/tools/atlas/GameInterface/Messages.h
===================================================================
--- source/tools/atlas/GameInterface/Messages.h	(revision 7843)
+++ source/tools/atlas/GameInterface/Messages.h	(working copy)
@@ -372,6 +372,11 @@
 		((float, amount))
 		);
 
+COMMAND(SmoothElevation, MERGE,
+		((Position, pos))
+		((float, amount))
+		);
+
 COMMAND(FlattenElevation, MERGE,
 		((Position, pos))
 		((float, amount))
Index: source/tools/atlas/GameInterface/Handlers/ElevationHandlers.cpp
===================================================================
--- source/tools/atlas/GameInterface/Handlers/ElevationHandlers.cpp	(revision 7843)
+++ source/tools/atlas/GameInterface/Handlers/ElevationHandlers.cpp	(working copy)
@@ -178,7 +178,127 @@
 END_COMMAND(AlterElevation)
 
 //////////////////////////////////////////////////////////////////////////
+	
+BEGIN_COMMAND(SmoothElevation)
+{
+	TerrainArray m_TerrainDelta;
+	ssize_t m_i0, m_j0, m_i1, m_j1;
 
+	cSmoothElevation()
+	{
+		m_TerrainDelta.Init();
+	}
+
+	void MakeDirty()
+	{
+		g_Game->GetWorld()->GetTerrain()->MakeDirty(m_i0, m_j0, m_i1, m_j1, RENDERDATA_UPDATE_VERTICES);
+		CmpPtr<ICmpTerrain> cmpTerrain(*g_Game->GetSimulation2(), SYSTEM_ENTITY);
+		if (!cmpTerrain.null())
+			cmpTerrain->MakeDirty(m_i0, m_j0, m_i1, m_j1);
+	}
+
+	void Do()
+	{
+		int amount = (int)msg->amount;
+
+		printf("amount = %d\n", amount);
+
+		// If the framerate is very high, 'amount' is often very
+		// small (even zero) so the integer truncation is significant
+		static float roundingError = 0.0;
+		roundingError += msg->amount - (float)amount;
+		if (roundingError >= 1.f)
+		{
+			amount += (int)roundingError;
+			roundingError -= (float)(int)roundingError;
+		}
+
+		static CVector3D previousPosition;
+		g_CurrentBrush.m_Centre = msg->pos->GetWorldSpace(previousPosition);
+		previousPosition = g_CurrentBrush.m_Centre;
+
+		ssize_t x0, y0;
+		g_CurrentBrush.GetBottomLeft(x0, y0);
+
+		if (g_CurrentBrush.m_H > 2)
+		{
+			int num = (g_CurrentBrush.m_H - 2) * (g_CurrentBrush.m_W-2);
+			float *terrainDeltas = (float*)calloc(num, sizeof(float));
+
+			for (ssize_t dy = 0; dy < g_CurrentBrush.m_H; ++dy)
+			{
+				for (ssize_t dx = 0; dx < g_CurrentBrush.m_W; ++dx)
+				{
+					//float b = g_CurrentBrush.Get(dx, dy) * m_TerrainDelta.GetVertex(x0+dx,y0+dy);
+					float b = m_TerrainDelta.GetVertex(x0+dx,y0+dy);
+					
+					if (b)
+					{
+						float delta = b / 9.0;
+						int x1_min = std::max(1, dx - 1);
+						int x1_max = std::min(dx + 1, g_CurrentBrush.m_W - 2);
+						int y1_min = std::max(1, dy - 1);
+						int y1_max = std::min(dy + 1, g_CurrentBrush.m_H - 2);
+
+
+						for(int yy = y1_min; yy <= y1_max; yy ++)
+						{
+							for(int xx = x1_min;xx <= x1_max; xx ++)
+							{
+								int index =(yy-1)*(g_CurrentBrush.m_W-2) + (xx-1);
+								terrainDeltas[index] += delta;
+							}
+						}
+					}
+				}
+			}
+			for (ssize_t dy = 1; dy < g_CurrentBrush.m_H - 1; ++dy)
+			{
+				for (ssize_t dx = 1; dx < g_CurrentBrush.m_W - 1; ++dx)
+				{
+					int index =(dy-1)*(g_CurrentBrush.m_W-2) + (dx-1);
+					float b = terrainDeltas[index]; 
+					if (b)
+						m_TerrainDelta.MoveVertexTowards(x0+dx, y0+dy, (int)b, (int)(amount*g_CurrentBrush.Get(dx,dy)));
+				}
+			}
+
+			free(terrainDeltas);
+		}
+
+		m_i0 = x0;
+		m_j0 = y0;
+		m_i1 = x0 + g_CurrentBrush.m_W;
+		m_j1 = y0 + g_CurrentBrush.m_H;
+		MakeDirty();
+	}
+
+	void Undo()
+	{
+		m_TerrainDelta.Undo();
+		MakeDirty();
+	}
+
+	void Redo()
+	{
+		m_TerrainDelta.Redo();
+		MakeDirty();
+	}
+
+	void MergeIntoPrevious(cSmoothElevation* prev)
+	{
+		prev->m_TerrainDelta.OverlayWith(m_TerrainDelta);
+		prev->m_i0 = std::min(prev->m_i0, m_i0);
+		prev->m_j0 = std::min(prev->m_j0, m_j0);
+		prev->m_i1 = std::max(prev->m_i1, m_i1);
+		prev->m_j1 = std::max(prev->m_j1, m_j1);
+	}
+};
+END_COMMAND(SmoothElevation)
+
+//////////////////////////////////////////////////////////////////////////
+
+
 BEGIN_COMMAND(FlattenElevation)
 {
 	TerrainArray m_TerrainDelta;
Index: source/lib/res/sound/ogg.cpp
===================================================================
--- source/lib/res/sound/ogg.cpp	(revision 7843)
+++ source/lib/res/sound/ogg.cpp	(working copy)
@@ -92,7 +92,7 @@
 			NODEFAULT;
 		}
 
-		adapter->offset = Clamp(origin+offset, off_t(0), adapter->size);
+		adapter->offset = Clamp(off_t(origin+offset), off_t(0), adapter->size);
 		return 0;
 	}
 
Index: binaries/data/tools/atlas/scripts/section/terrain.js
===================================================================
--- binaries/data/tools/atlas/scripts/section/terrain.js	(revision 7840)
+++ binaries/data/tools/atlas/scripts/section/terrain.js	(working copy)
@@ -129,6 +129,7 @@
 		
 	var tools = [
 		{ label: 'Modify', name: 'AlterElevation' },
+		{ label: 'Smooth', name: 'SmoothElevation' },
 		{ label: 'Flatten', name: 'FlattenElevation' },
 		{ label: 'Paint', name: 'PaintTerrain' },
 	];
