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