Index: source/simulation2/components/ICmpTerrainModifier.h
===================================================================
--- source/simulation2/components/ICmpTerrainModifier.h (revision 0)
+++ source/simulation2/components/ICmpTerrainModifier.h (working copy)
@@ -0,0 +1,35 @@
+/* Copyright (C) 2014 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 .
+ */
+
+#ifndef INCLUDED_ICMPTERRAINMODIFIER
+#define INCLUDED_ICMPTERRAINMODIFIER
+
+#include "simulation2/system/Interface.h"
+
+/**
+ * Handles terrain changes around an entity
+ * Currently only handles flattening on building placement.
+ */
+class ICmpTerrainModifier : public IComponent
+{
+public:
+ virtual void ApplyTerrainModification() = 0;
+
+ DECLARE_INTERFACE_TYPE(TerrainModifier)
+};
+
+#endif // INCLUDED_ICMPTERRAINMODIFIER
Property changes on: source/simulation2/components/ICmpTerrainModifier.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Index: source/simulation2/components/CCmpTerrainModifier.cpp
===================================================================
--- source/simulation2/components/CCmpTerrainModifier.cpp (revision 0)
+++ source/simulation2/components/CCmpTerrainModifier.cpp (working copy)
@@ -0,0 +1,304 @@
+/* Copyright (C) 2013 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 .
+ */
+
+#include "precompiled.h"
+
+#include "simulation2/system/Component.h"
+#include "ICmpTerrainModifier.h"
+
+#include "graphics/Terrain.h"
+#include "ps/CLogger.h"
+#include "simulation2/MessageTypes.h"
+#include "simulation2/serialization/SerializeTemplates.h"
+
+#include "simulation2/components/ICmpFootprint.h"
+#include "simulation2/components/ICmpPosition.h"
+#include "simulation2/components/ICmpTerrain.h"
+#include "simulation2/helpers/Geometry.h"
+
+
+/**
+ * Handles terrain changes around an entity
+ * Currently only handles flattening on building placement.
+ */
+class CCmpTerrainModifier : public ICmpTerrainModifier
+{
+private:
+ // used to expand outwards.
+ struct Point {
+ Point() : X(0), Y(0), parentX(0), parentY(0), generation(1), originalHeight(0)
+ { }
+ Point(int x, int y, u16 height) : X(x), Y(y), parentX(x), parentY(y), generation(1), originalHeight(height)
+ {}
+ Point(int x, int y, int px, int py, int Generation, u16 height) : X(x), Y(y), parentX(px), parentY(py), generation(Generation), originalHeight(height)
+ {}
+
+ int X,Y;
+ int parentX,parentY;
+ int generation;
+ u16 originalHeight;
+ };
+
+public:
+ static void ClassInit(CComponentManager& componentManager)
+ {
+ componentManager.SubscribeToMessageType(MT_Destroy);
+ }
+
+ DEFAULT_COMPONENT_ALLOCATOR(TerrainModifier)
+
+ // Dynamic state:
+
+ static std::string GetSchema()
+ {
+ return
+ ""
+ "Causes the entity to flatten the terrain when placed on the map, if possible."
+ "";
+ }
+
+ virtual void Init(const CParamNode& UNUSED(paramNode))
+ {
+ }
+
+ virtual void Deinit()
+ {
+ }
+
+ template
+ void SerializeCommon(S& UNUSED(serialize))
+ {
+ }
+
+ virtual void Serialize(ISerializer& serialize)
+ {
+ SerializeCommon(serialize);
+ }
+
+ virtual void Deserialize(const CParamNode& paramNode, IDeserializer& deserialize)
+ {
+ Init(paramNode);
+
+ SerializeCommon(deserialize);
+ }
+
+ virtual void HandleMessage(const CMessage& msg, bool UNUSED(global))
+ {
+ switch (msg.GetType())
+ {
+ case MT_Destroy:
+ {
+ break;
+ }
+ }
+ }
+
+ // Try to modifiy the terrain around us.
+ virtual void ApplyTerrainModification()
+ {
+ FlattenTerrainAroundCenter();
+ }
+
+ // Flatten the terrain around us.
+ void FlattenTerrainAroundCenter()
+ {
+ CmpPtr cmpPosition(GetEntityHandle());
+ if (!cmpPosition)
+ return;
+
+ CmpPtr cmpTerrain(GetSystemEntity());
+ if (!cmpTerrain)
+ return;
+
+ CmpPtr cmpFootprint(GetEntityHandle());
+ if (!cmpFootprint)
+ return;
+
+ // grab the shape and dimensions of the footprint
+ entity_pos_t footprintSize0, footprintSize1, footprintHeight;
+ ICmpFootprint::EShape footprintShape;
+ cmpFootprint->GetShape(footprintShape, footprintSize0, footprintSize1, footprintHeight);
+
+ CFixedVector2D position = cmpPosition->GetPosition2D();
+
+ fixed originX = (position.X/4);
+ fixed originY = (position.Y/4);
+ int posX = originX.ToInt_RoundToZero();
+ int posY = originY.ToInt_RoundToZero();
+
+ // copy the heightmap
+ CTerrain* terrain = cmpTerrain->GetCTerrain();
+ ssize_t width = terrain->GetVerticesPerSide();
+ u16* heightmap = terrain->GetHeightMap();
+
+ // we'll be hotmodifying the heightmap.
+
+ /* Algorithm is somewhat simple:
+ * We start from the 4 vertices surrounding the center point
+ * For each vertice
+ * If we've already been added to the closed list, we remove us from the open list
+ * Depending on the quadrant (of a circle around the center point) they are in, we add 2 points that go away from the center
+ */
+#define tou16(a) (a*(int)HEIGHT_UNITS_PER_METRE).ToInt_RoundToNearest();
+
+ u16 originalHeight = tou16(terrain->GetExactGroundLevelFixed(position.X,position.Y));
+
+ // let's actually flatten the terrain.
+ // So what we actually need here is to be quite sure we don't make a passable tile impassable.
+ // because that has all sorts of weird gameplay side-effects which we do not want.
+ // so we need to refrain from moving vertices too much.
+
+ // define the 4 corners as base pixels. I'll assume we can't be exactly on a point here, which probably holds true.
+ std::vector openList;
+
+ std::stack lastPoints;
+
+ // acts as a global list of points I've studied.
+ std::map, Point> closedList;
+
+ Point basePointA(posX,posY, originalHeight);
+ Point basePointB(posX,posY+1, originalHeight);
+ Point basePointC(posX+1,posY, originalHeight);
+ Point basePointD(posX+1,posY+1, originalHeight);
+ openList.push_back(basePointA);
+ openList.push_back(basePointB);
+ openList.push_back(basePointC);
+ openList.push_back(basePointD);
+
+
+ // for each base pixel on the openList, update
+ while (openList.size() > 0)
+ {
+ Point curPoint = openList[0];
+ // disregard already moved points or points not on the map (includes the edges, so we don't need to clamp)
+ if (closedList.find(std::make_pair(curPoint.X,curPoint.Y)) != closedList.end())
+ {
+ openList.erase(openList.begin());
+ continue;
+ }
+ if (curPoint.X <= 0 || curPoint.X >= width-1
+ || curPoint.Y <= 0 || curPoint.Y >= width-1)
+ {
+ lastPoints.push(curPoint);
+ closedList[std::make_pair(curPoint.X,curPoint.Y)] = curPoint;
+ openList.erase(openList.begin());
+ continue;
+ }
+
+ CFixedVector2D path(fixed::FromInt(curPoint.X) - originX,fixed::FromInt(curPoint.Y) - originY);
+ fixed distance = path.Length();
+
+ // if we're too far away
+ if (distance > footprintSize0/2)
+ {
+ lastPoints.push(curPoint);
+ closedList[std::make_pair(curPoint.X,curPoint.Y)] = curPoint;
+ openList.erase(openList.begin());
+ continue;
+ }
+ else if(distance >= footprintSize0/5 && abs(heightmap[curPoint.X + curPoint.Y*width] - originalHeight) < 175)
+ {
+ // here we're not under the foundation and it's still flat, so disregard going further.
+ lastPoints.push(curPoint);
+ closedList[std::make_pair(curPoint.X,curPoint.Y)] = curPoint;
+ openList.erase(openList.begin());
+ continue;
+
+ }
+
+ path.Normalize();
+
+#define checkHeight(X,Y,changeX,changeY) abs(heightmap[X+changeX + (Y+changeY)*width]-heightmap[X + Y*width]) < 4000
+#define addPoint(id, X,Y,changeX,changeY, generation) id = Point(X+changeX,Y+changeY,X,Y,generation, heightmap[X+changeX + (Y+changeY)*width]);\
+++addedPoints;\
+openList.push_back(id);
+
+ int newSquares[2][2] = { {0,0}, {0,0}};
+
+ if (path.X <= fixed::Zero() && path.Y <= fixed::Zero())
+ {
+ // lower left quadrant
+ newSquares[0][0] = -1;
+ newSquares[1][1] = -1;
+ }
+ else if (path.X <= fixed::Zero() && path.Y >= fixed::Zero())
+ {
+ // upper left quadrant
+ newSquares[0][0] = -1;
+ newSquares[1][1] = +1;
+ }
+ else if (path.X >= fixed::Zero() && path.Y <= fixed::Zero())
+ {
+ // lower right quadrant
+ newSquares[0][0] = +1;
+ newSquares[1][1] = -1;
+ }
+ else if (path.X >= fixed::Zero() && path.Y >= fixed::Zero())
+ {
+ // upper right quadrant
+ newSquares[0][0] = +1;
+ newSquares[1][1] = +1;
+ }
+ int generation = 1;
+ if(distance >= footprintSize0/5 && distance <= footprintSize0/2)
+ generation = curPoint.generation+1;
+
+ int addedPoints = 0;
+ Point newA;
+ Point newB;
+ // let's check that the slope isn't too big in that direction.
+ if (checkHeight(curPoint.X,curPoint.Y,newSquares[0][0],newSquares[0][1]))
+ addPoint(newA,curPoint.X,curPoint.Y,newSquares[0][0],newSquares[0][1], generation);
+ if (checkHeight(curPoint.X,curPoint.Y,newSquares[1][0],newSquares[1][1]))
+ addPoint(newB,curPoint.X,curPoint.Y,newSquares[1][0],newSquares[1][1], generation);
+
+#undef addPoint
+#undef checkHeight
+ if (addedPoints == 0)
+ lastPoints.push(curPoint);
+
+ closedList[std::make_pair(curPoint.X,curPoint.Y)] = curPoint;
+ openList.erase(openList.begin());
+ }
+ // Now for each point, we'll move towards the last parent, flattening a bit each time.
+ // we'll do it linearly for now, since we now of many points we'll go through till the center.
+ while (lastPoints.size() > 0)
+ {
+ Point curPoint = lastPoints.top();
+ lastPoints.pop();
+ int startGeneration = curPoint.generation;
+ do
+ {
+ u16 myHeight = curPoint.originalHeight;
+ // target height is original height
+ fixed coeff = fixed::FromInt(curPoint.generation) / startGeneration;
+ fixed height = coeff * (int)myHeight;
+ height += (fixed::FromInt(1) - coeff) * (int)originalHeight;
+ heightmap[width*curPoint.Y + curPoint.X] = height.ToInt_RoundToNearest();
+
+ curPoint = closedList.find(std::make_pair(curPoint.parentX,curPoint.parentY))->second;
+ } while(curPoint.X != curPoint.parentX || curPoint.Y != curPoint.parentY);
+ }
+
+ // upload the modified heightmap.
+ terrain->SetHeightMap(heightmap);
+ cmpTerrain->MakeDirty(position.X.ToInt_RoundToZero(), position.X.ToInt_RoundToInfinity(),
+ position.Y.ToInt_RoundToZero(), position.Y.ToInt_RoundToInfinity());
+ }
+};
+
+REGISTER_COMPONENT_TYPE(TerrainModifier)
Property changes on: source/simulation2/components/CCmpTerrainModifier.cpp
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Index: source/simulation2/components/ICmpTerrainModifier.cpp
===================================================================
--- source/simulation2/components/ICmpTerrainModifier.cpp (revision 0)
+++ source/simulation2/components/ICmpTerrainModifier.cpp (working copy)
@@ -0,0 +1,37 @@
+/* Copyright (C) 2014 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 .
+ */
+
+#include "precompiled.h"
+
+#include "ICmpTerrainModifier.h"
+
+#include "simulation2/system/InterfaceScripted.h"
+#include "simulation2/system/SimContext.h"
+
+BEGIN_INTERFACE_WRAPPER(TerrainModifier)
+DEFINE_INTERFACE_METHOD_0("ApplyTerrainModification", void, ICmpTerrainModifier, ApplyTerrainModification)
+/*DEFINE_INTERFACE_METHOD_2("CheckFoundation", std::string, ICmpObstruction, CheckFoundation_wrapper, std::string, bool)
+DEFINE_INTERFACE_METHOD_0("CheckDuplicateFoundation", bool, ICmpObstruction, CheckDuplicateFoundation)
+DEFINE_INTERFACE_METHOD_2("GetEntityCollisions", std::vector, ICmpObstruction, GetEntityCollisions, bool, bool)
+DEFINE_INTERFACE_METHOD_1("SetActive", void, ICmpObstruction, SetActive, bool)
+DEFINE_INTERFACE_METHOD_3("SetDisableBlockMovementPathfinding", void, ICmpObstruction, SetDisableBlockMovementPathfinding, bool, bool, int32_t)
+DEFINE_INTERFACE_METHOD_0("GetBlockMovementFlag", bool, ICmpObstruction, GetBlockMovementFlag)
+DEFINE_INTERFACE_METHOD_1("SetControlGroup", void, ICmpObstruction, SetControlGroup, entity_id_t)
+DEFINE_INTERFACE_METHOD_0("GetControlGroup", entity_id_t, ICmpObstruction, GetControlGroup)
+DEFINE_INTERFACE_METHOD_1("SetControlGroup2", void, ICmpObstruction, SetControlGroup2, entity_id_t)
+DEFINE_INTERFACE_METHOD_0("GetControlGroup2", entity_id_t, ICmpObstruction, GetControlGroup2)
+*/END_INTERFACE_WRAPPER(TerrainModifier)
Property changes on: source/simulation2/components/ICmpTerrainModifier.cpp
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Index: binaries/data/mods/public/simulation/helpers/Commands.js
===================================================================
--- binaries/data/mods/public/simulation/helpers/Commands.js (revision 14730)
+++ binaries/data/mods/public/simulation/helpers/Commands.js (working copy)
@@ -876,6 +876,12 @@
var cmpFoundation = Engine.QueryInterface(ent, IID_Foundation);
cmpFoundation.InitialiseConstruction(player, cmd.template);
+
+ // If it modifies the terrain, apply the changes
+ var CmpTerrainModifier = Engine.QueryInterface(ent, IID_TerrainModifier);
+ if (CmpTerrainModifier)
+ CmpTerrainModifier.ApplyTerrainModification();
+
// send Metadata info if any
if (cmd.metadata)
Engine.PostMessage(ent, MT_AIMetadata, { "id": ent, "metadata" : cmd.metadata, "owner" : player } );
Index: binaries/data/mods/public/simulation/templates/template_structure.xml
===================================================================
--- binaries/data/mods/public/simulation/templates/template_structure.xml (revision 14730)
+++ binaries/data/mods/public/simulation/templates/template_structure.xml (working copy)
@@ -97,6 +97,7 @@
0.6
12.0
+
5
Index: source/simulation2/TypeList.h
===================================================================
--- source/simulation2/TypeList.h (revision 14730)
+++ source/simulation2/TypeList.h (working copy)
@@ -149,6 +149,9 @@
INTERFACE(Terrain)
COMPONENT(Terrain)
+INTERFACE(TerrainModifier)
+COMPONENT(TerrainModifier)
+
INTERFACE(TerritoryInfluence)
COMPONENT(TerritoryInfluence)
Index: source/simulation2/components/CCmpTemplateManager.cpp
===================================================================
--- source/simulation2/components/CCmpTemplateManager.cpp (revision 14730)
+++ source/simulation2/components/CCmpTemplateManager.cpp (working copy)
@@ -572,6 +572,7 @@
permittedComponentTypes.insert("AIProxy");
permittedComponentTypes.insert("RallyPoint");
permittedComponentTypes.insert("RallyPointRenderer");
+ permittedComponentTypes.insert("TerrainModifier");
CParamNode::LoadXMLString(out, "");
out.CopyFilteredChildrenOfChild(in, "Entity", permittedComponentTypes);
Index: source/simulation2/components/CCmpTerrain.cpp
===================================================================
--- source/simulation2/components/CCmpTerrain.cpp (revision 14730)
+++ source/simulation2/components/CCmpTerrain.cpp (working copy)
@@ -25,6 +25,9 @@
#include "simulation2/MessageTypes.h"
#include "graphics/Terrain.h"
+#include "graphics/RenderableObject.h"
+#include "ps/Game.h"
+#include "ps/World.h"
#include "renderer/Renderer.h"
#include "renderer/WaterManager.h"
#include "maths/Vector3D.h"
@@ -140,7 +143,7 @@
MakeDirty(0, 0, tiles+1, tiles+1);
}
-
+
virtual void MakeDirty(i32 i0, i32 j0, i32 i1, i32 j1)
{
CMessageTerrainChanged msg(i0, j0, i1, j1);