Gates. Adds UI buttons, replaces wall section with a gate, defines and create obstruction shapes, detects friendly units and eventually disable door's "block movement" flag, allows us to lock / unlock the door by disabling "block pathfinding" flag. Needs icons, play sound, animations. Fixes #1385, refs #619.
This was SVN commit r12081.
This commit is contained in:
parent
9a3a6b9c2f
commit
2c5933912c
@ -1626,6 +1626,27 @@ function performStance(entity, stanceName)
|
||||
}
|
||||
}
|
||||
|
||||
// Lock / Unlock the gate
|
||||
function lockGate(lock)
|
||||
{
|
||||
var selection = g_Selection.toList();
|
||||
Engine.PostNetworkCommand({
|
||||
"type": "lock-gate",
|
||||
"entities": selection,
|
||||
"lock": lock,
|
||||
});
|
||||
}
|
||||
|
||||
// Transform a wall to a gate
|
||||
function transformWallToGate()
|
||||
{
|
||||
var selection = g_Selection.toList();
|
||||
Engine.PostNetworkCommand({
|
||||
"type": "wall-to-gate",
|
||||
"entities": selection,
|
||||
});
|
||||
}
|
||||
|
||||
// Set the camera to follow the given unit
|
||||
function setCameraFollow(entity)
|
||||
{
|
||||
|
@ -859,6 +859,19 @@
|
||||
</object>
|
||||
</object>
|
||||
|
||||
<object name="unitGatePanel"
|
||||
size="10 12 100% 100%"
|
||||
>
|
||||
<object size="0 0 100% 100%">
|
||||
<repeat count="1">
|
||||
<object name="unitGateButton[n]" style="iconButton" type="button" size="0 0 46 46" tooltip_style="sessionToolTipBottom">
|
||||
<object name="unitGateIcon[n]" type="image" ghost="true" size="3 3 43 43"/>
|
||||
<object name="unitGateSelection[n]" hidden="true" type="image" ghost="true" size="3 3 43 43" sprite="stretched:session/icons/corners.png"/>
|
||||
</object>
|
||||
</repeat>
|
||||
</object>
|
||||
</object>
|
||||
|
||||
</object> <!-- END OF UNIT COMMANDS -->
|
||||
|
||||
</object><!-- END OF BOTTOM PANEL -->
|
||||
|
@ -8,6 +8,7 @@ const RESEARCH = "Research";
|
||||
const CONSTRUCTION = "Construction";
|
||||
const COMMAND = "Command";
|
||||
const STANCE = "Stance";
|
||||
const GATE = "Gate";
|
||||
|
||||
// Constants
|
||||
const COMMANDS_PANEL_WIDTH = 228;
|
||||
@ -24,10 +25,10 @@ const BARTER_RESOURCES = ["food", "wood", "stone", "metal"];
|
||||
const BARTER_ACTIONS = ["Sell", "Buy"];
|
||||
|
||||
// The number of currently visible buttons (used to optimise showing/hiding)
|
||||
var g_unitPanelButtons = {"Selection": 0, "Queue": 0, "Formation": 0, "Garrison": 0, "Training": 0, "Research": 0, "Barter": 0, "Trading": 0, "Construction": 0, "Command": 0, "Stance": 0};
|
||||
var g_unitPanelButtons = {"Selection": 0, "Queue": 0, "Formation": 0, "Garrison": 0, "Training": 0, "Research": 0, "Barter": 0, "Trading": 0, "Construction": 0, "Command": 0, "Stance": 0, "Gate": 0};
|
||||
|
||||
// Unit panels are panels with row(s) of buttons
|
||||
var g_unitPanels = ["Selection", "Queue", "Formation", "Garrison", "Training", "Barter", "Trading", "Construction", "Research", "Stance", "Command"];
|
||||
var g_unitPanels = ["Selection", "Queue", "Formation", "Garrison", "Training", "Barter", "Trading", "Construction", "Research", "Stance", "Command", "Gate"];
|
||||
|
||||
// Indexes of resources to sell and buy on barter panel
|
||||
var g_barterSell = 0;
|
||||
@ -203,6 +204,11 @@ function setupUnitPanel(guiName, usedPanels, unitEntState, items, callback)
|
||||
numberOfItems = 6;
|
||||
break;
|
||||
|
||||
case GATE:
|
||||
if(numberOfItems > 1)
|
||||
numberOfItems = 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -319,6 +325,7 @@ function setupUnitPanel(guiName, usedPanels, unitEntState, items, callback)
|
||||
|
||||
case STANCE:
|
||||
case FORMATION:
|
||||
case GATE:
|
||||
var tooltip = toTitleCase(item);
|
||||
break;
|
||||
|
||||
@ -492,12 +499,16 @@ function setupUnitPanel(guiName, usedPanels, unitEntState, items, callback)
|
||||
icon.sprite = "stretched:session/icons/" + item.icon;
|
||||
|
||||
}
|
||||
else if (guiName == GATE)
|
||||
{
|
||||
icon.sprite = "stretched:session/icons/production.png";
|
||||
}
|
||||
else if (template.icon)
|
||||
{
|
||||
var grayscale = "";
|
||||
button.enabled = true;
|
||||
|
||||
if (guiName != SELECTION && template.requiredTechnology && !Engine.GuiInterfaceCall("IsTechnologyResearched", template.requiredTechnology))
|
||||
if (0 && guiName != SELECTION && template.requiredTechnology && !Engine.GuiInterfaceCall("IsTechnologyResearched", template.requiredTechnology))
|
||||
{
|
||||
button.enabled = false;
|
||||
var techName = getEntityName(GetTechnologyData(template.requiredTechnology));
|
||||
@ -793,6 +804,26 @@ function updateUnitCommands(entState, supplementalDetailsPanel, commandsPanel, s
|
||||
setupUnitTradingPanel(entState, selection);
|
||||
}
|
||||
|
||||
if(!entState.foundation && (entState.gate || hasClass(entState, "StoneWall") && !hasClass(entState, "Tower")))
|
||||
{
|
||||
if (entState.gate)
|
||||
{
|
||||
var action = entState.gate.locked ? "Unlock gate": "Lock gate";
|
||||
setupUnitPanel(GATE, usedPanels, entState, [action],
|
||||
function (item) { lockGate(!entState.gate.locked); } );
|
||||
}
|
||||
else // Wall
|
||||
{
|
||||
var templateData = GetTemplateData(entState.template);
|
||||
// Only allow long walls section to be transformed to gates
|
||||
if (templateData.wallPiece.length > 20) //TODO : increase
|
||||
{
|
||||
setupUnitPanel(GATE, usedPanels, entState, ["Create a gate"],
|
||||
function (item) { transformWallToGate(); } );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
supplementalDetailsPanel.hidden = false;
|
||||
commandsPanel.hidden = false;
|
||||
}
|
||||
|
@ -137,7 +137,7 @@ Foundation.prototype.Build = function(builderEnt, work)
|
||||
// but we've temporarily allowed units to walk all over it
|
||||
// (via CCmpTemplateManager). Now we need to remove that temporary
|
||||
// blocker-disabling, so that we'll perform standard unit blocking instead.
|
||||
cmpObstruction.SetDisableBlockMovementPathfinding(false);
|
||||
cmpObstruction.SetDisableBlockMovementPathfinding(false, false, -1);
|
||||
}
|
||||
|
||||
this.committed = true;
|
||||
|
176
binaries/data/mods/public/simulation/components/Gate.js
Normal file
176
binaries/data/mods/public/simulation/components/Gate.js
Normal file
@ -0,0 +1,176 @@
|
||||
function Gate() {}
|
||||
|
||||
Gate.prototype.Schema =
|
||||
"<element name='Radius'>" +
|
||||
"<ref name='nonNegativeDecimal'/>" +
|
||||
"</element>";
|
||||
|
||||
/**
|
||||
* Initialize Gate Component
|
||||
*/
|
||||
Gate.prototype.Init = function()
|
||||
{
|
||||
this.allyUnits = [];
|
||||
};
|
||||
|
||||
Gate.prototype.OnOwnershipChanged = function(msg)
|
||||
{
|
||||
if (msg.to != -1)
|
||||
{
|
||||
this.SetupRangeQuery(msg.to);
|
||||
this.UnlockGate();
|
||||
this.CloseGate();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Cleanup on destroy
|
||||
*/
|
||||
Gate.prototype.OnDestroy = function()
|
||||
{
|
||||
// Clean up range query
|
||||
var cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
|
||||
if (this.allyUnitsQuery)
|
||||
cmpRangeManager.DestroyActiveQuery(this.allyUnitsQuery);
|
||||
};
|
||||
|
||||
/**
|
||||
* Setup the Range Query to detect units coming in & out of range
|
||||
*/
|
||||
Gate.prototype.SetupRangeQuery = function(owner)
|
||||
{
|
||||
var cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
|
||||
var cmpPlayerManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager);
|
||||
if (this.allyUnitsQuery)
|
||||
cmpRangeManager.DestroyActiveQuery(this.allyUnitsQuery);
|
||||
var allyPlayers = []
|
||||
|
||||
var cmpPlayer = Engine.QueryInterface(cmpPlayerManager.GetPlayerByID(owner), IID_Player);
|
||||
var numPlayers = cmpPlayerManager.GetNumPlayers();
|
||||
|
||||
for (var i = 1; i < numPlayers; ++i)
|
||||
{ // Exclude gaia, allies, and self
|
||||
// TODO: How to handle neutral players - Special query to attack military only?
|
||||
if (cmpPlayer.IsAlly(i))
|
||||
allyPlayers.push(i);
|
||||
}
|
||||
|
||||
if (this.GetRadius() > 0)
|
||||
{
|
||||
var range = this.GetRadius();
|
||||
this.allyUnitsQuery = cmpRangeManager.CreateActiveQuery(this.entity, 0, range, allyPlayers, 0, cmpRangeManager.GetEntityFlagMask("normal"));
|
||||
cmpRangeManager.EnableActiveQuery(this.allyUnitsQuery);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Called when units enter or leave range
|
||||
*/
|
||||
Gate.prototype.OnRangeUpdate = function(msg)
|
||||
{
|
||||
if (msg.tag != this.allyUnitsQuery)
|
||||
return;
|
||||
|
||||
if (msg.added.length > 0)
|
||||
{
|
||||
for each (var entity in msg.added)
|
||||
{
|
||||
var cmpIdentity = Engine.QueryInterface(entity, IID_Identity);
|
||||
if(cmpIdentity)
|
||||
{
|
||||
var classes = cmpIdentity.GetClassesList();
|
||||
if(classes.indexOf("Unit") != -1)
|
||||
this.allyUnits.push(entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (msg.removed.length > 0)
|
||||
{
|
||||
for each (var entity in msg.removed)
|
||||
{
|
||||
this.allyUnits.splice(this.allyUnits.indexOf(entity), 1);
|
||||
}
|
||||
}
|
||||
|
||||
this.ManeuverGate();
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the range query radius
|
||||
*/
|
||||
Gate.prototype.GetRadius = function()
|
||||
{
|
||||
return +this.template.Radius;
|
||||
};
|
||||
|
||||
/**
|
||||
* Open or close the gate
|
||||
*/
|
||||
Gate.prototype.ManeuverGate = function()
|
||||
{
|
||||
if (this.opened == true )
|
||||
{
|
||||
if (this.allyUnits.length == 0)
|
||||
{
|
||||
this.CloseGate();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (this.allyUnits.length > 0)
|
||||
{
|
||||
this.OpenGate();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Gate.prototype.IsLocked = function()
|
||||
{
|
||||
return this.locked;
|
||||
};
|
||||
|
||||
Gate.prototype.LockGate = function()
|
||||
{
|
||||
var cmpObstruction = Engine.QueryInterface(this.entity, IID_Obstruction);
|
||||
if (!cmpObstruction)
|
||||
return;
|
||||
cmpObstruction.SetDisableBlockMovementPathfinding(false, false, 0);
|
||||
this.locked = true;
|
||||
this.opened = false;
|
||||
};
|
||||
|
||||
Gate.prototype.UnlockGate = function()
|
||||
{
|
||||
var cmpObstruction = Engine.QueryInterface(this.entity, IID_Obstruction);
|
||||
if (!cmpObstruction)
|
||||
return;
|
||||
cmpObstruction.SetDisableBlockMovementPathfinding(false, true, 0);
|
||||
this.locked = false;
|
||||
this.opened = false;
|
||||
if (this.allyUnits.length > 0)
|
||||
this.OpenGate();
|
||||
};
|
||||
|
||||
Gate.prototype.OpenGate = function()
|
||||
{
|
||||
if (this.locked)
|
||||
return;
|
||||
var cmpObstruction = Engine.QueryInterface(this.entity, IID_Obstruction);
|
||||
if (!cmpObstruction)
|
||||
return;
|
||||
cmpObstruction.SetDisableBlockMovementPathfinding(true, true, 0);
|
||||
this.opened = true;
|
||||
};
|
||||
|
||||
Gate.prototype.CloseGate = function()
|
||||
{
|
||||
if (this.locked)
|
||||
return;
|
||||
var cmpObstruction = Engine.QueryInterface(this.entity, IID_Obstruction);
|
||||
if (!cmpObstruction)
|
||||
return;
|
||||
cmpObstruction.SetDisableBlockMovementPathfinding(false, true, 0);
|
||||
this.opened = false;
|
||||
};
|
||||
|
||||
Engine.RegisterComponentType(IID_Gate, "Gate", Gate);
|
@ -289,6 +289,14 @@ GuiInterface.prototype.GetEntityState = function(player, ent)
|
||||
"orders": cmpUnitAI.GetOrders(),
|
||||
};
|
||||
}
|
||||
|
||||
var cmpGate = Engine.QueryInterface(ent, IID_Gate);
|
||||
if (cmpGate)
|
||||
{
|
||||
ret.gate = {
|
||||
"locked": cmpGate.IsLocked(),
|
||||
};
|
||||
}
|
||||
|
||||
if (!cmpFoundation && cmpIdentity && cmpIdentity.HasClass("BarterMarket"))
|
||||
{
|
||||
@ -408,11 +416,15 @@ GuiInterface.prototype.GetTemplateData = function(player, name)
|
||||
ret.obstruction.shape.width = +template.Obstruction.Static["@width"];
|
||||
ret.obstruction.shape.depth = +template.Obstruction.Static["@depth"];
|
||||
}
|
||||
else
|
||||
else if (template.Obstruction.Unit)
|
||||
{
|
||||
ret.obstruction.shape.type = "unit";
|
||||
ret.obstruction.shape.radius = +template.Obstruction.Unit["@radius"];
|
||||
}
|
||||
else
|
||||
{
|
||||
ret.obstruction.shape.type = "cluster";
|
||||
}
|
||||
}
|
||||
|
||||
if (template.Health)
|
||||
|
@ -0,0 +1 @@
|
||||
Engine.RegisterInterface("Gate");
|
@ -351,6 +351,29 @@ function ProcessCommand(player, cmd)
|
||||
}
|
||||
break;
|
||||
|
||||
case "wall-to-gate":
|
||||
var entities = FilterEntityList(cmd.entities, player, controlAllUnits);
|
||||
for each (var ent in entities)
|
||||
{
|
||||
TryTransformWallToGate(ent, cmpPlayer);
|
||||
}
|
||||
break;
|
||||
|
||||
case "lock-gate":
|
||||
var entities = FilterEntityList(cmd.entities, player, controlAllUnits);
|
||||
for each (var ent in entities)
|
||||
{
|
||||
var cmpGate = Engine.QueryInterface(ent, IID_Gate);
|
||||
if (cmpGate)
|
||||
{
|
||||
if (cmd.lock)
|
||||
cmpGate.LockGate();
|
||||
else
|
||||
cmpGate.UnlockGate();
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case "setup-trade-route":
|
||||
for each (var ent in cmd.entities)
|
||||
{
|
||||
@ -1071,6 +1094,67 @@ function FilterEntityList(entities, player, controlAll)
|
||||
return entities.filter(function(ent) { return CanControlUnit(ent, player, controlAll);} );
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to transform a wall to a gate
|
||||
*/
|
||||
function TryTransformWallToGate(ent, cmpPlayer)
|
||||
{
|
||||
var cmpIdentity = Engine.QueryInterface(ent, IID_Identity);
|
||||
if (!cmpIdentity)
|
||||
return;
|
||||
var civ = cmpIdentity.GetCiv();
|
||||
var template = "structures/" + civ + "_wall_gate";
|
||||
var gate = Engine.AddEntity(template);
|
||||
|
||||
var cmpCost = Engine.QueryInterface(gate, IID_Cost);
|
||||
if (!cmpPlayer.TrySubtractResources(cmpCost.GetResourceCosts()))
|
||||
{
|
||||
if (g_DebugCommands)
|
||||
{
|
||||
warn("Invalid command: building cost check failed for player "+player+": "+uneval(cmd));
|
||||
}
|
||||
|
||||
Engine.DestroyEntity(gate);
|
||||
return;
|
||||
}
|
||||
|
||||
ReplaceBuildingWith(ent, gate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unconditionally replace a building with another one
|
||||
*/
|
||||
function ReplaceBuildingWith(ent, building)
|
||||
{
|
||||
// Move the building to the right place
|
||||
var cmpPosition = Engine.QueryInterface(ent, IID_Position);
|
||||
var cmpBuildingPosition = Engine.QueryInterface(building, IID_Position);
|
||||
var pos = cmpPosition.GetPosition2D();
|
||||
cmpBuildingPosition.JumpTo(pos.x, pos.y);
|
||||
var rot = cmpPosition.GetRotation();
|
||||
cmpBuildingPosition.SetYRotation(rot.y);
|
||||
cmpBuildingPosition.SetXZRotation(rot.x, rot.z);
|
||||
|
||||
// Copy ownership
|
||||
var cmpOwnership = Engine.QueryInterface(ent, IID_Ownership);
|
||||
var cmpBuildingOwnership = Engine.QueryInterface(building, IID_Ownership);
|
||||
cmpBuildingOwnership.SetOwner(cmpOwnership.GetOwner());
|
||||
|
||||
// Copy control groups
|
||||
var cmpObstruction = Engine.QueryInterface(ent, IID_Obstruction);
|
||||
var cmpBuildingObstruction = Engine.QueryInterface(building, IID_Obstruction);
|
||||
cmpBuildingObstruction.SetControlGroup(cmpObstruction.GetControlGroup());
|
||||
cmpBuildingObstruction.SetControlGroup2(cmpObstruction.GetControlGroup2());
|
||||
|
||||
PlaySound("constructed", building);
|
||||
|
||||
Engine.PostMessage(ent, MT_ConstructionFinished,
|
||||
{ "entity": ent, "newentity": building });
|
||||
Engine.BroadcastMessage(MT_EntityRenamed, { entity: ent, newentity: building });
|
||||
|
||||
Engine.DestroyEntity(ent);
|
||||
}
|
||||
|
||||
Engine.RegisterGlobal("GetFormationRequirements", GetFormationRequirements);
|
||||
Engine.RegisterGlobal("CanMoveEntsIntoFormation", CanMoveEntsIntoFormation);
|
||||
Engine.RegisterGlobal("ProcessCommand", ProcessCommand);
|
||||
|
@ -13,7 +13,20 @@
|
||||
<History>The Athenian city wall was pierced by numerous gates and posterns of various sizes and importance. The "Sacred Gate" was the gate on the road to Eleusis. Another gate was the Dipylon Gate, whose name literally means "Double Gate."</History>
|
||||
</Identity>
|
||||
<Obstruction>
|
||||
<Static width="38.0" depth="6.5"/>
|
||||
<Cluster>
|
||||
<Right width="12" depth="6.5">
|
||||
<PosX>13</PosX>
|
||||
<PosZ>0</PosZ>
|
||||
</Right>
|
||||
<Left width="12" depth="6.5">
|
||||
<PosX>-13</PosX>
|
||||
<PosZ>0</PosZ>
|
||||
</Left>
|
||||
<Door width="14.0" depth="6.5">
|
||||
<PosX>0</PosX>
|
||||
<PosZ>0</PosZ>
|
||||
</Door>
|
||||
</Cluster>
|
||||
</Obstruction>
|
||||
<VisualActor>
|
||||
<Actor>structures/hellenes/wall_gate.xml</Actor>
|
||||
|
@ -20,7 +20,20 @@
|
||||
<History>The Romans called this wall 'Murus Gallicus'. Translated, it means 'Gaulish wall'. It was extremely resistant to assault by battering ram. Julius Caesar described a type of wood and stone wall, known as a Murus Gallicus, in his account of the Gallic Wars. These walls were made of a stone wall filled with rubble, with wooden logs inside for stability. Caesar noted how the flexibility of the wood added to the strength of the fort in case of battering ram attack.</History>
|
||||
</Identity>
|
||||
<Obstruction>
|
||||
<Static width="25.0" depth="8.0"/>
|
||||
<Cluster>
|
||||
<Right width="6" depth="8">
|
||||
<PosX>9.5</PosX>
|
||||
<PosZ>0</PosZ>
|
||||
</Right>
|
||||
<Left width="6" depth="8">
|
||||
<PosX>-9.5</PosX>
|
||||
<PosZ>0</PosZ>
|
||||
</Left>
|
||||
<Door width="13.0" depth="8">
|
||||
<PosX>0</PosX>
|
||||
<PosZ>0</PosZ>
|
||||
</Door>
|
||||
</Cluster>
|
||||
</Obstruction>
|
||||
<VisualActor>
|
||||
<Actor>structures/celts/wall_gate.xml</Actor>
|
||||
|
@ -20,7 +20,20 @@
|
||||
<History>The Romans called this wall 'Murus Gallicus'. Translated, it means 'Gaulish wall'. It was extremely resistant to assault by battering ram. Julius Caesar described a type of wood and stone wall, known as a Murus Gallicus, in his account of the Gallic Wars. These walls were made of a stone wall filled with rubble, with wooden logs inside for stability. Caesar noted how the flexibility of the wood added to the strength of the fort in case of battering ram attack.</History>
|
||||
</Identity>
|
||||
<Obstruction>
|
||||
<Static width="25.0" depth="8.0"/>
|
||||
<Cluster>
|
||||
<Right width="5" depth="8">
|
||||
<PosX>10</PosX>
|
||||
<PosZ>0</PosZ>
|
||||
</Right>
|
||||
<Left width="5" depth="8">
|
||||
<PosX>-10</PosX>
|
||||
<PosZ>0</PosZ>
|
||||
</Left>
|
||||
<Door width="15.0" depth="8">
|
||||
<PosX>0</PosX>
|
||||
<PosZ>0</PosZ>
|
||||
</Door>
|
||||
</Cluster>
|
||||
</Obstruction>
|
||||
<VisualActor>
|
||||
<Actor>structures/celts/wall_gate.xml</Actor>
|
||||
|
@ -20,7 +20,20 @@
|
||||
<History>The Romans called this wall 'Murus Gallicus'. Translated, it means 'Gaulish wall'. It was extremely resistant to assault by battering ram. Julius Caesar described a type of wood and stone wall, known as a Murus Gallicus, in his account of the Gallic Wars. These walls were made of a stone wall filled with rubble, with wooden logs inside for stability. Caesar noted how the flexibility of the wood added to the strength of the fort in case of battering ram attack.</History>
|
||||
</Identity>
|
||||
<Obstruction>
|
||||
<Static width="25.0" depth="8.0"/>
|
||||
<Cluster>
|
||||
<Right width="7" depth="8">
|
||||
<PosX>9</PosX>
|
||||
<PosZ>0</PosZ>
|
||||
</Right>
|
||||
<Left width="7" depth="8">
|
||||
<PosX>-9</PosX>
|
||||
<PosZ>0</PosZ>
|
||||
</Left>
|
||||
<Door width="11.0" depth="8">
|
||||
<PosX>0</PosX>
|
||||
<PosZ>0</PosZ>
|
||||
</Door>
|
||||
</Cluster>
|
||||
</Obstruction>
|
||||
<VisualActor>
|
||||
<Actor>structures/celts/wall_gate.xml</Actor>
|
||||
|
@ -13,7 +13,20 @@
|
||||
<History>(Insert history)</History>
|
||||
</Identity>
|
||||
<Obstruction>
|
||||
<Static width="38.0" depth="6.5"/>
|
||||
<Cluster>
|
||||
<Right width="12" depth="6.5">
|
||||
<PosX>13</PosX>
|
||||
<PosZ>0</PosZ>
|
||||
</Right>
|
||||
<Left width="12" depth="6.5">
|
||||
<PosX>-13</PosX>
|
||||
<PosZ>0</PosZ>
|
||||
</Left>
|
||||
<Door width="14.0" depth="6.5">
|
||||
<PosX>0</PosX>
|
||||
<PosZ>0</PosZ>
|
||||
</Door>
|
||||
</Cluster>
|
||||
</Obstruction>
|
||||
<VisualActor>
|
||||
<Actor>structures/hellenes/wall_gate.xml</Actor>
|
||||
|
@ -10,7 +10,20 @@
|
||||
<History>One of the central attributes of the Iberians civ is that it was a highly defensive one that constantly gave the Carthaginians trouble in their bid to conquer the peninsula (which they never really did) and took the Romans another 200 years to subdue, along with incredibly large cumulative loss of Roman soldier's lives. This doubled gate has been found incorporated into walls surrounding Iberian villages, Oppidum, and fortresses, Castros. It presents rather formidable aspects with its 4 towers, 2 gates, and a courtyard-like interior wherein enemy forces could become entrapped between the two gates, combined with a monolithically strong stone structure. The concept comes from archeologist and paleontologist descriptions of the remains of such gates at various locations scattered about the Iberian Peninsula.</History>
|
||||
</Identity>
|
||||
<Obstruction>
|
||||
<Static width="36.0" depth="8.5"/>
|
||||
<Cluster>
|
||||
<Right width="10" depth="8.5">
|
||||
<PosX>13</PosX>
|
||||
<PosZ>0</PosZ>
|
||||
</Right>
|
||||
<Left width="10" depth="8.5">
|
||||
<PosX>-13</PosX>
|
||||
<PosZ>0</PosZ>
|
||||
</Left>
|
||||
<Door width="16.0" depth="8.5">
|
||||
<PosX>0</PosX>
|
||||
<PosZ>0</PosZ>
|
||||
</Door>
|
||||
</Cluster>
|
||||
</Obstruction>
|
||||
<VisualActor>
|
||||
<Actor>structures/iberians/wall_gate.xml</Actor>
|
||||
|
@ -13,7 +13,20 @@
|
||||
<History>(Insert history)</History>
|
||||
</Identity>
|
||||
<Obstruction>
|
||||
<Static width="38.0" depth="6.5"/>
|
||||
<Cluster>
|
||||
<Right width="12" depth="6.5">
|
||||
<PosX>13</PosX>
|
||||
<PosZ>0</PosZ>
|
||||
</Right>
|
||||
<Left width="12" depth="6.5">
|
||||
<PosX>-13</PosX>
|
||||
<PosZ>0</PosZ>
|
||||
</Left>
|
||||
<Door width="14.0" depth="6.5">
|
||||
<PosX>0</PosX>
|
||||
<PosZ>0</PosZ>
|
||||
</Door>
|
||||
</Cluster>
|
||||
</Obstruction>
|
||||
<VisualActor>
|
||||
<Actor>structures/hellenes/wall_gate.xml</Actor>
|
||||
|
@ -16,7 +16,20 @@
|
||||
<History>Persepolis, the Persian royal capital, was constructed on an immense man-made terrace with strong defensive walls.</History>
|
||||
</Identity>
|
||||
<Obstruction>
|
||||
<Static width="37.0" depth="7.0"/>
|
||||
<Cluster>
|
||||
<Right width="11" depth="7.0">
|
||||
<PosX>13</PosX>
|
||||
<PosZ>0</PosZ>
|
||||
</Right>
|
||||
<Left width="11" depth="7.0">
|
||||
<PosX>-13</PosX>
|
||||
<PosZ>0</PosZ>
|
||||
</Left>
|
||||
<Door width="15.0" depth="7.0">
|
||||
<PosX>0</PosX>
|
||||
<PosZ>0</PosZ>
|
||||
</Door>
|
||||
</Cluster>
|
||||
</Obstruction>
|
||||
<VisualActor>
|
||||
<Actor>structures/persians/wall_gate.xml</Actor>
|
||||
|
@ -28,7 +28,20 @@
|
||||
<History>(Insert History Here)</History>
|
||||
</Identity>
|
||||
<Obstruction>
|
||||
<Static width="37.0" depth="5.0"/>
|
||||
<Cluster>
|
||||
<Right width="12" depth="5">
|
||||
<PosX>12.5</PosX>
|
||||
<PosZ>0</PosZ>
|
||||
</Right>
|
||||
<Left width="12" depth="5">
|
||||
<PosX>-12.5</PosX>
|
||||
<PosZ>0</PosZ>
|
||||
</Left>
|
||||
<Door width="13.0" depth="5">
|
||||
<PosX>0</PosX>
|
||||
<PosZ>0</PosZ>
|
||||
</Door>
|
||||
</Cluster>
|
||||
</Obstruction>
|
||||
<TerritoryDecay>
|
||||
<HealthDecayRate>1</HealthDecayRate>
|
||||
|
@ -10,7 +10,20 @@
|
||||
<History>Rome had a number of gates piercing its city walls. One of the most famous of these was the Appian Gate.</History>
|
||||
</Identity>
|
||||
<Obstruction>
|
||||
<Static width="37.0" depth="7.0"/>
|
||||
<Cluster>
|
||||
<Right width="13" depth="7">
|
||||
<PosX>12</PosX>
|
||||
<PosZ>0</PosZ>
|
||||
</Right>
|
||||
<Left width="13" depth="7">
|
||||
<PosX>-12</PosX>
|
||||
<PosZ>0</PosZ>
|
||||
</Left>
|
||||
<Door width="11.0" depth="7">
|
||||
<PosX>0</PosX>
|
||||
<PosZ>0</PosZ>
|
||||
</Door>
|
||||
</Cluster>
|
||||
</Obstruction>
|
||||
<VisualActor>
|
||||
<Actor>structures/romans/wall_gate.xml</Actor>
|
||||
|
@ -10,7 +10,20 @@
|
||||
<History>(Insert history)</History>
|
||||
</Identity>
|
||||
<Obstruction>
|
||||
<Static width="38.0" depth="6.5"/>
|
||||
<Cluster>
|
||||
<Right width="12" depth="6.5">
|
||||
<PosX>13</PosX>
|
||||
<PosZ>0</PosZ>
|
||||
</Right>
|
||||
<Left width="12" depth="6.5">
|
||||
<PosX>-13</PosX>
|
||||
<PosZ>0</PosZ>
|
||||
</Left>
|
||||
<Door width="14.0" depth="6.5">
|
||||
<PosX>0</PosX>
|
||||
<PosZ>0</PosZ>
|
||||
</Door>
|
||||
</Cluster>
|
||||
</Obstruction>
|
||||
<VisualActor>
|
||||
<Actor>structures/hellenes/wall_gate.xml</Actor>
|
||||
|
@ -5,6 +5,9 @@
|
||||
<Pierce>40.0</Pierce>
|
||||
<Crush>10.0</Crush>
|
||||
</Armour>
|
||||
<Gate>
|
||||
<Radius>20</Radius>
|
||||
</Gate>
|
||||
<BuildRestrictions>
|
||||
<Category>Wall</Category>
|
||||
</BuildRestrictions>
|
||||
@ -36,7 +39,20 @@
|
||||
<metal>0</metal>
|
||||
</Loot>
|
||||
<Obstruction>
|
||||
<Static width="6.0" depth="6.0"/>
|
||||
<Cluster>
|
||||
<Right width="5" depth="5">
|
||||
<PosX>10</PosX>
|
||||
<PosZ>0</PosZ>
|
||||
</Right>
|
||||
<Left width="5" depth="5">
|
||||
<PosX>-10</PosX>
|
||||
<PosZ>0</PosZ>
|
||||
</Left>
|
||||
<Door width="20.0" depth="6.5">
|
||||
<PosX>0</PosX>
|
||||
<PosZ>0</PosZ>
|
||||
</Door>
|
||||
</Cluster>
|
||||
</Obstruction>
|
||||
<RallyPoint disable=""/>
|
||||
<Sound>
|
||||
|
@ -24,6 +24,10 @@
|
||||
#include "simulation2/MessageTypes.h"
|
||||
#include "simulation2/components/ICmpObstructionManager.h"
|
||||
#include "simulation2/components/ICmpPosition.h"
|
||||
#include "simulation2/serialization/SerializeTemplates.h"
|
||||
|
||||
#define MAX(x,y) x>y ? x : y
|
||||
#define MIN(x,y) x>y ? y : x
|
||||
|
||||
/**
|
||||
* Obstruction implementation. This keeps the ICmpPathfinder's model of the world updated when the
|
||||
@ -47,13 +51,23 @@ public:
|
||||
|
||||
enum {
|
||||
STATIC,
|
||||
UNIT
|
||||
UNIT,
|
||||
CLUSTER
|
||||
} m_Type;
|
||||
|
||||
entity_pos_t m_Size0; // radius or width
|
||||
entity_pos_t m_Size1; // radius or depth
|
||||
flags_t m_TemplateFlags;
|
||||
|
||||
typedef struct {
|
||||
entity_pos_t dx, dz;
|
||||
entity_angle_t da;
|
||||
entity_pos_t size0, size1;
|
||||
flags_t flags;
|
||||
} Shape;
|
||||
|
||||
std::vector<Shape> m_Shapes;
|
||||
|
||||
// Dynamic state:
|
||||
|
||||
/// Whether the obstruction is actively obstructing or just an inactive placeholder.
|
||||
@ -82,6 +96,7 @@ public:
|
||||
/// Identifier of this entity's obstruction shape, as registered in the obstruction manager. Contains
|
||||
/// structure, but should be treated as opaque here.
|
||||
tag_t m_Tag;
|
||||
std::vector<tag_t> m_ClusterTags;
|
||||
|
||||
/// Set of flags affecting the behaviour of this entity's obstruction shape.
|
||||
flags_t m_Flags;
|
||||
@ -105,6 +120,25 @@ public:
|
||||
"<ref name='positiveDecimal'/>"
|
||||
"</attribute>"
|
||||
"</element>"
|
||||
"<element name='Cluster'>"
|
||||
"<zeroOrMore>"
|
||||
"<element>"
|
||||
"<anyName/>"
|
||||
"<element name='PosX'>"
|
||||
"<data type='decimal'/>"
|
||||
"</element>"
|
||||
"<element name='PosZ'>"
|
||||
"<data type='decimal'/>"
|
||||
"</element>"
|
||||
"<attribute name='width'>"
|
||||
"<ref name='positiveDecimal'/>"
|
||||
"</attribute>"
|
||||
"<attribute name='depth'>"
|
||||
"<ref name='positiveDecimal'/>"
|
||||
"</attribute>"
|
||||
"</element>"
|
||||
"</zeroOrMore>"
|
||||
"</element>"
|
||||
"</choice>"
|
||||
"<element name='Active' a:help='If false, this entity will be ignored in collision tests by other units but can still perform its own collision tests'>"
|
||||
"<data type='boolean'/>"
|
||||
@ -131,18 +165,6 @@ public:
|
||||
|
||||
virtual void Init(const CParamNode& paramNode)
|
||||
{
|
||||
if (paramNode.GetChild("Unit").IsOk())
|
||||
{
|
||||
m_Type = UNIT;
|
||||
m_Size0 = m_Size1 = paramNode.GetChild("Unit").GetChild("@radius").ToFixed();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Type = STATIC;
|
||||
m_Size0 = paramNode.GetChild("Static").GetChild("@width").ToFixed();
|
||||
m_Size1 = paramNode.GetChild("Static").GetChild("@depth").ToFixed();
|
||||
}
|
||||
|
||||
m_TemplateFlags = 0;
|
||||
if (paramNode.GetChild("BlockMovement").ToBool())
|
||||
m_TemplateFlags |= ICmpObstructionManager::FLAG_BLOCK_MOVEMENT;
|
||||
@ -159,9 +181,47 @@ public:
|
||||
if (paramNode.GetChild("DisableBlockPathfinding").ToBool())
|
||||
m_Flags &= (flags_t)(~ICmpObstructionManager::FLAG_BLOCK_PATHFINDING);
|
||||
|
||||
if (paramNode.GetChild("Unit").IsOk())
|
||||
{
|
||||
m_Type = UNIT;
|
||||
m_Size0 = m_Size1 = paramNode.GetChild("Unit").GetChild("@radius").ToFixed();
|
||||
}
|
||||
else if (paramNode.GetChild("Static").IsOk())
|
||||
{
|
||||
m_Type = STATIC;
|
||||
m_Size0 = paramNode.GetChild("Static").GetChild("@width").ToFixed();
|
||||
m_Size1 = paramNode.GetChild("Static").GetChild("@depth").ToFixed();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Type = CLUSTER;
|
||||
CFixedVector2D max = CFixedVector2D(fixed::FromInt(0), fixed::FromInt(0));
|
||||
CFixedVector2D min = CFixedVector2D(fixed::FromInt(0), fixed::FromInt(0));
|
||||
const CParamNode::ChildrenMap& clusterMap = paramNode.GetChild("Cluster").GetChildren();
|
||||
for(CParamNode::ChildrenMap::const_iterator it = clusterMap.begin(); it != clusterMap.end(); ++it)
|
||||
{
|
||||
Shape b;
|
||||
b.size0 = it->second.GetChild("@width").ToFixed();
|
||||
b.size1 = it->second.GetChild("@depth").ToFixed();
|
||||
b.dx = it->second.GetChild("PosX").ToFixed();
|
||||
b.dz = it->second.GetChild("PosZ").ToFixed();
|
||||
b.da = entity_angle_t::FromInt(0);
|
||||
b.flags = m_Flags;
|
||||
m_Shapes.push_back(b);
|
||||
max.X = MAX(max.X, b.dx + b.size0/2);
|
||||
max.Y = MAX(max.Y, b.dz + b.size1/2);
|
||||
min.X = MIN(min.X, b.dx - b.size0/2);
|
||||
min.Y = MIN(min.Y, b.dz - b.size1/2);
|
||||
}
|
||||
m_Size0 = fixed::FromInt(2).Multiply(MAX(max.X, -min.X));
|
||||
m_Size1 = fixed::FromInt(2).Multiply(MAX(max.Y, -min.Y));
|
||||
}
|
||||
|
||||
m_Active = paramNode.GetChild("Active").ToBool();
|
||||
|
||||
m_Tag = tag_t();
|
||||
if (m_Type == CLUSTER)
|
||||
m_ClusterTags.clear();
|
||||
m_Moving = false;
|
||||
m_ControlGroup = GetEntityId();
|
||||
m_ControlGroup2 = INVALID_ENTITY;
|
||||
@ -171,6 +231,15 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
struct SerializeTag
|
||||
{
|
||||
template<typename S>
|
||||
void operator()(S& serialize, const char* UNUSED(name), tag_t& value)
|
||||
{
|
||||
serialize.NumberU32_Unbounded("tag", value.n);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename S>
|
||||
void SerializeCommon(S& serialize)
|
||||
{
|
||||
@ -180,6 +249,8 @@ public:
|
||||
serialize.NumberU32_Unbounded("control group 2", m_ControlGroup2);
|
||||
serialize.NumberU32_Unbounded("tag", m_Tag.n);
|
||||
serialize.NumberU8_Unbounded("flags", m_Flags);
|
||||
if (m_Type == CLUSTER)
|
||||
SerializeVector<SerializeTag>()(serialize, "cluster tags", m_ClusterTags);
|
||||
}
|
||||
|
||||
virtual void Serialize(ISerializer& serialize)
|
||||
@ -215,6 +286,17 @@ public:
|
||||
if (data.inWorld && m_Tag.valid())
|
||||
{
|
||||
cmpObstructionManager->MoveShape(m_Tag, data.x, data.z, data.a);
|
||||
|
||||
if(m_Type == CLUSTER)
|
||||
{
|
||||
for (size_t i = 0; i < m_Shapes.size(); ++i)
|
||||
{
|
||||
Shape& b = m_Shapes[i];
|
||||
fixed s, c;
|
||||
sincos_approx(data.a, s, c);
|
||||
cmpObstructionManager->MoveShape(m_ClusterTags[i], data.x + b.dx.Multiply(c) + b.dz.Multiply(s), data.z + b.dz.Multiply(c) - b.dx.Multiply(s), data.a + b.da);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (data.inWorld && !m_Tag.valid())
|
||||
{
|
||||
@ -222,14 +304,18 @@ public:
|
||||
if (m_Type == STATIC)
|
||||
m_Tag = cmpObstructionManager->AddStaticShape(GetEntityId(),
|
||||
data.x, data.z, data.a, m_Size0, m_Size1, m_Flags, m_ControlGroup, m_ControlGroup2);
|
||||
else
|
||||
else if (m_Type == UNIT)
|
||||
m_Tag = cmpObstructionManager->AddUnitShape(GetEntityId(),
|
||||
data.x, data.z, m_Size0, (flags_t)(m_Flags | (m_Moving ? ICmpObstructionManager::FLAG_MOVING : 0)), m_ControlGroup);
|
||||
else
|
||||
AddClusterShapes(data.x, data.x, data.a);
|
||||
}
|
||||
else if (!data.inWorld && m_Tag.valid())
|
||||
{
|
||||
cmpObstructionManager->RemoveShape(m_Tag);
|
||||
m_Tag = tag_t();
|
||||
if(m_Type == CLUSTER)
|
||||
RemoveClusterShapes();
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -243,6 +329,8 @@ public:
|
||||
|
||||
cmpObstructionManager->RemoveShape(m_Tag);
|
||||
m_Tag = tag_t();
|
||||
if(m_Type == CLUSTER)
|
||||
RemoveClusterShapes();
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -273,9 +361,11 @@ public:
|
||||
if (m_Type == STATIC)
|
||||
m_Tag = cmpObstructionManager->AddStaticShape(GetEntityId(),
|
||||
pos.X, pos.Y, cmpPosition->GetRotation().Y, m_Size0, m_Size1, m_Flags, m_ControlGroup, m_ControlGroup2);
|
||||
else
|
||||
else if (m_Type == UNIT)
|
||||
m_Tag = cmpObstructionManager->AddUnitShape(GetEntityId(),
|
||||
pos.X, pos.Y, m_Size0, (flags_t)(m_Flags | (m_Moving ? ICmpObstructionManager::FLAG_MOVING : 0)), m_ControlGroup);
|
||||
else
|
||||
AddClusterShapes(pos.X, pos.Y, cmpPosition->GetRotation().Y);
|
||||
}
|
||||
else if (!active && m_Active)
|
||||
{
|
||||
@ -292,25 +382,33 @@ public:
|
||||
|
||||
cmpObstructionManager->RemoveShape(m_Tag);
|
||||
m_Tag = tag_t();
|
||||
if (m_Type == CLUSTER)
|
||||
RemoveClusterShapes();
|
||||
}
|
||||
}
|
||||
// else we didn't change the active status
|
||||
}
|
||||
|
||||
virtual void SetDisableBlockMovementPathfinding(bool disabled)
|
||||
virtual void SetDisableBlockMovementPathfinding(bool movementDisabled, bool pathfindingDisabled, int32_t shape)
|
||||
{
|
||||
if (disabled)
|
||||
{
|
||||
// Remove the blocking flags
|
||||
m_Flags &= (flags_t)(~ICmpObstructionManager::FLAG_BLOCK_MOVEMENT);
|
||||
m_Flags &= (flags_t)(~ICmpObstructionManager::FLAG_BLOCK_PATHFINDING);
|
||||
}
|
||||
flags_t *flags = NULL;
|
||||
if (shape == -1)
|
||||
flags = &m_Flags;
|
||||
else if (m_Type == CLUSTER && shape < (int32_t)m_Shapes.size())
|
||||
flags = &m_Shapes[shape].flags;
|
||||
else
|
||||
{
|
||||
// Add the blocking flags if the template had enabled them
|
||||
m_Flags = (flags_t)(m_Flags | (m_TemplateFlags & ICmpObstructionManager::FLAG_BLOCK_MOVEMENT));
|
||||
m_Flags = (flags_t)(m_Flags | (m_TemplateFlags & ICmpObstructionManager::FLAG_BLOCK_PATHFINDING));
|
||||
}
|
||||
return; // error
|
||||
|
||||
// Remove the blocking / pathfinding flags or
|
||||
// Add the blocking / pathfinding flags if the template had enabled them
|
||||
if (movementDisabled)
|
||||
*flags &= (flags_t)(~ICmpObstructionManager::FLAG_BLOCK_MOVEMENT);
|
||||
else
|
||||
*flags |= (flags_t)(m_TemplateFlags & ICmpObstructionManager::FLAG_BLOCK_MOVEMENT);
|
||||
if (pathfindingDisabled)
|
||||
*flags &= (flags_t)(~ICmpObstructionManager::FLAG_BLOCK_PATHFINDING);
|
||||
else
|
||||
*flags |= (flags_t)(m_TemplateFlags & ICmpObstructionManager::FLAG_BLOCK_PATHFINDING);
|
||||
|
||||
// Reset the shape with the new flags (kind of inefficiently - we
|
||||
// should have a ICmpObstructionManager::SetFlags function or something)
|
||||
@ -347,8 +445,10 @@ public:
|
||||
CFixedVector2D pos = cmpPosition->GetPosition2D();
|
||||
if (m_Type == STATIC)
|
||||
out = cmpObstructionManager->GetStaticShapeObstruction(pos.X, pos.Y, cmpPosition->GetRotation().Y, m_Size0, m_Size1);
|
||||
else
|
||||
else if (m_Type == UNIT)
|
||||
out = cmpObstructionManager->GetUnitShapeObstruction(pos.X, pos.Y, m_Size0);
|
||||
else
|
||||
out = cmpObstructionManager->GetStaticShapeObstruction(pos.X, pos.Y, cmpPosition->GetRotation().Y, m_Size0, m_Size1);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -393,8 +493,10 @@ public:
|
||||
|
||||
if (m_Type == STATIC)
|
||||
return cmpPathfinder->CheckBuildingPlacement(filter, pos.X, pos.Y, cmpPosition->GetRotation().Y, m_Size0, m_Size1, GetEntityId(), passClass);
|
||||
else
|
||||
else if (m_Type == UNIT)
|
||||
return cmpPathfinder->CheckUnitPlacement(filter, pos.X, pos.Y, m_Size0, passClass);
|
||||
else
|
||||
return cmpPathfinder->CheckBuildingPlacement(filter, pos.X, pos.Y, cmpPosition->GetRotation().Y, m_Size0, m_Size1, GetEntityId(), passClass);
|
||||
}
|
||||
|
||||
virtual std::vector<entity_id_t> GetConstructionCollisions()
|
||||
@ -429,9 +531,11 @@ public:
|
||||
|
||||
if (m_Type == STATIC)
|
||||
cmpObstructionManager->TestStaticShape(filter, pos.X, pos.Y, cmpPosition->GetRotation().Y, m_Size0, m_Size1, &ret);
|
||||
else
|
||||
else if (m_Type == UNIT)
|
||||
cmpObstructionManager->TestUnitShape(filter, pos.X, pos.Y, m_Size0, &ret);
|
||||
|
||||
else
|
||||
cmpObstructionManager->TestStaticShape(filter, pos.X, pos.Y, cmpPosition->GetRotation().Y, m_Size0, m_Size1, &ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -484,10 +588,62 @@ public:
|
||||
{
|
||||
cmpObstructionManager->SetStaticControlGroup(m_Tag, m_ControlGroup, m_ControlGroup2);
|
||||
}
|
||||
else
|
||||
{
|
||||
cmpObstructionManager->SetStaticControlGroup(m_Tag, m_ControlGroup, m_ControlGroup2);
|
||||
for (size_t i = 0; i < m_ClusterTags.size(); ++i)
|
||||
{
|
||||
cmpObstructionManager->SetStaticControlGroup(m_ClusterTags[i], m_ControlGroup, m_ControlGroup2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
inline void AddClusterShapes(entity_pos_t x, entity_pos_t z, entity_angle_t a)
|
||||
{
|
||||
CmpPtr<ICmpObstructionManager> cmpObstructionManager(GetSimContext(), SYSTEM_ENTITY);
|
||||
if (!cmpObstructionManager)
|
||||
return; // error
|
||||
|
||||
flags_t flags = m_Flags;
|
||||
// Disable block movement and block pathfinding for the obstruction shape
|
||||
flags &= (flags_t)(~ICmpObstructionManager::FLAG_BLOCK_MOVEMENT);
|
||||
flags &= (flags_t)(~ICmpObstructionManager::FLAG_BLOCK_PATHFINDING);
|
||||
|
||||
m_Tag = cmpObstructionManager->AddStaticShape(GetEntityId(),
|
||||
x, z, a, m_Size0, m_Size1, flags, m_ControlGroup, m_ControlGroup2);
|
||||
|
||||
fixed s, c;
|
||||
sincos_approx(a, s, c);
|
||||
|
||||
for (size_t i = 0; i < m_Shapes.size(); ++i)
|
||||
{
|
||||
Shape& b = m_Shapes[i];
|
||||
tag_t tag = cmpObstructionManager->AddStaticShape(GetEntityId(),
|
||||
x + b.dx.Multiply(c) + b.dz.Multiply(s), z + b.dz.Multiply(c) - b.dx.Multiply(s), a + b.da, b.size0, b.size1, b.flags, m_ControlGroup, m_ControlGroup2);
|
||||
m_ClusterTags.push_back(tag);
|
||||
}
|
||||
}
|
||||
|
||||
inline void RemoveClusterShapes()
|
||||
{
|
||||
CmpPtr<ICmpObstructionManager> cmpObstructionManager(GetSimContext(), SYSTEM_ENTITY);
|
||||
if (!cmpObstructionManager)
|
||||
return; // error
|
||||
|
||||
for (size_t i = 0; i < m_ClusterTags.size(); ++i)
|
||||
{
|
||||
if (m_ClusterTags[i].valid())
|
||||
{
|
||||
cmpObstructionManager->RemoveShape(m_ClusterTags[i]);
|
||||
}
|
||||
}
|
||||
m_ClusterTags.clear();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
REGISTER_COMPONENT_TYPE(Obstruction)
|
||||
|
@ -26,7 +26,7 @@ DEFINE_INTERFACE_METHOD_0("GetUnitRadius", entity_pos_t, ICmpObstruction, GetUni
|
||||
DEFINE_INTERFACE_METHOD_1("CheckFoundation", bool, ICmpObstruction, CheckFoundation, std::string)
|
||||
DEFINE_INTERFACE_METHOD_0("GetConstructionCollisions", std::vector<entity_id_t>, ICmpObstruction, GetConstructionCollisions)
|
||||
DEFINE_INTERFACE_METHOD_1("SetActive", void, ICmpObstruction, SetActive, bool)
|
||||
DEFINE_INTERFACE_METHOD_1("SetDisableBlockMovementPathfinding", void, ICmpObstruction, SetDisableBlockMovementPathfinding, 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)
|
||||
|
@ -60,7 +60,7 @@ public:
|
||||
|
||||
virtual void SetMovingFlag(bool enabled) = 0;
|
||||
|
||||
virtual void SetDisableBlockMovementPathfinding(bool disabled) = 0;
|
||||
virtual void SetDisableBlockMovementPathfinding(bool movementDisabled, bool pathfindingDisabled, int32_t shape) = 0;
|
||||
|
||||
virtual bool GetBlockMovementFlag() = 0;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user