Index: binaries/data/mods/public/simulation/components/GarrisonHolder.js =================================================================== --- binaries/data/mods/public/simulation/components/GarrisonHolder.js +++ binaries/data/mods/public/simulation/components/GarrisonHolder.js @@ -31,6 +31,20 @@ "" + "" + "" + + "" + + "" + + "" + + "" + + "own" + + "ally" + + "neutral" + + "enemy" + + "" + + "" + + "" + + "" + + "" + + "" + "" + "" + "" + @@ -167,7 +181,7 @@ if (!this.IsGarrisoningAllowed()) return false; - if (!IsOwnedByMutualAllyOfEntity(ent, this.entity)) + if (!this.IsAllowedByDiplomacy(ent)) return false; let cmpIdentity = Engine.QueryInterface(ent, IID_Identity); @@ -190,6 +204,8 @@ if (!cmpPosition) return false; + // Turn in when visibly garrisoned and the order is given. (D2367) + if (!this.PerformGarrison(entity)) return false; @@ -505,7 +521,24 @@ GarrisonHolder.prototype.HasEnoughHealth = function() { let cmpHealth = Engine.QueryInterface(this.entity, IID_Health); - return cmpHealth.GetHitpoints() > Math.floor(+this.template.EjectHealth * cmpHealth.GetMaxHitpoints()); + if (cmpHealth) + return cmpHealth.GetHitpoints() > Math.floor(+this.template.EjectHealth * cmpHealth.GetMaxHitpoints()); + return true; +}; + +GarrisonHolder.prototype.IsAllowedByDiplomacy = function(ent) +{ + if (!this.template.Owners) + return IsOwnedByMutualAllyOfEntity(ent, this.entity); + + let owner = INVALID_PLAYER; + let cmpOwner = Engine.QueryInterface(this.entity, IID_Ownership); + if (cmpOwner) + owner = cmpOwner.GetOwner(); + return this.template.Owners.indexOf("own") != -1 && IsOwnedByPlayer(owner, ent) || + this.template.Owners.indexOf("ally") != -1 && IsOwnedByMutualAllyOfEntity(this.entity, ent) || + this.template.Owners.indexOf("neutral") != -1 && IsOwnedByNeutralOfEntity(this.entity, ent) || + this.template.Owners.indexOf("enemy") != -1 && IsOwnedByEnemyOfEntity(this.entity, ent); }; /** @@ -564,7 +597,7 @@ // The ownership change may be on the garrisonholder if (this.entity == msg.entity) { - let entities = this.entities.filter(ent => msg.to == INVALID_PLAYER || !IsOwnedByMutualAllyOfEntity(this.entity, ent)); + let entities = this.entities.filter(ent => msg.to == INVALID_PLAYER || !this.IsAllowedByDiplomacy(ent)); if (entities.length) this.EjectOrKill(entities); @@ -588,7 +621,7 @@ if (point.entity == msg.entity) point.entity = null; } - else if (msg.to == INVALID_PLAYER || !IsOwnedByMutualAllyOfEntity(this.entity, msg.entity)) + else if (msg.to == INVALID_PLAYER || !this.IsAllowedByDiplomacy(msg.entity)) this.EjectOrKill([msg.entity]); } }; @@ -636,7 +669,7 @@ */ GarrisonHolder.prototype.OnDiplomacyChanged = function() { - this.EjectOrKill(this.entities.filter(ent => !IsOwnedByMutualAllyOfEntity(this.entity, ent))); + this.EjectOrKill(this.entities.filter(ent => !this.IsAllowedByDiplomacy(ent))); }; /** Index: binaries/data/mods/public/simulation/components/ResourceSupply.js =================================================================== --- binaries/data/mods/public/simulation/components/ResourceSupply.js +++ binaries/data/mods/public/simulation/components/ResourceSupply.js @@ -25,6 +25,11 @@ "" + "" + "" + + "" + + "" + + "" + + "" + + "" + ""; ResourceSupply.prototype.Init = function() @@ -42,6 +47,15 @@ this.cachedType = { "generic": type, "specific": subtype }; }; +ResourceSupply.prototype.IsMine = function() +{ + let cmpGarrisonHolder = Engine.QueryInterface(this.entity, IID_GarrisonHolder); + if (!cmpGarrisonHolder) + return false; + + return this.template.Mine && this.template.Mine == "true"; +}; + ResourceSupply.prototype.IsInfinite = function() { return !isFinite(+this.template.Amount); Index: binaries/data/mods/public/simulation/components/UnitAI.js =================================================================== --- binaries/data/mods/public/simulation/components/UnitAI.js +++ binaries/data/mods/public/simulation/components/UnitAI.js @@ -2216,6 +2216,17 @@ { this.StopMoving(); this.SetDefaultAnimationVariant(); + + if (cmpSupply.IsMine()) + { + let cmpGarrisonHolder = Engine.QueryInterface(this.gatheringTarget, IID_GarrisonHolder); + if (!cmpGarrisonHolder || !cmpGarrisonHolder.Garrison(this.entity)) + { + this.FinishOrder(); + return true; + } + this.isGarrisoned = true; + } this.FaceTowardsTarget(this.order.data.target); this.SelectAnimation("gather_" + this.order.data.type.specific); } @@ -2238,6 +2249,7 @@ }, "Timer": function(msg) { + let orderData = this.order.data; let resourceTemplate = this.order.data.template; let resourceType = this.order.data.type; @@ -2259,7 +2271,7 @@ return; } - if (!this.CheckTargetRange(this.gatheringTarget, IID_ResourceGatherer)) + if (!this.CheckTargetRange(this.gatheringTarget, IID_ResourceGatherer) && !cmpSupply.IsMine()) { // Try to follow the target if (this.MoveToTargetRange(this.gatheringTarget, IID_ResourceGatherer)) @@ -2299,6 +2311,12 @@ // return to the nearest dropsite if (status.filled) { + if (cmpSupply.IsMine()) + { + let cmpGarrisonHolder = Engine.QueryInterface(this.gatheringTarget, IID_GarrisonHolder); + if (cmpGarrisonHolder && !cmpGarrisonHolder.Unload(this.entity)) + return; + } let nearby = this.FindNearestDropsite(resourceType.generic); if (nearby) { @@ -2307,8 +2325,12 @@ // However mark our target as invalid if it's exhausted, so we don't waste time // trying to gather from it. if (status.exhausted) - this.order.data.target = INVALID_ENTITY; + this.order ? this.order.data.target = INVALID_ENTITY : orderData.target = INVALID_ENTITY; this.PushOrderFront("ReturnResource", { "target": nearby, "force": false }); + + // Needed because the ungarrison order clears the order queue. + if (cmpSupply.IsMine()) + this.PushOrder("Gather", orderData); return; } @@ -2319,7 +2341,17 @@ // Find a new target if the current one is exhausted if (status.exhausted) + { + if (cmpSupply.IsMine()) + { + let cmpGarrisonHolder = Engine.QueryInterface(this.gatheringTarget, IID_GarrisonHolder); + if (cmpGarrisonHolder && !cmpGarrisonHolder.Unload(this.entity)) + return; + orderData.target = INVALID_ENTITY; + this.PushOrder("Gather", orderData); + } this.SetNextState("FINDINGNEWTARGET"); + } }, }, @@ -2952,13 +2984,13 @@ delete this.pickup; } - if (this.IsTurret()) - { - this.SetNextState("IDLE"); + //if (this.IsTurret()) + //{ + this.FinishOrder(); return true; - } + //} - return false; + //return false; } } else @@ -5781,27 +5813,32 @@ UnitAI.prototype.CanGather = function(target) { - if (this.IsTurret()) - return false; // The target must be a valid resource supply, or the mirage of one. - var cmpResourceSupply = QueryMiragedInterface(target, IID_ResourceSupply); + let cmpResourceSupply = QueryMiragedInterface(target, IID_ResourceSupply); if (!cmpResourceSupply) return false; - // Formation controllers should always respond to commands + // Formation controllers should always respond to commands. // (then the individual units can make up their own minds) if (this.IsFormationController()) return true; - // Verify that we're able to respond to Gather commands - var cmpResourceGatherer = Engine.QueryInterface(this.entity, IID_ResourceGatherer); + // Verify that we're able to respond to Gather commands. + let cmpResourceGatherer = Engine.QueryInterface(this.entity, IID_ResourceGatherer); if (!cmpResourceGatherer) return false; - // Verify that we can gather from this target + // Verify that we can gather from this target. if (!cmpResourceGatherer.GetTargetGatherRate(target)) return false; + // If we're a turret and can gather from our parent its okay. + if (this.IsTurret()) + { + let cmpPosition = Engine.QueryInterface(this.entity, IID_Position); + return cmpPosition && cmpPosition.GetTurretParent() == target; + } + // No need to verify ownership as we should be able to gather from // a target regardless of ownership. // No need to call "cmpResourceSupply.IsAvailable()" either because that Index: binaries/data/mods/public/simulation/helpers/Player.js =================================================================== --- binaries/data/mods/public/simulation/helpers/Player.js +++ binaries/data/mods/public/simulation/helpers/Player.js @@ -277,6 +277,16 @@ return IsOwnedByEntityHelper(entity, target, "IsMutualAlly"); } +function IsOwnedByNeutralOfEntity(entity, target) +{ + return IsOwnedByEntityHelper(entity, target, "IsNeutral"); +} + +function IsOwnedByEnemyOfEntity(entity, target) +{ + return IsOwnedByEntityHelper(entity, target, "IsEnemy"); +} + function IsOwnedByEntityHelper(entity, target, check) { // Figure out which player controls us @@ -353,6 +363,8 @@ Engine.RegisterGlobal("QueryBuilderListInterface", QueryBuilderListInterface); Engine.RegisterGlobal("IsOwnedByAllyOfEntity", IsOwnedByAllyOfEntity); Engine.RegisterGlobal("IsOwnedByMutualAllyOfEntity", IsOwnedByMutualAllyOfEntity); +Engine.RegisterGlobal("IsOwnedByNeutralOfEntity", IsOwnedByNeutralOfEntity); +Engine.RegisterGlobal("IsOwnedByEnemyOfEntity", IsOwnedByEnemyOfEntity); Engine.RegisterGlobal("IsOwnedByPlayer", IsOwnedByPlayer); Engine.RegisterGlobal("IsOwnedByGaia", IsOwnedByGaia); Engine.RegisterGlobal("IsOwnedByAllyOfPlayer", IsOwnedByAllyOfPlayer); Index: binaries/data/mods/public/simulation/templates/template_gaia_geo_rock.xml =================================================================== --- binaries/data/mods/public/simulation/templates/template_gaia_geo_rock.xml +++ binaries/data/mods/public/simulation/templates/template_gaia_geo_rock.xml @@ -1,5 +1,19 @@ + + 12 + 0 + Unit + Worker + 0 + own ally neutral enemy + 1 + + + 011.50 + + + Stone Quarry Quarry rock for stone. @@ -11,9 +25,10 @@ false - 1000 + 100 stone.rock 12 + true Index: binaries/data/mods/public/simulation/templates/template_gaia_geo_rock_slabs.xml =================================================================== --- binaries/data/mods/public/simulation/templates/template_gaia_geo_rock_slabs.xml +++ binaries/data/mods/public/simulation/templates/template_gaia_geo_rock_slabs.xml @@ -8,7 +8,7 @@ - 5000 + 100 24