Index: binaries/data/mods/public/simulation/components/BuildRestrictions.js
===================================================================
--- binaries/data/mods/public/simulation/components/BuildRestrictions.js
+++ binaries/data/mods/public/simulation/components/BuildRestrictions.js
@@ -17,7 +17,8 @@
"" +
"land" +
"shore" +
- "land-shore"+
+ "land-shore" +
+ "socket" +
"" +
"" +
"" +
@@ -45,11 +46,23 @@
"" +
"" +
"" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "tokens" +
+ "" +
+ "" +
+ "" +
"";
BuildRestrictions.prototype.Init = function()
{
this.territories = this.template.Territory.split(/\s+/);
+ if (this.template.Sockets)
+ this.sockets = this.template.Sockets._string.split(/\s+/);
+ if (this.template.PlacementType == "socket" && !this.sockets)
+ warn("Placement type 'Socket' without a socket specified, this building (" + this.entity + ") can never be built.");
};
/**
@@ -111,7 +124,7 @@
}
// Check obstructions and terrain passability
- var passClassName = "";
+ let passClassName = "";
switch (this.template.PlacementType)
{
case "shore":
@@ -124,6 +137,11 @@
passClassName = "default-terrain-only";
break;
+ case "socket":
+ // Special passabilityClass assuming "unrestricted" and ignoring collisions with sockets.
+ passClassName = "socket";
+ break;
+
case "land":
default:
passClassName = "building-land";
@@ -134,14 +152,20 @@
return result; // Fail
+ let ret;
if (this.template.Category == "Wall")
{
- // for walls, only test the center point
- var ret = cmpObstruction.CheckFoundation(passClassName, true);
+ // For walls, only test the center point.
+ ret = cmpObstruction.CheckFoundation(passClassName, true);
+ }
+ else if (passClassName == "socket")
+ {
+ // Verify no non-socket obstructions exist here. Ignore terrain passability.
+ ret = cmpObstruction.CheckFoundation(passClassName, false);
}
else
{
- var ret = cmpObstruction.CheckFoundation(passClassName, false);
+ ret = cmpObstruction.CheckFoundation(passClassName, false);
}
if (ret != "success")
@@ -214,13 +238,13 @@
result.message = markForTranslation("%(name)s cannot be built in %(territoryType)s territory. Valid territories: %(validTerritories)s");
result.translateParameters.push("territoryType");
result.translateParameters.push("validTerritories");
- result.parameters.territoryType = {"context": "Territory type", "message": invalidTerritory};
+ result.parameters.territoryType = { "context": "Territory type", "message": invalidTerritory };
// gui code will join this array to a string
- result.parameters.validTerritories = {"context": "Territory type list", "list": this.GetTerritories()};
+ result.parameters.validTerritories = { "context": "Territory type list", "list": this.GetTerritories() };
return result; // Fail
}
- // Check special requirements
+ // Check special requirements.
if (this.template.PlacementType == "shore")
{
if (!cmpObstruction.CheckShorePlacement())
@@ -229,6 +253,15 @@
return result; // Fail
}
}
+ if (this.template.PlacementType == "socket")
+ {
+ if (!cmpObstruction.CheckSocketPlacement("false"))
+ {
+ // ToDo: Send the name of the socket where this building ought to be build upon.
+ result.message = markForTranslation("%(name)s must be built on a valid socket");
+ return result; // Fail
+ }
+ }
let cmpTemplateManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_TemplateManager);
Index: binaries/data/mods/public/simulation/components/BuildSlot.js
===================================================================
--- binaries/data/mods/public/simulation/components/BuildSlot.js
+++ binaries/data/mods/public/simulation/components/BuildSlot.js
@@ -1,9 +1,17 @@
-function Settlement() {}
-
-Settlement.prototype.Schema =
- "";
-
-Engine.RegisterComponentType(IID_Settlement, "Settlement", Settlement);
+class BuildSlot
+{
+ get Schema()
+ {
+ return "Specifies this is a building slot, a entity where a building can be placed upon." +
+ "" +
+ "" +
+ "true" +
+ "" +
+ "" +
+ "" +
+ "" +
+ "";
+ }
/*
* TODO: the vague plan is that this should keep track of who currently owns the settlement,
@@ -13,3 +21,63 @@
* tell us that its player owns us, and move us back into our original position when the building
* is destroyed. Don't know if that's a sensible plan, though.
*/
+
+ Init()
+ {
+ this.owner = INVALID_PLAYER;
+ };
+
+ /**
+ * Initialises construction, thus rendering this socket useless.
+ *
+ * @param {number} player - The player requesting the initialisation.
+ *
+ * @return {boolean} Whether the initialisation was successful.
+ */
+ InitConstruction(player)
+ {
+ this.owner = player;
+
+ if (this.template.HideUponUse != "true")
+ return true;
+
+ let cmpPosition = Engine.QueryInterface(this.entity, IID_Position);
+ if (!cmpPosition)
+ return false;
+
+ this.previousPosition = cmpPosition.GetPosition();
+ cmpPosition.MoveOutOfWorld();
+
+ return true;
+ };
+
+ /**
+ * Resets this socket by setting the owner to -1 and moving back to its former position.
+ */
+ Reset()
+ {
+ this.owner = INVALID_PLAYER;
+
+ if (!this.previousPosition)
+ return;
+
+ let cmpPosition = Engine.QueryInterface(this.entity, IID_Position);
+ if (!cmpPosition)
+ return;
+
+ cmpPosition.JumpTo(this.previousPosition.x, this.previousPosition.z);
+ delete this.previousPosition;
+ };
+
+ /**
+ * Get the current owner.
+ *
+ * @return {number} The current owner of this build slot.
+ */
+ GetOwner()
+ {
+ return this.owner;
+ }
+}
+
+Engine.RegisterComponentType(IID_BuildSlot, "BuildSlot", BuildSlot);
Index: binaries/data/mods/public/simulation/components/Settlement.js
===================================================================
--- binaries/data/mods/public/simulation/components/Settlement.js
+++ binaries/data/mods/public/simulation/components/Settlement.js
@@ -1,15 +0,0 @@
-function Settlement() {}
-
-Settlement.prototype.Schema =
- "";
-
-Engine.RegisterComponentType(IID_Settlement, "Settlement", Settlement);
-
-/*
- * TODO: the vague plan is that this should keep track of who currently owns the settlement,
- * and some other code can detect this (or get notified of changes) when it needs to.
- * A civcenter's BuildRestrictions component will see that it's being built on this settlement,
- * call MoveOutOfWorld on us (so we're invisible and only the building is visible/selectable),
- * tell us that its player owns us, and move us back into our original position when the building
- * is destroyed. Don't know if that's a sensible plan, though.
- */
Index: binaries/data/mods/public/simulation/components/interfaces/BuildSlot.js
===================================================================
--- /dev/null
+++ binaries/data/mods/public/simulation/components/interfaces/BuildSlot.js
@@ -0,0 +1 @@
+Engine.RegisterInterface("BuildSlot");
Index: binaries/data/mods/public/simulation/components/tests/test_BuildSlot.js
===================================================================
--- /dev/null
+++ binaries/data/mods/public/simulation/components/tests/test_BuildSlot.js
@@ -0,0 +1,13 @@
+Engine.LoadComponentScript("interfaces/BuildSlot.js");
+Engine.LoadComponentScript("BuildSlot.js");
+
+const buildSlotId = 1;
+const playerId = 2;
+
+let cmpBuildSlot = ConstructComponent(buildSlotId, "BuildSlot", {
+ "HideUponUse": false
+});
+
+TS_ASSERT_UNEVAL_EQUALS(cmpBuildSlot.GetOwner(), INVALID_PLAYER);
+TS_ASSERT_UNEVAL_EQUALS(cmpBuildSlot.InitConstruction(playerId), true);
+TS_ASSERT_UNEVAL_EQUALS(cmpBuildSlot.GetOwner(), playerId);
Index: binaries/data/mods/public/simulation/templates/template_formation.xml
===================================================================
--- binaries/data/mods/public/simulation/templates/template_formation.xml
+++ binaries/data/mods/public/simulation/templates/template_formation.xml
@@ -43,6 +43,7 @@
false
false
false
+ false
false
false
false
Index: binaries/data/mods/public/simulation/templates/template_gaia.xml
===================================================================
--- binaries/data/mods/public/simulation/templates/template_gaia.xml
+++ binaries/data/mods/public/simulation/templates/template_gaia.xml
@@ -13,6 +13,7 @@
true
true
true
+ false
false
false
false
Index: binaries/data/mods/public/simulation/templates/template_structure.xml
===================================================================
--- binaries/data/mods/public/simulation/templates/template_structure.xml
+++ binaries/data/mods/public/simulation/templates/template_structure.xml
@@ -79,6 +79,7 @@
true
true
false
+ false
false
false
false
Index: binaries/data/mods/public/simulation/templates/template_structure_civic_house.xml
===================================================================
--- binaries/data/mods/public/simulation/templates/template_structure_civic_house.xml
+++ binaries/data/mods/public/simulation/templates/template_structure_civic_house.xml
@@ -2,6 +2,8 @@
House
+ socket
+ template_socket_house
300
Index: binaries/data/mods/public/simulation/templates/template_unit.xml
===================================================================
--- binaries/data/mods/public/simulation/templates/template_unit.xml
+++ binaries/data/mods/public/simulation/templates/template_unit.xml
@@ -65,6 +65,7 @@
false
false
true
+ false
false
false
false
Index: source/simulation2/components/CCmpObstruction.cpp
===================================================================
--- source/simulation2/components/CCmpObstruction.cpp
+++ source/simulation2/components/CCmpObstruction.cpp
@@ -164,6 +164,9 @@
""
""
""
+ ""
+ ""
+ ""
""
""
""
@@ -196,6 +199,8 @@
m_TemplateFlags |= ICmpObstructionManager::FLAG_BLOCK_CONSTRUCTION;
if (paramNode.GetChild("DeleteUponConstruction").ToBool())
m_TemplateFlags |= ICmpObstructionManager::FLAG_DELETE_UPON_CONSTRUCTION;
+ if (paramNode.GetChild("IsSocket").ToBool())
+ m_TemplateFlags |= ICmpObstructionManager::FLAG_IS_SOCKET;
m_Flags = m_TemplateFlags;
if (paramNode.GetChild("DisableBlockMovement").ToBool())
@@ -549,6 +554,20 @@
cmpWaterManager->GetWaterLevel( back.X, back.Y) - cmpTerrain->GetGroundLevel( back.X, back.Y) < fixed::FromInt(2);
}
+ virtual bool CheckSocketPlacement(const std::string& slotTemplate) const
+ {
+ ICmpObstructionManager::ObstructionSquare s;
+ if (!GetObstructionSquare(s))
+ return false;
+
+ // Something useful ought to be checked here,,,
+
+ if (slotTemplate == "true")
+ return true;
+ else
+ return false;
+ }
+
virtual EFoundationCheck CheckFoundation(const std::string& className) const
{
return CheckFoundation(className, false);
@@ -576,8 +595,12 @@
return FOUNDATION_CHECK_FAIL_ERROR;
}
- // Get passability class
- pass_class_t passClass = cmpPathfinder->GetPassabilityClass(className);
+ // Get passability class. Socketted buildings are allowed anywhere where the socket exists.
+ pass_class_t passClass;
+ if (className == "socket")
+ passClass = cmpPathfinder->GetPassabilityClass("unrestricted");
+ else
+ passClass = cmpPathfinder->GetPassabilityClass(className);
// Ignore collisions within the same control group, or with other non-foundation-blocking shapes.
// Note that, since the control group for each entity defaults to the entity's ID, this is typically
@@ -585,6 +608,10 @@
SkipControlGroupsRequireFlagObstructionFilter filter(m_ControlGroup, m_ControlGroup2,
ICmpObstructionManager::FLAG_BLOCK_FOUNDATION);
+ if (className == "socket")
+ SkipControlGroupsRequireFlagObstructionFilter filter(m_ControlGroup, m_ControlGroup2,
+ ICmpObstructionManager::FLAG_IS_SOCKET);
+
if (m_Type == UNIT)
return cmpPathfinder->CheckUnitPlacement(filter, pos.X, pos.Y, m_Clearance, passClass, onlyCenterPoint);
else
Index: source/simulation2/components/ICmpObstruction.h
===================================================================
--- source/simulation2/components/ICmpObstruction.h
+++ source/simulation2/components/ICmpObstruction.h
@@ -74,6 +74,11 @@
virtual bool CheckShorePlacement() const = 0;
/**
+ * Test whether the square is within a socket of the right type.
+ */
+ virtual bool CheckSocketPlacement(const std::string& socketTemplate) const = 0;
+
+ /**
* Test whether this entity is colliding with any obstruction that are set to
* block the creation of foundations.
* @param ignoredEntities List of entities to ignore during the test.
Index: source/simulation2/components/ICmpObstruction.cpp
===================================================================
--- source/simulation2/components/ICmpObstruction.cpp
+++ source/simulation2/components/ICmpObstruction.cpp
@@ -1,4 +1,4 @@
-/* Copyright (C) 2018 Wildfire Games.
+/* Copyright (C) 2019 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@@ -48,6 +48,7 @@
BEGIN_INTERFACE_WRAPPER(Obstruction)
DEFINE_INTERFACE_METHOD_CONST_0("GetUnitRadius", entity_pos_t, ICmpObstruction, GetUnitRadius)
DEFINE_INTERFACE_METHOD_CONST_0("CheckShorePlacement", bool, ICmpObstruction, CheckShorePlacement)
+DEFINE_INTERFACE_METHOD_CONST_1("CheckSocketPlacement", bool, ICmpObstruction, CheckSocketPlacement, std::string)
DEFINE_INTERFACE_METHOD_CONST_2("CheckFoundation", std::string, ICmpObstruction, CheckFoundation_wrapper, std::string, bool)
DEFINE_INTERFACE_METHOD_CONST_0("CheckDuplicateFoundation", bool, ICmpObstruction, CheckDuplicateFoundation)
DEFINE_INTERFACE_METHOD_CONST_0("GetEntitiesBlockingConstruction", std::vector, ICmpObstruction, GetEntitiesBlockingConstruction)
Index: source/simulation2/components/ICmpObstructionManager.h
===================================================================
--- source/simulation2/components/ICmpObstructionManager.h
+++ source/simulation2/components/ICmpObstructionManager.h
@@ -86,7 +86,8 @@
FLAG_BLOCK_CONSTRUCTION = (1 << 2), // prevents buildings being constructed on this shape
FLAG_BLOCK_PATHFINDING = (1 << 3), // prevents the tile pathfinder choosing paths through this shape
FLAG_MOVING = (1 << 4), // indicates this unit is currently moving
- FLAG_DELETE_UPON_CONSTRUCTION = (1 << 5) // this entity is deleted when construction of a building placed on top of this entity starts
+ FLAG_DELETE_UPON_CONSTRUCTION = (1 << 5), // this entity is deleted when construction of a building placed on top of this entity starts
+ FLAG_IS_SOCKET = (1 << 6) // this entity is a slot where construction of a building placed on top of this entity starts
};
/**
Index: source/simulation2/components/tests/test_ObstructionManager.h
===================================================================
--- source/simulation2/components/tests/test_ObstructionManager.h
+++ source/simulation2/components/tests/test_ObstructionManager.h
@@ -35,6 +35,7 @@
virtual void SetUnitClearance(const entity_pos_t& UNUSED(clearance)) { }
virtual bool IsControlPersistent() const { return true; }
virtual bool CheckShorePlacement() const { return true; }
+ virtual bool CheckSocketPlacement(const std::string& UNUSED(socketTemplate)) const { return true; }
virtual EFoundationCheck CheckFoundation(const std::string& UNUSED(className)) const { return EFoundationCheck(); }
virtual EFoundationCheck CheckFoundation(const std::string& UNUSED(className), bool UNUSED(onlyCenterPoint)) const { return EFoundationCheck(); }
virtual std::string CheckFoundation_wrapper(const std::string& UNUSED(className), bool UNUSED(onlyCenterPoint)) const { return std::string(); }