diff --git a/binaries/data/mods/public/art/textures/ui/session/portraits/technologies/diaspora.png b/binaries/data/mods/public/art/textures/ui/session/portraits/technologies/diaspora.png
new file mode 100644
index 0000000000..19bffc55fd
--- /dev/null
+++ b/binaries/data/mods/public/art/textures/ui/session/portraits/technologies/diaspora.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:9ee781144e25c4e0b6070a5d9ec5feae0050cfd9f72ba40b73f6d16d74751085
+size 33234
diff --git a/binaries/data/mods/public/gui/session/selection_panels.js b/binaries/data/mods/public/gui/session/selection_panels.js
index b00326e825..b836dafefe 100644
--- a/binaries/data/mods/public/gui/session/selection_panels.js
+++ b/binaries/data/mods/public/gui/session/selection_panels.js
@@ -224,8 +224,9 @@ g_SelectionPanels.Command = {
},
"setGraphics": function(data)
{
- data.icon.sprite = "stretched:session/icons/" + data.item.icon;
data.button.enabled = controlsPlayer(data.unitEntState.player);
+ let grayscale = data.button.enabled ? "" : "grayscale:";
+ data.icon.sprite = "stretched:" + grayscale + "session/icons/" + data.item.icon;
},
"setPosition": function(data)
{
@@ -280,8 +281,9 @@ g_SelectionPanels.AllyCommand = {
},
"setGraphics": function(data)
{
- data.icon.sprite = "stretched:session/icons/" + data.item.icon;
- data.button.enabled = data.item.count > 0;
+ data.button.enabled = data.item.count != undefined && data.item.count > 0;
+ let grayscale = data.button.enabled ? "" : "grayscale:";
+ data.icon.sprite = "stretched:" + grayscale + "session/icons/" + data.item.icon;
},
"setPosition": function(data)
{
diff --git a/binaries/data/mods/public/gui/session/unit_actions.js b/binaries/data/mods/public/gui/session/unit_actions.js
index 4f4f0f2812..6238e4a57f 100644
--- a/binaries/data/mods/public/gui/session/unit_actions.js
+++ b/binaries/data/mods/public/gui/session/unit_actions.js
@@ -270,9 +270,15 @@ var unitActions =
},
"getActionInfo": function(entState, targetState)
{
- if (!targetState.resourceDropsite)
+ if (!targetState.resourceDropsite || !targetState.resourceDropsite.sharable)
return false;
- if (!playerCheck(entState, targetState, ["Player"]))
+ var playerState = GetSimState().players[entState.player];
+ if (playerState.hasSharedDropsites && targetState.resourceDropsite.shared)
+ {
+ if (!playerCheck(entState, targetState, ["Player", "MutualAlly"]))
+ return false;
+ }
+ else if (!playerCheck(entState, targetState, ["Player"]))
return false;
if (!entState.resourceCarrying || !entState.resourceCarrying.length)
return false;
@@ -872,7 +878,7 @@ var g_EntityCommands =
},
},
// Trading
- "select-trading-goods": {
+ "select-trading-goods": {
"getInfo": function(entState)
{
if (!hasClass(entState, "Market"))
@@ -887,6 +893,34 @@ var g_EntityCommands =
toggleTrade();
},
},
+ // Dropsite sharing
+ "share-dropsite": {
+ "getInfo": function(entState)
+ {
+ if (!entState.resourceDropsite || !entState.resourceDropsite.sharable)
+ return false;
+ let playerState = GetSimState().players[entState.player];
+ if (!playerState.isMutualAlly.some((e, i) => e && i != entState.player))
+ return false;
+ if (entState.resourceDropsite.shared)
+ return {
+ "tooltip": translate("Press to prevent allies from using this dropsite"),
+ "icon": "lock_unlocked.png"
+ };
+ return {
+ "tooltip": translate("Press to allow allies to use this dropsite"),
+ "icon": "lock_locked.png"
+ };
+ },
+ "execute": function(entState)
+ {
+ Engine.PostNetworkCommand({
+ "type": "set-dropsite-sharing",
+ "entities": [entState.id],
+ "shared": !entState.resourceDropsite.shared
+ });
+ },
+ }
};
var g_AllyEntityCommands =
@@ -923,6 +957,29 @@ var g_AllyEntityCommands =
unloadAllByOwner();
},
},
+ // Dropsite sharing
+ "share-dropsite": {
+ "getInfo": function(entState)
+ {
+ if (!GetSimState().players[Engine.GetPlayerID()].hasSharedDropsites)
+ return false;
+ if (!entState.resourceDropsite || !entState.resourceDropsite.sharable)
+ return false;
+ if (entState.resourceDropsite.shared)
+ return {
+ "tooltip": translate("You are allowed to use this dropsite"),
+ "icon": "lock_unlocked.png"
+ };
+ return {
+ "tooltip": translate("The use of this dropsite is prohibited"),
+ "icon": "lock_locked.png"
+ };
+ },
+ "execute": function(entState)
+ {
+ // This command button is always disabled
+ },
+ }
};
function playerCheck(entState, targetState, validPlayers)
diff --git a/binaries/data/mods/public/simulation/ai/petra/baseManager.js b/binaries/data/mods/public/simulation/ai/petra/baseManager.js
index d8e22a977a..97dc211db4 100644
--- a/binaries/data/mods/public/simulation/ai/petra/baseManager.js
+++ b/binaries/data/mods/public/simulation/ai/petra/baseManager.js
@@ -264,6 +264,14 @@ m.BaseManager.prototype.assignResourceToDropsite = function (gameState, dropsite
});
} */
}
+
+ // Allows all allies to use this dropsite except if base anchor to be sure to keep
+ // a minimum of resources for this base
+ Engine.PostCommand(PlayerID, {
+ "type": "set-dropsite-sharing",
+ "entities": [dropsiteId],
+ "shared": dropsiteId !== this.anchorId
+ });
};
// completely remove the dropsite resources from our list.
diff --git a/binaries/data/mods/public/simulation/components/GuiInterface.js b/binaries/data/mods/public/simulation/components/GuiInterface.js
index 8dd6f81a78..9c9a89a1a0 100644
--- a/binaries/data/mods/public/simulation/components/GuiInterface.js
+++ b/binaries/data/mods/public/simulation/components/GuiInterface.js
@@ -106,6 +106,7 @@ GuiInterface.prototype.GetSimulationState = function(player)
"teamsLocked": cmpPlayer.GetLockTeams(),
"cheatsEnabled": cmpPlayer.GetCheatsEnabled(),
"disabledTemplates": cmpPlayer.GetDisabledTemplates(),
+ "hasSharedDropsites": cmpPlayer.HasSharedDropsites(),
"phase": phase,
"isAlly": allies,
"isMutualAlly": mutualAllies,
@@ -516,7 +517,9 @@ GuiInterface.prototype.GetExtendedEntityState = function(player, ent)
let cmpResourceDropsite = Engine.QueryInterface(ent, IID_ResourceDropsite);
if (cmpResourceDropsite)
ret.resourceDropsite = {
- "types": cmpResourceDropsite.GetTypes()
+ "types": cmpResourceDropsite.GetTypes(),
+ "sharable": cmpResourceDropsite.IsSharable(),
+ "shared": cmpResourceDropsite.IsShared()
};
let cmpPromotion = Engine.QueryInterface(ent, IID_Promotion);
diff --git a/binaries/data/mods/public/simulation/components/Player.js b/binaries/data/mods/public/simulation/components/Player.js
index 0458ee1055..dceb2db4c3 100644
--- a/binaries/data/mods/public/simulation/components/Player.js
+++ b/binaries/data/mods/public/simulation/components/Player.js
@@ -3,6 +3,9 @@ function Player() {}
Player.prototype.Schema =
"" +
"" +
+ "" +
+ "" +
+ "" +
"";
Player.prototype.Init = function()
@@ -31,6 +34,7 @@ Player.prototype.Init = function()
this.teamsLocked = false;
this.state = "active"; // game state - one of "active", "defeated", "won"
this.diplomacy = []; // array of diplomatic stances for this player with respect to other players (including gaia and self)
+ this.sharedDropsites = false;
this.formations = [];
this.startCam = undefined;
this.controlAllUnits = false;
@@ -507,6 +511,11 @@ Player.prototype.HasStartingCamera = function()
return (this.startCam !== undefined);
};
+Player.prototype.HasSharedDropsites = function()
+{
+ return this.sharedDropsites;
+};
+
Player.prototype.SetControlAllUnits = function(c)
{
this.controlAllUnits = c;
@@ -680,6 +689,8 @@ Player.prototype.OnResearchFinished = function(msg)
{
if (msg.tech == this.template.SharedLosTech)
this.UpdateSharedLos();
+ else if (msg.tech == this.template.SharedDropsitesTech)
+ this.sharedDropsites = true;
};
Player.prototype.OnDiplomacyChanged = function()
diff --git a/binaries/data/mods/public/simulation/components/ResourceDropsite.js b/binaries/data/mods/public/simulation/components/ResourceDropsite.js
index ee6451994b..c44dc45805 100644
--- a/binaries/data/mods/public/simulation/components/ResourceDropsite.js
+++ b/binaries/data/mods/public/simulation/components/ResourceDropsite.js
@@ -12,9 +12,16 @@ ResourceDropsite.prototype.Schema =
"" +
"" +
"" +
+ "" +
+ "" +
+ "" +
"";
-ResourceDropsite.prototype.Serialize = null;
+ResourceDropsite.prototype.Init = function()
+{
+ this.sharable = this.template.Sharable == "true";
+ this.shared = false;
+};
/**
* Returns the list of resource types accepted by this dropsite.
@@ -33,4 +40,20 @@ ResourceDropsite.prototype.AcceptsType = function(type)
return this.GetTypes().indexOf(type) != -1;
};
+ResourceDropsite.prototype.IsSharable = function()
+{
+ return this.sharable;
+};
+
+ResourceDropsite.prototype.IsShared = function()
+{
+ return this.shared;
+};
+
+ResourceDropsite.prototype.SetSharing = function(value)
+{
+ if (this.sharable)
+ this.shared = value;
+};
+
Engine.RegisterComponentType(IID_ResourceDropsite, "ResourceDropsite", ResourceDropsite);
diff --git a/binaries/data/mods/public/simulation/components/UnitAI.js b/binaries/data/mods/public/simulation/components/UnitAI.js
index 2ce6889fb4..306d47e9a7 100644
--- a/binaries/data/mods/public/simulation/components/UnitAI.js
+++ b/binaries/data/mods/public/simulation/components/UnitAI.js
@@ -4061,8 +4061,17 @@ UnitAI.prototype.FindNearestDropsite = function(genericType)
if (!cmpOwnership || cmpOwnership.GetOwner() == -1)
return undefined;
- // Find dropsites owned by this unit's player
- var players = [cmpOwnership.GetOwner()];
+ // Find dropsites owned by this unit's player or allied ones if allowed
+ var owner = cmpOwnership.GetOwner();
+ var players = [owner];
+ var cmpPlayer = QueryOwnerInterface(this.entity);
+ if (cmpPlayer && cmpPlayer.HasSharedDropsites())
+ {
+ let cmpPlayerManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager);
+ for (let i = 1; i < cmpPlayerManager.GetNumPlayers(); ++i)
+ if (i != owner && cmpPlayer.IsMutualAlly(i))
+ players.push(i);
+ }
var cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
var nearby = cmpRangeManager.ExecuteQuery(this.entity, 0, -1, players, IID_ResourceDropsite);
@@ -4072,7 +4081,13 @@ UnitAI.prototype.FindNearestDropsite = function(genericType)
if (excludeLand)
nearby = nearby.filter(e => Engine.QueryInterface(e, IID_Identity).HasClass("Naval"));
- return nearby.find(ent => Engine.QueryInterface(ent, IID_ResourceDropsite).AcceptsType(genericType));
+ return nearby.find(ent => {
+ let cmpResourceDropsite = Engine.QueryInterface(ent, IID_ResourceDropsite);
+ if (!cmpResourceDropsite.AcceptsType(genericType))
+ return false;
+ let cmpOwnership = Engine.QueryInterface(ent, IID_Ownership);
+ return cmpOwnership.GetOwner() == owner || cmpResourceDropsite.IsShared();
+ });
};
/**
@@ -5753,9 +5768,13 @@ UnitAI.prototype.CanReturnResource = function(target, checkCarriedResource)
return false;
}
- // Verify that the dropsite is owned by this entity's player
+ // Verify that the dropsite is owned by this entity's player (or an a mutual allied if allowed)
var cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership);
- return cmpOwnership && IsOwnedByPlayer(cmpOwnership.GetOwner(), target);
+ var cmpPlayer = QueryOwnerInterface(this.entity);
+ if (cmpOwnership && IsOwnedByPlayer(cmpOwnership.GetOwner(), target))
+ return true;
+ return cmpPlayer && cmpPlayer.HasSharedDropsites() && cmpResourceDropsite.IsShared() &&
+ cmpOwnership && IsOwnedByMutualAllyOfPlayer(cmpOwnership.GetOwner(), target);
};
UnitAI.prototype.CanTrade = function(target)
diff --git a/binaries/data/mods/public/simulation/data/technologies/unlock_shared_dropsites.json b/binaries/data/mods/public/simulation/data/technologies/unlock_shared_dropsites.json
new file mode 100644
index 0000000000..f05631a204
--- /dev/null
+++ b/binaries/data/mods/public/simulation/data/technologies/unlock_shared_dropsites.json
@@ -0,0 +1,13 @@
+{
+ "genericName": "Diaspora",
+ "description": "The extension of trade leads to the permanent establishment of storekeepers and their families in foreign countries, allowing them to exploit these countries wealth.",
+ "cost": { "food": 200, "wood": 200, "stone": 100, "metal": 100 },
+ "requirements": { "class": "Trader", "number": 3 },
+ "requirementsTooltip": "Requires 3 Traders",
+ "supersedes": "unlock_shared_los",
+ "icon": "diaspora.png",
+ "researchTime": 40,
+ "tooltip": "Player can use his allies dropsites.",
+ "modifications": [{ "value": "Player/sharedDropsites", "replace": true }],
+ "soundComplete": "interface/alarm/alarm_upgradearmory.xml"
+}
diff --git a/binaries/data/mods/public/simulation/helpers/Commands.js b/binaries/data/mods/public/simulation/helpers/Commands.js
index aaf99cc9a6..4189a2f625 100644
--- a/binaries/data/mods/public/simulation/helpers/Commands.js
+++ b/binaries/data/mods/public/simulation/helpers/Commands.js
@@ -685,6 +685,16 @@ var g_Commands = {
// Currently nothing. Triggers can read it anyway, and send this
// message to any component you like.
},
+
+ "set-dropsite-sharing": function(player, cmd, data)
+ {
+ for (let ent of data.entities)
+ {
+ let cmpResourceDropsite = Engine.QueryInterface(ent, IID_ResourceDropsite);
+ if (cmpResourceDropsite && cmpResourceDropsite.IsSharable())
+ cmpResourceDropsite.SetSharing(cmd.shared);
+ }
+ },
};
/**
diff --git a/binaries/data/mods/public/simulation/templates/special/player.xml b/binaries/data/mods/public/simulation/templates/special/player.xml
index d25510b1bc..c18e69f649 100644
--- a/binaries/data/mods/public/simulation/templates/special/player.xml
+++ b/binaries/data/mods/public/simulation/templates/special/player.xml
@@ -55,6 +55,7 @@
unlock_shared_los
+ unlock_shared_dropsites
diff --git a/binaries/data/mods/public/simulation/templates/special/player_gaia.xml b/binaries/data/mods/public/simulation/templates/special/player_gaia.xml
index 441b7c051c..1edff0a877 100644
--- a/binaries/data/mods/public/simulation/templates/special/player_gaia.xml
+++ b/binaries/data/mods/public/simulation/templates/special/player_gaia.xml
@@ -2,5 +2,6 @@
+
diff --git a/binaries/data/mods/public/simulation/templates/structures/brit_crannog.xml b/binaries/data/mods/public/simulation/templates/structures/brit_crannog.xml
index 00153ccd6e..82bba4696a 100644
--- a/binaries/data/mods/public/simulation/templates/structures/brit_crannog.xml
+++ b/binaries/data/mods/public/simulation/templates/structures/brit_crannog.xml
@@ -47,6 +47,7 @@
food wood stone metal
+ true
structures/britons/crannog.xml
diff --git a/binaries/data/mods/public/simulation/templates/template_structure_civic_civil_centre.xml b/binaries/data/mods/public/simulation/templates/template_structure_civic_civil_centre.xml
index 472d6ee9c3..c37eeeb214 100644
--- a/binaries/data/mods/public/simulation/templates/template_structure_civic_civil_centre.xml
+++ b/binaries/data/mods/public/simulation/templates/template_structure_civic_civil_centre.xml
@@ -68,10 +68,7 @@
Civic Center
Build to acquire large tracts of territory. Train citizens. Garrison: 20.
-
- Defensive
- CivCentre
-
+ Defensive CivCentre
CivilCentre
structures/civic_centre.png
@@ -97,6 +94,7 @@
food wood stone metal
+ true
@@ -104,9 +102,9 @@
interface/complete/building/complete_civ_center.xml
attack/weapon/arrowfly.xml
attack/destruction/building_collapse_large.xml
- interface/alarm/alarm_alert_0.xml
- interface/alarm/alarm_alert_1.xml
- interface/alarm/alarm_alert_2.xml
+ interface/alarm/alarm_alert_0.xml
+ interface/alarm/alarm_alert_1.xml
+ interface/alarm/alarm_alert_2.xml
diff --git a/binaries/data/mods/public/simulation/templates/template_structure_economic_farmstead.xml b/binaries/data/mods/public/simulation/templates/template_structure_economic_farmstead.xml
index ed4371a52c..552aa151d3 100644
--- a/binaries/data/mods/public/simulation/templates/template_structure_economic_farmstead.xml
+++ b/binaries/data/mods/public/simulation/templates/template_structure_economic_farmstead.xml
@@ -49,6 +49,7 @@
food
+ true
diff --git a/binaries/data/mods/public/simulation/templates/template_structure_economic_market.xml b/binaries/data/mods/public/simulation/templates/template_structure_economic_market.xml
index 9f23b9ae5a..99f12c8bb4 100644
--- a/binaries/data/mods/public/simulation/templates/template_structure_economic_market.xml
+++ b/binaries/data/mods/public/simulation/templates/template_structure_economic_market.xml
@@ -51,6 +51,7 @@
0.7
unlock_shared_los
+ unlock_shared_dropsites
trade_convoys_speed
trade_convoys_armor
trade_gain_01
diff --git a/binaries/data/mods/public/simulation/templates/template_structure_economic_storehouse.xml b/binaries/data/mods/public/simulation/templates/template_structure_economic_storehouse.xml
index f8f658804d..ee0235981b 100644
--- a/binaries/data/mods/public/simulation/templates/template_structure_economic_storehouse.xml
+++ b/binaries/data/mods/public/simulation/templates/template_structure_economic_storehouse.xml
@@ -23,12 +23,7 @@
Storehouse
Dropsite for wood, stone, and metal resources. Research gathering improvements for these resources.
-
- DropsiteWood
- DropsiteMetal
- DropsiteStone
- -ConquestCritical
-
+ DropsiteWood DropsiteMetal DropsiteStone -ConquestCritical
Village Storehouse
structures/storehouse.png
@@ -62,6 +57,7 @@
wood stone metal
+ true
diff --git a/binaries/data/mods/public/simulation/templates/template_structure_military_dock.xml b/binaries/data/mods/public/simulation/templates/template_structure_military_dock.xml
index d66f9d8f77..0ea502c992 100644
--- a/binaries/data/mods/public/simulation/templates/template_structure_military_dock.xml
+++ b/binaries/data/mods/public/simulation/templates/template_structure_military_dock.xml
@@ -45,6 +45,7 @@
food wood stone metal
+ true
@@ -71,7 +72,7 @@
armor_ship_hullsheathing
-
+
40
diff --git a/binaries/data/mods/public/simulation/templates/units/maur_support_elephant.xml b/binaries/data/mods/public/simulation/templates/units/maur_support_elephant.xml
index 134913c856..09e9b807ec 100644
--- a/binaries/data/mods/public/simulation/templates/units/maur_support_elephant.xml
+++ b/binaries/data/mods/public/simulation/templates/units/maur_support_elephant.xml
@@ -44,6 +44,7 @@
food wood stone metal
+ false