Index: ps/trunk/binaries/data/mods/public/art/textures/cursors/action-collect-treasure.txt =================================================================== --- ps/trunk/binaries/data/mods/public/art/textures/cursors/action-collect-treasure.txt +++ ps/trunk/binaries/data/mods/public/art/textures/cursors/action-collect-treasure.txt @@ -0,0 +1 @@ +1 1 Index: ps/trunk/binaries/data/mods/public/art/textures/cursors/action-gather-treasure.txt =================================================================== --- ps/trunk/binaries/data/mods/public/art/textures/cursors/action-gather-treasure.txt +++ ps/trunk/binaries/data/mods/public/art/textures/cursors/action-gather-treasure.txt @@ -1 +0,0 @@ -1 1 Index: ps/trunk/binaries/data/mods/public/globalscripts/Resources.js =================================================================== --- ps/trunk/binaries/data/mods/public/globalscripts/Resources.js +++ ps/trunk/binaries/data/mods/public/globalscripts/Resources.js @@ -18,13 +18,6 @@ if (data.code != data.code.toLowerCase()) warn("Resource codes should use lower case: " + data.code); - // Treasures are supported for every specified resource - if (data.code == "treasure") - { - error("Encountered resource with reserved keyword: " + data.code); - continue; - } - this.resourceData.push(data); this.resourceDataObj[data.code] = data; this.resourceCodes.push(data.code); Index: ps/trunk/binaries/data/mods/public/globalscripts/Templates.js =================================================================== --- ps/trunk/binaries/data/mods/public/globalscripts/Templates.js +++ ps/trunk/binaries/data/mods/public/globalscripts/Templates.js @@ -481,6 +481,16 @@ "GainMultiplier": getEntityValue("Trader/GainMultiplier") }; + if (template.Treasure) + { + ret.treasure = { + "collectTime": getEntityValue("Treasure/CollectTime"), + "resources": {} + }; + for (let resource in template.Treasure.Resources) + ret.treasure.resources[resource] = getEntityValue("Treasure/Resources/" + resource); + } + if (template.WallSet) { ret.wallSet = { Index: ps/trunk/binaries/data/mods/public/gui/common/tooltips.js =================================================================== --- ps/trunk/binaries/data/mods/public/gui/common/tooltips.js +++ ps/trunk/binaries/data/mods/public/gui/common/tooltips.js @@ -761,17 +761,48 @@ return ""; let supply = template.supply; - let type = supply.type[0] == "treasure" ? supply.type[1] : supply.type[0]; - // Translation: Label in tooltip showing the resource type and quantity of a given resource supply. return sprintf(translate("%(label)s %(component)s %(amount)s"), { "label": headerFont(translate("Resource Supply:")), - "component": resourceIcon(type), + "component": resourceIcon(supply.type[0]), // Translation: Marks that a resource supply entity has an unending, infinite, supply of its resource. "amount": Number.isFinite(+supply.amount) ? supply.amount : translate("∞") }); } +/** + * @param {Object} template - The entity's template. + * @return {string} - The resources this entity rewards to a collecter. + */ +function getTreasureTooltip(template) +{ + if (!template.treasure) + return ""; + + let resources = {}; + for (let resource of g_ResourceData.GetResources()) + { + let type = resource.code; + if (template.treasure.resources[type]) + resources[type] = template.treasure.resources[type]; + } + + let resourceNames = Object.keys(resources); + if (!resourceNames.length) + return ""; + + return sprintf(translate("%(label)s %(details)s"), { + "label": headerFont(translate("Reward:")), + "details": + resourceNames.map( + type => sprintf(translate("%(resourceIcon)s %(reward)s"), { + "resourceIcon": resourceIcon(type), + "reward": resources[type] + }) + ).join(" ") + }); +} + function getResourceTrickleTooltip(template) { if (!template.resourceTrickle) Index: ps/trunk/binaries/data/mods/public/gui/session/selection_details.js =================================================================== --- ps/trunk/binaries/data/mods/public/gui/session/selection_details.js +++ ps/trunk/binaries/data/mods/public/gui/session/selection_details.js @@ -10,14 +10,6 @@ Engine.GetGUIObjectByName("detailsAreaSingle").hidden = true; } -function getResourceTypeDisplayName(resourceType) -{ - return resourceNameFirstWord( - resourceType.generic == "treasure" ? - resourceType.specific : - resourceType.generic); -} - // Updates the health bar of garrisoned units function updateGarrisonHealthBar(entState, selection) { @@ -228,7 +220,7 @@ unitResourceBar.size = resourceSize; Engine.GetGUIObjectByName("resourceLabel").caption = sprintf(translate("%(resource)s:"), { - "resource": getResourceTypeDisplayName(entState.resourceSupply.type) + "resource": resourceNameFirstWord(entState.resourceSupply.type.generic) }); Engine.GetGUIObjectByName("resourceStats").caption = resources; @@ -347,6 +339,7 @@ getVisibleEntityClassesFormatted, getAurasTooltip, getEntityTooltip, + getTreasureTooltip, showTemplateViewerOnRightClickTooltip ].map(func => func(template))); Index: ps/trunk/binaries/data/mods/public/gui/session/unit_actions.js =================================================================== --- ps/trunk/binaries/data/mods/public/gui/session/unit_actions.js +++ ps/trunk/binaries/data/mods/public/gui/session/unit_actions.js @@ -803,6 +803,49 @@ "specificness": 40, }, + "collect-treasure": + { + "execute": function(target, action, selection, queued) + { + Engine.PostNetworkCommand({ + "type": "collect-treasure", + "entities": selection, + "target": action.target, + "queued": queued, + "formation": g_AutoFormation.getNull() + }); + + Engine.GuiInterfaceCall("PlaySound", { + "name": "order_collect_treasure", + "entity": action.firstAbleEntity + }); + + return true; + }, + "getActionInfo": function(entState, targetState) + { + if (!entState.treasureCollecter || + !targetState || !targetState.treasure) + return false; + + return { + "possible": true, + "cursor": "action-collect-treasure" + }; + }, + "actionCheck": function(target, selection) + { + let actionInfo = getActionInfo("collect-treasure", target, selection); + return actionInfo.possible && { + "type": "collect-treasure", + "cursor": actionInfo.cursor, + "target": target, + "firstAbleEntity": actionInfo.entity + }; + }, + "specificness": 1, + }, + "remove-guard": { "execute": function(target, action, selection, queued) @@ -932,10 +975,7 @@ else if (targetState && targetState.resourceSupply) { let resourceType = targetState.resourceSupply.type; - if (resourceType.generic == "treasure") - cursor = "action-gather-" + resourceType.generic; - else - cursor = "action-gather-" + resourceType.specific; + cursor = "action-gather-" + resourceType.specific; data.command = "gather-near-position"; data.resourceType = resourceType; @@ -946,6 +986,12 @@ data.target = targetState.id; } } + else if (targetState && targetState.treasure) + { + cursor = "action-collect-treasure"; + data.command = "collect-treasure"; + data.target = targetState.id; + } else if (entState.market && targetState && targetState.market && entState.id != targetState.id && (!entState.market.naval || targetState.market.naval) && Index: ps/trunk/binaries/data/mods/public/maps/random/rmgen-common/player.js =================================================================== --- ps/trunk/binaries/data/mods/public/maps/random/rmgen-common/player.js +++ ps/trunk/binaries/data/mods/public/maps/random/rmgen-common/player.js @@ -468,7 +468,7 @@ let count = Math.max(0, Math.ceil( (ccCost[resourceType] - (g_MapSettings.StartingResources || 0)) / - Engine.GetTemplate(treasureTemplate).ResourceSupply.Amount)); + Engine.GetTemplate(treasureTemplate).Treasure.Resources[resourceType])); objects.push(new SimpleObject(treasureTemplate, count, count, 3, 5)); } Index: ps/trunk/binaries/data/mods/public/simulation/ai/common-api/entity.js =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/ai/common-api/entity.js +++ ps/trunk/binaries/data/mods/public/simulation/ai/common-api/entity.js @@ -380,14 +380,11 @@ let [type, subtype] = this.get("ResourceSupply/Type").split('.'); return { "generic": type, "specific": subtype }; }, - // will return either "food", "wood", "stone", "metal" and not treasure. + "getResourceType": function() { if (!this.get("ResourceSupply")) return undefined; - let [type, subtype] = this.get("ResourceSupply/Type").split('.'); - if (type == "treasure") - return subtype; - return type; + return this.get("ResourceSupply/Type").split('.')[0]; }, "getDiminishingReturns": function() { return +(this.get("ResourceSupply/DiminishingReturns") || 1); }, @@ -414,6 +411,17 @@ return types ? types.split(/\s+/) : []; }, + "isTreasure": function() { return this.get("Treasure") !== undefined; }, + + "treasureResources": function() { + if (!this.get("Treasure")) + return undefined; + let ret = {}; + for (let r in this.get("Treasure/Resources")) + ret[r] = +this.get("Treasure/Resources/" + r); + return ret; + }, + "garrisonableClasses": function() { return this.get("GarrisonHolder/List/_string"); }, @@ -557,6 +565,8 @@ "canGuard": function() { return this.get("UnitAI/CanGuard") === "true"; }, "canGarrison": function() { return "Garrisonable" in this._template; }, + + "isTreasureCollecter": function() { return this.get("TreasureCollecter") !== undefined; }, }); @@ -723,9 +733,6 @@ if (!type) return 0; - if (type.generic == "treasure") - return 1000; - let tstring = type.generic + "." + type.specific; let rate = +this.get("ResourceGatherer/BaseSpeed"); rate *= +this.get("ResourceGatherer/Rates/" +tstring); @@ -795,7 +802,7 @@ let restrictedClasses = this.get("Attack/" + type + "/RestrictedClasses/_string"); if (!restrictedClasses || !MatchesClassList(target.classes(), restrictedClasses)) return true; - }; + } return false; }, @@ -852,6 +859,16 @@ return this; }, + "collectTreasure": function(target, queued = false) { + Engine.PostCommand(PlayerID, { + "type": "collect-treasure", + "entities": [this.id()], + "target": target.id(), + "queued": queued + }); + return this; + }, + // moveApart from a point in the opposite direction with a distance dist "moveApart": function(point, dist) { if (this.position() !== undefined) { Index: ps/trunk/binaries/data/mods/public/simulation/ai/common-api/filters.js =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/ai/common-api/filters.js +++ ps/trunk/binaries/data/mods/public/simulation/ai/common-api/filters.js @@ -117,6 +117,20 @@ "dynamicProperties": [] }), + "isTreasure": () => ({ + "func": ent => { + if (!ent.isTreasure()) + return false; + + // Don't go for floating treasures since we might not be able + // to reach them and that kills the pathfinder. + let template = ent.templateName(); + return template != "gaia/treasure/shipwreck_debris" && + template != "gaia/treasure/shipwreck"; + }, + "dynamicProperties": [] + }), + "byResource": resourceType => ({ "func": ent => { if (!ent.resourceSupplyMax()) @@ -130,14 +144,6 @@ if (!ent.isHuntable() || ent.hasClass("SeaCreature")) return false; - // Don't go for floating treasures since we won't be able to reach them and it kills the pathfinder. - if (ent.templateName() == "gaia/treasure/shipwreck_debris" || - ent.templateName() == "gaia/treasure/shipwreck") - return false; - - if (type.generic == "treasure") - return resourceType == type.specific; - return resourceType == type.generic; }, "dynamicProperties": [] Index: ps/trunk/binaries/data/mods/public/simulation/ai/common-api/terrain-analysis.js =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/ai/common-api/terrain-analysis.js +++ ps/trunk/binaries/data/mods/public/simulation/ai/common-api/terrain-analysis.js @@ -397,7 +397,7 @@ } for (let ent of this._entities.values()) { - if (!ent || !ent.position() || !ent.resourceSupplyType() || ent.resourceSupplyType().generic === "treasure") + if (!ent || !ent.position() || !ent.resourceSupplyType()) continue; let resource = ent.resourceSupplyType().generic; if (!this.resourceMaps[resource]) @@ -439,7 +439,7 @@ if (!e.entityObj) continue; let ent = e.entityObj; - if (!ent || !ent.position() || !ent.resourceSupplyType() || ent.resourceSupplyType().generic === "treasure") + if (!ent || !ent.position() || !ent.resourceSupplyType()) continue; let resource = ent.resourceSupplyType().generic; if (!this.resourceMaps[resource]) @@ -458,7 +458,7 @@ if (!e.entity || !this._entities.has(e.entity)) continue; let ent = this._entities.get(e.entity); - if (!ent || !ent.position() || !ent.resourceSupplyType() || ent.resourceSupplyType().generic === "treasure") + if (!ent || !ent.position() || !ent.resourceSupplyType()) continue; let resource = ent.resourceSupplyType().generic; if (!this.resourceMaps[resource]) Index: ps/trunk/binaries/data/mods/public/simulation/ai/petra/baseManager.js =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/ai/petra/baseManager.js +++ ps/trunk/binaries/data/mods/public/simulation/ai/petra/baseManager.js @@ -170,8 +170,6 @@ return; if (supply.hasClass("Field")) // fields are treated separately return; - if (supply.resourceSupplyType().generic == "treasure") // treasures are treated separately - return; // quick accessibility check if (PETRA.getLandAccess(gameState, supply) != accessIndex) return; Index: ps/trunk/binaries/data/mods/public/simulation/ai/petra/entityExtend.js =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/ai/petra/entityExtend.js +++ ps/trunk/binaries/data/mods/public/simulation/ai/petra/entityExtend.js @@ -382,16 +382,13 @@ return false; if (!ent || !ent.position()) return false; - let rates = ent.resourceGatherRates(); - if (!rates || !rates.treasure || rates.treasure <= 0) + if (!ent.isTreasureCollecter) return false; let treasureFound; let distmin = Math.min(); let access = water ? PETRA.getSeaAccess(gameState, ent) : PETRA.getLandAccess(gameState, ent); for (let treasure of gameState.ai.HQ.treasures.values()) { - if (PETRA.IsSupplyFull(gameState, treasure)) - continue; // let some time for the previous gatherer to reach the treasure before trying again let lastGathered = treasure.getMetadata(PlayerID, "lastGathered"); if (lastGathered && gameState.ai.elapsedTime - lastGathered < 20) @@ -414,9 +411,8 @@ if (!treasureFound) return false; treasureFound.setMetadata(PlayerID, "lastGathered", gameState.ai.elapsedTime); - ent.gather(treasureFound); - gameState.ai.HQ.AddTCGatherer(treasureFound.id()); - ent.setMetadata(PlayerID, "supply", treasureFound.id()); + ent.collectTreasure(treasureFound); + ent.setMetadata(PlayerID, "treasure", treasureFound.id()); return true; }; Index: ps/trunk/binaries/data/mods/public/simulation/ai/petra/headquarters.js =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/ai/petra/headquarters.js +++ ps/trunk/binaries/data/mods/public/simulation/ai/petra/headquarters.js @@ -65,10 +65,7 @@ this.navalMap = false; this.navalRegions = {}; - this.treasures = gameState.getEntities().filter(ent => { - let type = ent.resourceSupplyType(); - return type && type.generic == "treasure"; - }); + this.treasures = gameState.getEntities().filter(ent => ent.isTreasure()); this.treasures.registerUpdates(); this.currentPhase = gameState.currentPhase(); this.decayingStructures = new Set(); Index: ps/trunk/binaries/data/mods/public/simulation/ai/petra/startingStrategy.js =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/ai/petra/startingStrategy.js +++ ps/trunk/binaries/data/mods/public/simulation/ai/petra/startingStrategy.js @@ -268,17 +268,17 @@ if (ent.isIdle()) PETRA.gatherTreasure(gameState, ent); // Then count the resources from the treasures being collected - let supplyId = ent.getMetadata(PlayerID, "supply"); - if (!supplyId) + let treasureId = ent.getMetadata(PlayerID, "treasure"); + if (!treasureId) continue; - let supply = gameState.getEntityById(supplyId); - if (!supply || supply.resourceSupplyType().generic != "treasure") + let treasure = gameState.getEntityById(treasureId); + if (!treasure) continue; - let type = supply.resourceSupplyType().specific; - if (!(type in totalExpected)) - continue; - totalExpected[type] += supply.resourceSupplyMax(); - // If we can collect enough resources from these treasures, wait for them + let types = treasure.treasureResources(); + for (let type in types) + if (type in totalExpected) + totalExpected[type] += types[type]; + // If we can collect enough resources from these treasures, wait for them. if (totalExpected.canAfford(new API3.Resources(template.cost()))) return; } Index: ps/trunk/binaries/data/mods/public/simulation/ai/petra/worker.js =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/ai/petra/worker.js +++ ps/trunk/binaries/data/mods/public/simulation/ai/petra/worker.js @@ -220,7 +220,6 @@ let supplyId = ent.unitAIOrderData()[0].target; let supply = gameState.getEntityById(supplyId); if (supply && !supply.hasClass("Field") && !supply.hasClass("Animal") && - supply.resourceSupplyType().generic != "treasure" && supplyId != ent.getMetadata(PlayerID, "supply")) { let nbGatherers = supply.resourceSupplyNumGatherers() + gameState.ai.HQ.GetTCGatherer(supplyId); Index: ps/trunk/binaries/data/mods/public/simulation/components/GuiInterface.js =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/components/GuiInterface.js +++ ps/trunk/binaries/data/mods/public/simulation/components/GuiInterface.js @@ -552,6 +552,17 @@ "rates": cmpResourceTrickle.GetRates() }; + let cmpTreasure = Engine.QueryInterface(ent, IID_Treasure); + if (cmpTreasure) + ret.treasure = { + "collectTime": cmpTreasure.CollectionTime(), + "resources": cmpTreasure.Resources() + }; + + let cmpTreasureCollecter = Engine.QueryInterface(ent, IID_TreasureCollecter); + if (cmpTreasureCollecter) + ret.treasureCollecter = true; + let cmpUnitMotion = Engine.QueryInterface(ent, IID_UnitMotion); if (cmpUnitMotion) ret.speed = { Index: ps/trunk/binaries/data/mods/public/simulation/components/ResourceGatherer.js =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/components/ResourceGatherer.js +++ ps/trunk/binaries/data/mods/public/simulation/components/ResourceGatherer.js @@ -25,7 +25,7 @@ "" + "" + "" + - Resources.BuildSchema("positiveDecimal", ["treasure"], true) + + Resources.BuildSchema("positiveDecimal", [], true) + "" + "" + Resources.BuildSchema("positiveDecimal") + @@ -114,7 +114,7 @@ { let type = r.split("."); - if (type[0] != "treasure" && type.length > 1 && !Resources.GetResource(type[0]).subtypes[type[1]]) + if (!Resources.GetResource(type[0]).subtypes[type[1]]) { error("Resource subtype not found: " + type[0] + "." + type[1]); continue; @@ -165,35 +165,6 @@ }; /** - * Try to gather treasure - * @return 'true' if treasure is successfully gathered, otherwise 'false' - */ -ResourceGatherer.prototype.TryInstantGather = function(target) -{ - let cmpResourceSupply = Engine.QueryInterface(target, IID_ResourceSupply); - let type = cmpResourceSupply.GetType(); - - if (type.generic != "treasure") - return false; - - let status = cmpResourceSupply.TakeResources(cmpResourceSupply.GetCurrentAmount()); - - let cmpPlayer = QueryOwnerInterface(this.entity, IID_Player); - if (cmpPlayer) - cmpPlayer.AddResource(type.specific, status.amount); - - let cmpStatisticsTracker = QueryOwnerInterface(this.entity, IID_StatisticsTracker); - if (cmpStatisticsTracker) - cmpStatisticsTracker.IncreaseTreasuresCollectedCounter(); - - let cmpTrigger = Engine.QueryInterface(SYSTEM_ENTITY, IID_Trigger); - if (cmpTrigger && cmpPlayer) - cmpTrigger.CallEvent("TreasureCollected", { "player": cmpPlayer.GetPlayerID(), "type": type.specific, "amount": status.amount }); - - return true; -}; - -/** * Gather from the target entity. This should only be called after a successful range check, * and if the target has a compatible ResourceSupply. * Call interval will be determined by gather rate, so always gather 1 amount when called. Index: ps/trunk/binaries/data/mods/public/simulation/components/ResourceSupply.js =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/components/ResourceSupply.js +++ ps/trunk/binaries/data/mods/public/simulation/components/ResourceSupply.js @@ -45,7 +45,7 @@ "" + "" + "" + - Resources.BuildChoicesSchema(true, true) + + Resources.BuildChoicesSchema(true) + "" + "" + "" + Index: ps/trunk/binaries/data/mods/public/simulation/components/Treasure.js =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/components/Treasure.js +++ ps/trunk/binaries/data/mods/public/simulation/components/Treasure.js @@ -0,0 +1,111 @@ +function Treasure() {} + +Treasure.prototype.Schema = + "Provides a bonus when taken. E.g. a supply of resources." + + "" + + "1000" + + "" + + "1000" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + Resources.BuildSchema("positiveDecimal") + + "" + + ""; + +Treasure.prototype.Init = function() +{ +}; + +Treasure.prototype.ComputeReward = function() +{ + for (let resource in this.template.Resources) + { + let amount = ApplyValueModificationsToEntity("Treasure/Resources/" + resource, this.template.Resources[resource], this.entity); + if (!amount) + continue; + if (!this.resources) + this.resources = {}; + this.resources[resource] = amount; + } +}; + +/** + * @return {Object} - The resources given by this treasure. + */ +Treasure.prototype.Resources = function() +{ + return this.resources || {}; +}; + +/** + * @return {number} - The time in miliseconds it takes to collect this treasure. + */ +Treasure.prototype.CollectionTime = function() +{ + return +this.template.CollectTime; +}; + +/** + * @param {number} entity - The entity collecting us. + * @return {boolean} - Whether the reward was granted. + */ +Treasure.prototype.Reward = function(entity) +{ + if (this.isTaken) + return false; + + let cmpPlayer = QueryOwnerInterface(entity); + if (!cmpPlayer) + return false; + + let cmpFogging = Engine.QueryInterface(this.entity, IID_Fogging); + if (cmpFogging) + cmpFogging.Activate(); + + if (this.resources) + cmpPlayer.AddResources(this.resources); + + let cmpStatisticsTracker = QueryOwnerInterface(this.entity, IID_StatisticsTracker); + if (cmpStatisticsTracker) + cmpStatisticsTracker.IncreaseTreasuresCollectedCounter(); + + let cmpTrigger = Engine.QueryInterface(SYSTEM_ENTITY, IID_Trigger); + cmpTrigger.CallEvent("TreasureCollected", { + "player": cmpPlayer.GetPlayerID(), + "treasure": this.entity + }); + + this.isTaken = true; + Engine.DestroyEntity(this.entity); + return true; +}; + +/** + * We might live long enough for a collecting entity + * to find us again after taking us. + * @return {boolean} - Whether we are taken already. + */ +Treasure.prototype.IsAvailable = function() +{ + return !this.isTaken; +}; + +Treasure.prototype.OnOwnershipChanged = function(msg) +{ + if (msg.to != INVALID_PLAYER) + this.ComputeReward(); +}; + +Treasure.prototype.OnValueModification = function(msg) +{ + if (msg.component != "Treasure") + return; + this.ComputeReward(); +}; + +Engine.RegisterComponentType(IID_Treasure, "Treasure", Treasure); Index: ps/trunk/binaries/data/mods/public/simulation/components/TreasureCollecter.js =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/components/TreasureCollecter.js +++ ps/trunk/binaries/data/mods/public/simulation/components/TreasureCollecter.js @@ -0,0 +1,119 @@ +function TreasureCollecter() {} + +TreasureCollecter.prototype.Schema = + "Defines the treasure collecting abilities." + + "" + + "2.0" + + "" + + "" + + "" + + ""; + +TreasureCollecter.prototype.Init = function() +{ +}; + +/** + * @return {Object} - Min/Max range at which this entity can claim a treasure. + */ +TreasureCollecter.prototype.GetRange = function() +{ + return { "min": 0, "max": +this.template.MaxDistance }; +}; + +/** + * @param {number} target - Entity ID of the target. + * @return {boolean} - Whether we can collect from the target. + */ +TreasureCollecter.prototype.CanCollect = function(target) +{ + let cmpTreasure = Engine.QueryInterface(target, IID_Treasure); + return cmpTreasure && cmpTreasure.IsAvailable(); +}; + +/** + * @param {number} target - The target to collect. + * @param {number} callerIID - The IID to notify on specific events. + * + * @return {boolean} - Whether we started collecting. + */ +TreasureCollecter.prototype.StartCollecting = function(target, callerIID) +{ + if (this.target) + this.StopCollecting(); + + let cmpTreasure = Engine.QueryInterface(target, IID_Treasure); + if (!cmpTreasure || !cmpTreasure.IsAvailable()) + return false; + + this.target = target; + this.callerIID = callerIID; + + // ToDo: Implement rate modifiers. + let cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer); + this.timer = cmpTimer.SetTimeout(this.entity, IID_TreasureCollecter, "CollectTreasure", cmpTreasure.CollectionTime(), null); + + return true; +}; + +/** + * @param {string} reason - The reason why we stopped collecting, used to notify the caller. + */ +TreasureCollecter.prototype.StopCollecting = function(reason) +{ + if (this.timer) + { + let cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer); + cmpTimer.CancelTimer(this.timer); + delete this.timer; + } + delete this.target; + + // The callerIID component may start gathering again, + // replacing the callerIID, which gets deleted after + // the callerIID has finished. Hence save the data. + let callerIID = this.callerIID; + delete this.callerIID; + + if (reason && callerIID) + { + let component = Engine.QueryInterface(this.entity, callerIID); + if (component) + component.ProcessMessage(reason, null); + } +}; + +/** + * @params - Data and lateness are unused. + */ +TreasureCollecter.prototype.CollectTreasure = function(data, lateness) +{ + let cmpTreasure = Engine.QueryInterface(this.target, IID_Treasure); + if (!cmpTreasure || !cmpTreasure.IsAvailable()) + { + this.StopCollecting("TargetInvalidated"); + return; + } + + if (!this.IsTargetInRange(this.target)) + { + this.StopCollecting("OutOfRange"); + return; + } + + cmpTreasure.Reward(this.entity); + this.StopCollecting("TargetInvalidated"); +}; + +/** + * @param {number} - The entity ID of the target to check. + * @return {boolean} - Whether this entity is in range of its target. + */ +TreasureCollecter.prototype.IsTargetInRange = function(target) +{ + let range = this.GetRange(); + let cmpObstructionManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_ObstructionManager); + return cmpObstructionManager.IsInTargetRange(this.entity, target, range.min, range.max, false); +}; + +Engine.RegisterComponentType(IID_TreasureCollecter, "TreasureCollecter", TreasureCollecter); Index: ps/trunk/binaries/data/mods/public/simulation/components/UnitAI.js =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/components/UnitAI.js +++ ps/trunk/binaries/data/mods/public/simulation/components/UnitAI.js @@ -477,9 +477,8 @@ } // If the unit is full go to the nearest dropsite instead of trying to gather. - // Unless our target is a treasure which we cannot be full enough with (we can't carry treasures). let cmpResourceGatherer = Engine.QueryInterface(this.entity, IID_ResourceGatherer); - if (msg.data.type.generic !== "treasure" && cmpResourceGatherer && !cmpResourceGatherer.CanCarryMore(msg.data.type.generic)) + if (cmpResourceGatherer && !cmpResourceGatherer.CanCarryMore(msg.data.type.generic)) { let nearestDropsite = this.FindNearestDropsite(msg.data.type.generic); if (nearestDropsite) @@ -645,6 +644,15 @@ return this.FinishOrder(); }, + "Order.CollectTreasure": function(msg) { + let cmpTreasureCollecter = Engine.QueryInterface(this.entity, IID_TreasureCollecter); + if (!cmpTreasureCollecter || !cmpTreasureCollecter.CanCollect(msg.data.target)) + return this.FinishOrder(); + + this.SetNextState("COLLECTTREASURE"); + return ACCEPT_ORDER; + }, + // States for the special entity representing a group of units moving in formation: "FORMATIONCONTROLLER": { @@ -2551,14 +2559,9 @@ return; } - // Gather the resources: let cmpResourceGatherer = Engine.QueryInterface(this.entity, IID_ResourceGatherer); - // Try to gather treasure - if (cmpResourceGatherer.TryInstantGather(this.gatheringTarget)) - return; - // If we've already got some resources but they're the wrong type, // drop them first to ensure we're only ever carrying one type if (cmpResourceGatherer.IsCarryingAnythingExcept(resourceType.generic)) @@ -2566,11 +2569,8 @@ this.FaceTowardsTarget(this.order.data.target); - // Collect from the target let status = cmpResourceGatherer.PerformGather(this.gatheringTarget); - // If we've collected as many resources as possible, - // return to the nearest dropsite if (status.filled) { let nearestDropsite = this.FindNearestDropsite(resourceType.generic); @@ -2642,12 +2642,9 @@ if (previousTarget == ent) return false; - if (type.generic == "treasure" && resourceType.generic == "treasure") - return true; - return type.specific == resourceType.specific && (type.specific != "meat" || resourceTemplate == template); - }); + }); if (nearbyResource) { @@ -2874,6 +2871,76 @@ }, }, + "COLLECTTREASURE": { + "enter": function() { + let cmpTreasureCollecter = Engine.QueryInterface(this.entity, IID_TreasureCollecter); + if (!cmpTreasureCollecter || !cmpTreasureCollecter.CanCollect(this.order.data.target)) + { + this.FinishOrder(); + return true; + } + if (this.CheckTargetRange(this.order.data.target, IID_TreasureCollecter)) + this.SetNextState("COLLECTING"); + else + this.SetNextState("APPROACHING"); + return true; + }, + + "leave": function() { + }, + + "APPROACHING": { + "enter": function() { + if (!this.MoveToTargetRange(this.order.data.target, IID_TreasureCollecter)) + { + this.FinishOrder(); + return true; + } + return false; + }, + + "leave": function() { + this.StopMoving(); + }, + + "MovementUpdate": function(msg) { + if (this.CheckTargetRange(this.order.data.target, IID_TreasureCollecter)) + this.SetNextState("COLLECTING"); + else if (msg.likelyFailure) + this.FinishOrder(); + }, + }, + + "COLLECTING": { + "enter": function() { + let cmpTreasureCollecter = Engine.QueryInterface(this.entity, IID_TreasureCollecter); + if (!cmpTreasureCollecter.StartCollecting(this.order.data.target, IID_UnitAI)) + { + this.ProcessMessage("TargetInvalidated"); + return true; + } + this.FaceTowardsTarget(this.order.data.target); + this.SelectAnimation("collecting_treasure"); + return false; + }, + + "leave": function() { + let cmpTreasureCollecter = Engine.QueryInterface(this.entity, IID_TreasureCollecter); + if (cmpTreasureCollecter) + cmpTreasureCollecter.StopCollecting(); + this.ResetAnimation(); + }, + + "OutOfRange": function(msg) { + this.SetNextState("APPROACHING"); + }, + + "TargetInvalidated": function(msg) { + this.FinishOrder(); + }, + }, + }, + "TRADE": { "Attacked": function(msg) { // Ignore attack @@ -4240,6 +4307,16 @@ this.UnitFsm.ProcessMessage(this, {"type": "PackFinished", "packed": msg.packed}); }; +/** + * A general function to process messages sent from components. + * @param {string} type - The type of message to process. + * @param {Object} msg - Optionally extra data to use. + */ +UnitAI.prototype.ProcessMessage = function(type, msg) +{ + this.UnitFsm.ProcessMessage(this, { "type": type, "data": msg }); +}; + //// Helper functions to be called by the FSM //// UnitAI.prototype.GetWalkSpeed = function() @@ -5607,6 +5684,14 @@ this.AddOrder("ReturnResource", { "target": target, "force": true }, queued); }; +/** + * Adds order to collect a treasure to queue, forced by the player. + */ +UnitAI.prototype.CollectTreasure = function(target, queued) +{ + this.AddOrder("CollectTreasure", { "target": target, "force": true }, queued); +}; + UnitAI.prototype.CancelSetupTradeRoute = function(target) { let cmpTrader = Engine.QueryInterface(this.entity, IID_Trader); Index: ps/trunk/binaries/data/mods/public/simulation/components/interfaces/Treasure.js =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/components/interfaces/Treasure.js +++ ps/trunk/binaries/data/mods/public/simulation/components/interfaces/Treasure.js @@ -0,0 +1 @@ +Engine.RegisterInterface("Treasure"); Index: ps/trunk/binaries/data/mods/public/simulation/components/interfaces/TreasureCollecter.js =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/components/interfaces/TreasureCollecter.js +++ ps/trunk/binaries/data/mods/public/simulation/components/interfaces/TreasureCollecter.js @@ -0,0 +1 @@ +Engine.RegisterInterface("TreasureCollecter"); Index: ps/trunk/binaries/data/mods/public/simulation/components/tests/test_GuiInterface.js =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/components/tests/test_GuiInterface.js +++ ps/trunk/binaries/data/mods/public/simulation/components/tests/test_GuiInterface.js @@ -32,6 +32,8 @@ Engine.LoadComponentScript("interfaces/Trader.js"); Engine.LoadComponentScript("interfaces/TurretHolder.js"); Engine.LoadComponentScript("interfaces/Timer.js"); +Engine.LoadComponentScript("interfaces/Treasure.js"); +Engine.LoadComponentScript("interfaces/TreasureCollecter.js"); Engine.LoadComponentScript("interfaces/StatisticsTracker.js"); Engine.LoadComponentScript("interfaces/StatusEffectsReceiver.js"); Engine.LoadComponentScript("interfaces/UnitAI.js"); Index: ps/trunk/binaries/data/mods/public/simulation/components/tests/test_Treasure.js =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/components/tests/test_Treasure.js +++ ps/trunk/binaries/data/mods/public/simulation/components/tests/test_Treasure.js @@ -0,0 +1,56 @@ +Resources = { + "BuildSchema": () => { + let schema = ""; + for (let res of ["food", "metal"]) + { + for (let subtype in ["meat", "grain"]) + schema += "" + res + "." + subtype + ""; + schema += " treasure." + res + ""; + } + return "" + schema + ""; + } +}; + +Engine.LoadHelperScript("Player.js"); +Engine.LoadComponentScript("interfaces/StatisticsTracker.js"); +Engine.LoadComponentScript("interfaces/Treasure.js"); +Engine.LoadComponentScript("interfaces/Trigger.js"); +Engine.LoadComponentScript("Treasure.js"); +Engine.LoadComponentScript("Trigger.js"); + +Engine.RegisterGlobal("ApplyValueModificationsToEntity", (prop, oVal, ent) => oVal); +ConstructComponent(SYSTEM_ENTITY, "Trigger", {}); + +const entity = 11; +let treasurer = 12; +let treasurerOwner = 1; + +let cmpTreasure = ConstructComponent(entity, "Treasure", { + "CollectTime": "1000", + "Resources": { + "Food": "10" + } +}); +cmpTreasure.OnOwnershipChanged({ "to": 0 }); + +TS_ASSERT(!cmpTreasure.Reward(treasurer)); + +AddMock(treasurer, IID_Ownership, { + "GetOwner": () => treasurerOwner +}); + +AddMock(SYSTEM_ENTITY, IID_PlayerManager, { + "GetPlayerByID": (id) => treasurerOwner +}); + +let cmpPlayer = AddMock(treasurerOwner, IID_Player, { + "AddResources": (type, amount) => {}, + "GetPlayerID": () => treasurerOwner +}); +let spy = new Spy(cmpPlayer, "AddResources"); +TS_ASSERT(cmpTreasure.Reward(treasurer)); +TS_ASSERT_EQUALS(spy._called, 1); + +// Don't allow collecting twice. +TS_ASSERT(!cmpTreasure.Reward(treasurer)); +TS_ASSERT_EQUALS(spy._called, 1); Index: ps/trunk/binaries/data/mods/public/simulation/components/tests/test_TreasureCollecter.js =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/components/tests/test_TreasureCollecter.js +++ ps/trunk/binaries/data/mods/public/simulation/components/tests/test_TreasureCollecter.js @@ -0,0 +1,47 @@ +Engine.LoadHelperScript("Player.js"); +Engine.LoadComponentScript("interfaces/Timer.js"); +Engine.LoadComponentScript("interfaces/Treasure.js"); +Engine.LoadComponentScript("interfaces/TreasureCollecter.js"); +Engine.LoadComponentScript("interfaces/UnitAI.js"); +Engine.LoadComponentScript("Timer.js"); +Engine.LoadComponentScript("TreasureCollecter.js"); + +AddMock(SYSTEM_ENTITY, IID_ObstructionManager, { + "IsInTargetRange": () => true +}); + +const entity = 11; +let treasure = 12; +let cmpTimer = ConstructComponent(SYSTEM_ENTITY, "Timer", {}); + +let cmpTreasurer = ConstructComponent(entity, "TreasureCollecter", { + "MaxDistance": "2.0" +}); + +TS_ASSERT(!cmpTreasurer.StartCollecting(treasure)); + +let cmpTreasure = AddMock(treasure, IID_Treasure, { + "Reward": (ent) => true, + "CollectionTime": () => 1000, + "IsAvailable": () => true +}); +let spyTreasure = new Spy(cmpTreasure, "Reward"); +TS_ASSERT(cmpTreasurer.StartCollecting(treasure)); +cmpTimer.OnUpdate({ "turnLength": 1 }); +TS_ASSERT_EQUALS(spyTreasure._called, 1); + +// Test that starting to collect twice merely collects once. +spyTreasure._called = 0; +TS_ASSERT(cmpTreasurer.StartCollecting(treasure)); +TS_ASSERT(cmpTreasurer.StartCollecting(treasure)); +cmpTimer.OnUpdate({ "turnLength": 1 }); +TS_ASSERT_EQUALS(spyTreasure._called, 1); + +// Test callback is called. +let cmpUnitAI = AddMock(entity, IID_UnitAI, { + "ProcessMessage": (type, data) => TS_ASSERT_EQUALS(type, "TargetInvalidated") +}); +let spyUnitAI = new Spy(cmpUnitAI, "ProcessMessage"); +TS_ASSERT(cmpTreasurer.StartCollecting(treasure, IID_UnitAI)); +cmpTimer.OnUpdate({ "turnLength": 1 }); +TS_ASSERT_EQUALS(spyUnitAI._called, 1); Index: ps/trunk/binaries/data/mods/public/simulation/components/tests/test_Treasures.js =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/components/tests/test_Treasures.js +++ ps/trunk/binaries/data/mods/public/simulation/components/tests/test_Treasures.js @@ -0,0 +1,79 @@ +Resources = { + "GetCodes": () => ["food", "metal", "stone", "wood"], + "GetTradableCodes": () => ["food", "metal", "stone", "wood"], + "GetBarterableCodes": () => ["food", "metal", "stone", "wood"], + "BuildSchema": () => { + let schema = ""; + for (let res of ["food", "metal"]) + { + for (let subtype in ["meat", "grain"]) + schema += "" + res + "." + subtype + ""; + schema += " treasure." + res + ""; + } + return "" + schema + ""; + }, + "GetResource": (type) => { + return { + "subtypes": { + "meat": "meat", + "grain": "grain" + } + }; + } +}; + +Engine.LoadHelperScript("Player.js"); +Engine.LoadComponentScript("interfaces/Player.js"); +Engine.LoadComponentScript("interfaces/StatisticsTracker.js"); +Engine.LoadComponentScript("interfaces/Treasure.js"); +Engine.LoadComponentScript("interfaces/TreasureCollecter.js"); +Engine.LoadComponentScript("interfaces/Timer.js"); +Engine.LoadComponentScript("interfaces/Trigger.js"); +Engine.LoadComponentScript("interfaces/UnitAI.js"); +Engine.LoadComponentScript("Player.js"); +Engine.LoadComponentScript("Timer.js"); +Engine.LoadComponentScript("Treasure.js"); +Engine.LoadComponentScript("TreasureCollecter.js"); +Engine.LoadComponentScript("Trigger.js"); + +let cmpTimer = ConstructComponent(SYSTEM_ENTITY, "Timer", {}); +Engine.RegisterGlobal("ApplyValueModificationsToEntity", (prop, oVal, ent) => oVal); +ConstructComponent(SYSTEM_ENTITY, "Trigger", {}); + +const treasure = 11; +const treasurer = 12; +const owner = 1; + +AddMock(treasurer, IID_Ownership, { + "GetOwner": () => owner +}); + +AddMock(SYSTEM_ENTITY, IID_PlayerManager, { + "GetPlayerByID": (id) => owner +}); + +AddMock(SYSTEM_ENTITY, IID_ObstructionManager, { + "IsInTargetRange": (ent, target, min, max, invert) => true +}); + +let cmpPlayer = ConstructComponent(owner, "Player", { + "SpyCostMultiplier": 1, + "BarterMultiplier": {} +}); +let playerSpy = new Spy(cmpPlayer, "AddResources"); + +let cmpTreasure = ConstructComponent(treasure, "Treasure", { + "CollectTime": "1000", + "Resources": { + "Food": "10" + } +}); +cmpTreasure.OnOwnershipChanged({ "to": 0 }); + +let cmpTreasurer = ConstructComponent(treasurer, "TreasureCollecter", { + "MaxDistance": "2.0" +}); + +TS_ASSERT(cmpTreasurer.StartCollecting(treasure)); +cmpTimer.OnUpdate({ "turnLength": 1 }); +TS_ASSERT_EQUALS(playerSpy._called, 1); Index: ps/trunk/binaries/data/mods/public/simulation/data/technologies/unit_mercenary.json =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/data/technologies/unit_mercenary.json +++ ps/trunk/binaries/data/mods/public/simulation/data/technologies/unit_mercenary.json @@ -16,15 +16,7 @@ { "value": "Loot/metal", "replace": 6, "affects": "Infantry" }, { "value": "Loot/metal", "replace": 8, "affects": "Cavalry" }, { "value": "Loot/metal", "replace": 12, "affects": "Elephant" }, - { "value": "ResourceGatherer/Rates/food.fish", "replace": 0 }, - { "value": "ResourceGatherer/Rates/food.fruit", "replace": 0 }, - { "value": "ResourceGatherer/Rates/food.grain", "replace": 0 }, - { "value": "ResourceGatherer/Rates/food.meat", "replace": 0 }, - { "value": "ResourceGatherer/Rates/wood.tree", "replace": 0 }, - { "value": "ResourceGatherer/Rates/wood.ruins", "replace": 0 }, - { "value": "ResourceGatherer/Rates/stone.rock", "replace": 0 }, - { "value": "ResourceGatherer/Rates/stone.ruins", "replace": 0 }, - { "value": "ResourceGatherer/Rates/metal.ore", "replace": 0 } + { "value": "ResourceGatherer/BaseSpeed", "replace": 0 } ], "affects": ["Mercenary !Champion"] } Index: ps/trunk/binaries/data/mods/public/simulation/helpers/Commands.js =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/helpers/Commands.js +++ ps/trunk/binaries/data/mods/public/simulation/helpers/Commands.js @@ -72,6 +72,13 @@ Cheat(cmd); }, + "collect-treasure": function(player, cmd, data) + { + GetFormationUnitAIs(data.entities, player, cmd, data.formation).forEach(cmpUnitAI => { + cmpUnitAI.CollectTreasure(cmd.target, cmd.queued); + }); + }, + "diplomacy": function(player, cmd, data) { let cmpCeasefireManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_CeasefireManager); Index: ps/trunk/binaries/data/mods/public/simulation/helpers/RallyPointCommands.js =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/helpers/RallyPointCommands.js +++ ps/trunk/binaries/data/mods/public/simulation/helpers/RallyPointCommands.js @@ -97,6 +97,14 @@ "queued": true }); break; + case "collect-treasure": + ret.push({ + "type": "collect-treasure", + "entities": spawnedEnts, + "target": data[i].target, + "queued": true, + }); + break; default: ret.push({ "type": "walk", Index: ps/trunk/binaries/data/mods/public/simulation/helpers/Resources.js =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/helpers/Resources.js +++ ps/trunk/binaries/data/mods/public/simulation/helpers/Resources.js @@ -4,7 +4,7 @@ * To prevent validation errors, disabled resources are included in the schema. * * @param datatype - The datatype of the element - * @param additional - Array of additional data elements. Time, xp, treasure, etc. + * @param additional - Array of additional data elements. Time, xp, etc. * @param subtypes - If true, resource subtypes will be included as well. * @return RelaxNG schema string */ @@ -47,15 +47,6 @@ "" + ""; - if (additional.indexOf("treasure") !== -1) - for (let res of resCodes) - schema += - "" + - "" + - datatype + - "" + - ""; - return "" + schema + ""; }; @@ -63,29 +54,19 @@ * Builds the value choices for a RelaxNG `` object, based on currently valid resources. * * @oaram subtypes - If set to true, the choices returned will be resource subtypes, rather than main types - * @param treasure - If set to true, the pseudo resource 'treasure' (or its subtypes) will be included * @return String of RelaxNG Schema `` values. */ -Resources.prototype.BuildChoicesSchema = function(subtypes = false, treasure = false) +Resources.prototype.BuildChoicesSchema = function(subtypes = false) { let schema = ""; if (!subtypes) - { - let resCodes = this.resourceData.map(resource => resource.code); - if (treasure) - resCodes.push("treasure"); - for (let res of resCodes) + for (let res of this.resourceData.map(resource => resource.code)) schema += "" + res + ""; - } else for (let res of this.resourceData) - { for (let subtype in res.subtypes) schema += "" + res.code + "." + subtype + ""; - if (treasure) - schema += "" + "treasure." + res.code + ""; - } return "" + schema + ""; }; Index: ps/trunk/binaries/data/mods/public/simulation/helpers/Setup.js =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/helpers/Setup.js +++ ps/trunk/binaries/data/mods/public/simulation/helpers/Setup.js @@ -23,12 +23,8 @@ } if (settings.DisableTreasures) - for (let ent of Engine.GetEntitiesWithInterface(IID_ResourceSupply)) - { - let cmpResourceSupply = Engine.QueryInterface(ent, IID_ResourceSupply); - if (cmpResourceSupply.GetType().generic == "treasure") - Engine.DestroyEntity(ent); - } + for (let ent of Engine.GetEntitiesWithInterface(IID_Treasure)) + Engine.DestroyEntity(ent); let cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager); if (cmpRangeManager) Index: ps/trunk/binaries/data/mods/public/simulation/templates/gaia/treasure/food_barrel.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/gaia/treasure/food_barrel.xml +++ ps/trunk/binaries/data/mods/public/simulation/templates/gaia/treasure/food_barrel.xml @@ -8,10 +8,6 @@ Food Treasure gaia/special_treasure_food.png - - 100 - treasure.food - @@ -20,6 +16,11 @@ + + + 100 + + props/special/eyecandy/barrel_a.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/gaia/treasure/food_barrels_buried.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/gaia/treasure/food_barrels_buried.xml +++ ps/trunk/binaries/data/mods/public/simulation/templates/gaia/treasure/food_barrels_buried.xml @@ -15,10 +15,11 @@ false 0.0 - - 200 - treasure.food - + + + 200 + + props/special/eyecandy/barrels_buried.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/gaia/treasure/food_bin.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/gaia/treasure/food_bin.xml +++ ps/trunk/binaries/data/mods/public/simulation/templates/gaia/treasure/food_bin.xml @@ -11,10 +11,11 @@ - - 300 - treasure.food - + + + 300 + + props/special/eyecandy/produce_bin_a.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/gaia/treasure/food_crate.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/gaia/treasure/food_crate.xml +++ ps/trunk/binaries/data/mods/public/simulation/templates/gaia/treasure/food_crate.xml @@ -11,10 +11,11 @@ - - 200 - treasure.food - + + + 200 + + props/special/eyecandy/crate_a.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/gaia/treasure/food_jars.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/gaia/treasure/food_jars.xml +++ ps/trunk/binaries/data/mods/public/simulation/templates/gaia/treasure/food_jars.xml @@ -11,10 +11,11 @@ - - 300 - treasure.food - + + + 300 + + props/special/eyecandy/amphorae.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/gaia/treasure/food_persian_big.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/gaia/treasure/food_persian_big.xml +++ ps/trunk/binaries/data/mods/public/simulation/templates/gaia/treasure/food_persian_big.xml @@ -11,10 +11,11 @@ - - 600 - treasure.food - + + + 600 + + props/special/eyecandy/treasure_persian_food_big.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/gaia/treasure/food_persian_small.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/gaia/treasure/food_persian_small.xml +++ ps/trunk/binaries/data/mods/public/simulation/templates/gaia/treasure/food_persian_small.xml @@ -11,10 +11,11 @@ - - 400 - treasure.food - + + + 400 + + props/special/eyecandy/treasure_persian_food_small.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/gaia/treasure/golden_fleece.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/gaia/treasure/golden_fleece.xml +++ ps/trunk/binaries/data/mods/public/simulation/templates/gaia/treasure/golden_fleece.xml @@ -7,10 +7,11 @@ Golden Fleece - - 1000 - treasure.metal - + + + 1000 + + special/golden_fleece.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/gaia/treasure/metal.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/gaia/treasure/metal.xml +++ ps/trunk/binaries/data/mods/public/simulation/templates/gaia/treasure/metal.xml @@ -7,15 +7,16 @@ Secret Box - - 300 - treasure.metal - + + + 300 + + props/special/eyecandy/barrel_a.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/gaia/treasure/metal_persian_big.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/gaia/treasure/metal_persian_big.xml +++ ps/trunk/binaries/data/mods/public/simulation/templates/gaia/treasure/metal_persian_big.xml @@ -10,15 +10,16 @@ - - 500 - treasure.metal - + + + 500 + + props/special/eyecandy/treasure_persian_metal_big.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/gaia/treasure/metal_persian_small.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/gaia/treasure/metal_persian_small.xml +++ ps/trunk/binaries/data/mods/public/simulation/templates/gaia/treasure/metal_persian_small.xml @@ -10,15 +10,16 @@ - - 300 - treasure.metal - + + + 300 + + props/special/eyecandy/treasure_persian_metal_small.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/gaia/treasure/pegasus.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/gaia/treasure/pegasus.xml +++ ps/trunk/binaries/data/mods/public/simulation/templates/gaia/treasure/pegasus.xml @@ -7,10 +7,11 @@ Pegasus - - 1000 - treasure.metal - + + + 1000 + + special/pegasus.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/gaia/treasure/shipwreck.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/gaia/treasure/shipwreck.xml +++ ps/trunk/binaries/data/mods/public/simulation/templates/gaia/treasure/shipwreck.xml @@ -14,10 +14,11 @@ true 0.0 - - 500 - treasure.wood - + + + 500 + + props/special/eyecandy/shipwreck_ram_side.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/gaia/treasure/shipwreck_debris.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/gaia/treasure/shipwreck_debris.xml +++ ps/trunk/binaries/data/mods/public/simulation/templates/gaia/treasure/shipwreck_debris.xml @@ -17,10 +17,11 @@ true 0.0 - - 200 - treasure.food - + + + 200 + + props/special/eyecandy/barrels_floating.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/gaia/treasure/shipwreck_ram_bow.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/gaia/treasure/shipwreck_ram_bow.xml +++ ps/trunk/binaries/data/mods/public/simulation/templates/gaia/treasure/shipwreck_ram_bow.xml @@ -14,10 +14,11 @@ true 0.0 - - 550 - treasure.wood - + + + 550 + + props/special/eyecandy/shipwreck_ram_bow.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/gaia/treasure/shipwreck_sail_boat.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/gaia/treasure/shipwreck_sail_boat.xml +++ ps/trunk/binaries/data/mods/public/simulation/templates/gaia/treasure/shipwreck_sail_boat.xml @@ -14,10 +14,11 @@ true 0.0 - - 400 - treasure.wood - + + + 400 + + props/special/eyecandy/shipwreck_sail_boat.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/gaia/treasure/shipwreck_sail_boat_cut.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/gaia/treasure/shipwreck_sail_boat_cut.xml +++ ps/trunk/binaries/data/mods/public/simulation/templates/gaia/treasure/shipwreck_sail_boat_cut.xml @@ -14,10 +14,11 @@ true 0.0 - - 450 - treasure.wood - + + + 450 + + props/special/eyecandy/shipwreck_sail_boat_cut.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/gaia/treasure/standing_stone.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/gaia/treasure/standing_stone.xml +++ ps/trunk/binaries/data/mods/public/simulation/templates/gaia/treasure/standing_stone.xml @@ -10,15 +10,16 @@ - - 300 - treasure.stone - + + + 300 + + props/special/eyecandy/standing_stones.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/gaia/treasure/stone.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/gaia/treasure/stone.xml +++ ps/trunk/binaries/data/mods/public/simulation/templates/gaia/treasure/stone.xml @@ -10,15 +10,16 @@ - - 300 - treasure.stone - + + + 300 + + props/special/eyecandy/stone_pile.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/gaia/treasure/wood.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/gaia/treasure/wood.xml +++ ps/trunk/binaries/data/mods/public/simulation/templates/gaia/treasure/wood.xml @@ -10,15 +10,16 @@ - - 300 - treasure.wood - + + + 300 + + props/special/eyecandy/wood_pile.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/template_gaia_treasure.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/template_gaia_treasure.xml +++ ps/trunk/binaries/data/mods/public/simulation/templates/template_gaia_treasure.xml @@ -16,11 +16,6 @@ - - false - 300 - 1 - @@ -36,4 +31,7 @@ 3.75 + + 1000 + Index: ps/trunk/binaries/data/mods/public/simulation/templates/template_unit.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/template_unit.xml +++ ps/trunk/binaries/data/mods/public/simulation/templates/template_unit.xml @@ -85,19 +85,6 @@ - - 2.0 - 1.0 - - 1 - - - 10 - 10 - 10 - 10 - - @@ -120,6 +107,9 @@ 5.0 + + 2 + aggressive 12.0 Index: ps/trunk/binaries/data/mods/public/simulation/templates/template_unit_catafalque.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/template_unit_catafalque.xml +++ ps/trunk/binaries/data/mods/public/simulation/templates/template_unit_catafalque.xml @@ -28,7 +28,6 @@ pitch-roll - @@ -45,6 +44,7 @@ actor/singlesteps/steps_grass.xml + standground false Index: ps/trunk/binaries/data/mods/public/simulation/templates/template_unit_cavalry.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/template_unit_cavalry.xml +++ ps/trunk/binaries/data/mods/public/simulation/templates/template_unit_cavalry.xml @@ -65,9 +65,6 @@ 20 - 20 - 20 - 20 Index: ps/trunk/binaries/data/mods/public/simulation/templates/template_unit_dog.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/template_unit_dog.xml +++ ps/trunk/binaries/data/mods/public/simulation/templates/template_unit_dog.xml @@ -38,7 +38,6 @@ 100 10 - @@ -65,6 +64,7 @@ WarDog + 1.5 2 Index: ps/trunk/binaries/data/mods/public/simulation/templates/template_unit_fauna.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/template_unit_fauna.xml +++ ps/trunk/binaries/data/mods/public/simulation/templates/template_unit_fauna.xml @@ -21,7 +21,6 @@ 4 - @@ -30,6 +29,7 @@ + passive false Index: ps/trunk/binaries/data/mods/public/simulation/templates/template_unit_infantry.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/template_unit_infantry.xml +++ ps/trunk/binaries/data/mods/public/simulation/templates/template_unit_infantry.xml @@ -100,6 +100,12 @@ 2 0.5 + + 10 + 10 + 10 + 10 + Index: ps/trunk/binaries/data/mods/public/simulation/templates/template_unit_ship.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/template_unit_ship.xml +++ ps/trunk/binaries/data/mods/public/simulation/templates/template_unit_ship.xml @@ -70,6 +70,7 @@ 0.5 6.0 + ship Index: ps/trunk/binaries/data/mods/public/simulation/templates/template_unit_ship_bireme.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/template_unit_ship_bireme.xml +++ ps/trunk/binaries/data/mods/public/simulation/templates/template_unit_ship_bireme.xml @@ -55,7 +55,6 @@ 25 15 - attack/impact/arrow_impact.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/template_unit_ship_fire.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/template_unit_ship_fire.xml +++ ps/trunk/binaries/data/mods/public/simulation/templates/template_unit_ship_fire.xml @@ -44,7 +44,6 @@ - ship-small 1.6 Index: ps/trunk/binaries/data/mods/public/simulation/templates/template_unit_ship_fishing.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/template_unit_ship_fishing.xml +++ ps/trunk/binaries/data/mods/public/simulation/templates/template_unit_ship_fishing.xml @@ -48,9 +48,9 @@ 6.0 + 1.0 1.8 - 40 Index: ps/trunk/binaries/data/mods/public/simulation/templates/template_unit_ship_merchant.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/template_unit_ship_merchant.xml +++ ps/trunk/binaries/data/mods/public/simulation/templates/template_unit_ship_merchant.xml @@ -34,13 +34,13 @@ - - 12.0 - 0.75 0.2 + + 12 + passive false Index: ps/trunk/binaries/data/mods/public/simulation/templates/template_unit_ship_quinquereme.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/template_unit_ship_quinquereme.xml +++ ps/trunk/binaries/data/mods/public/simulation/templates/template_unit_ship_quinquereme.xml @@ -59,7 +59,6 @@ 2 - attack/siege/ballist_attack.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/template_unit_ship_trireme.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/template_unit_ship_trireme.xml +++ ps/trunk/binaries/data/mods/public/simulation/templates/template_unit_ship_trireme.xml @@ -58,7 +58,6 @@ 2 - attack/impact/arrow_impact.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/template_unit_support_female_citizen.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/template_unit_support_female_citizen.xml +++ ps/trunk/binaries/data/mods/public/simulation/templates/template_unit_support_female_citizen.xml @@ -85,6 +85,12 @@ 2 0.35 + + 10 + 10 + 10 + 10 + Index: ps/trunk/binaries/data/mods/public/simulation/templates/template_unit_support_slave.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/template_unit_support_slave.xml +++ ps/trunk/binaries/data/mods/public/simulation/templates/template_unit_support_slave.xml @@ -53,6 +53,7 @@ 5 + 2.0 1.0 0.5 @@ -64,9 +65,15 @@ 1.0 5 1.0 - + + 10 + 10 + 10 + 10 + + resource/construction/con_wood.xml