Split treasures from ResourceSupply.
Removes some hardcoding and allows for easier modding of treasures. Refs.: #5888 Differential revision: D3303 Comments by: @Imarok, @Nescio, @Stan, @wraitii This was SVN commit r24989.
This commit is contained in:
parent
0de47dd1ec
commit
ea96e81098
@ -18,13 +18,6 @@ function Resources()
|
|||||||
if (data.code != data.code.toLowerCase())
|
if (data.code != data.code.toLowerCase())
|
||||||
warn("Resource codes should use lower case: " + data.code);
|
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.resourceData.push(data);
|
||||||
this.resourceDataObj[data.code] = data;
|
this.resourceDataObj[data.code] = data;
|
||||||
this.resourceCodes.push(data.code);
|
this.resourceCodes.push(data.code);
|
||||||
|
@ -481,6 +481,16 @@ function GetTemplateDataHelper(template, player, auraTemplates, modifiers = {})
|
|||||||
"GainMultiplier": getEntityValue("Trader/GainMultiplier")
|
"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)
|
if (template.WallSet)
|
||||||
{
|
{
|
||||||
ret.wallSet = {
|
ret.wallSet = {
|
||||||
|
@ -761,17 +761,48 @@ function getResourceSupplyTooltip(template)
|
|||||||
return "";
|
return "";
|
||||||
|
|
||||||
let supply = template.supply;
|
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.
|
// Translation: Label in tooltip showing the resource type and quantity of a given resource supply.
|
||||||
return sprintf(translate("%(label)s %(component)s %(amount)s"), {
|
return sprintf(translate("%(label)s %(component)s %(amount)s"), {
|
||||||
"label": headerFont(translate("Resource Supply:")),
|
"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.
|
// Translation: Marks that a resource supply entity has an unending, infinite, supply of its resource.
|
||||||
"amount": Number.isFinite(+supply.amount) ? supply.amount : translate("∞")
|
"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)
|
function getResourceTrickleTooltip(template)
|
||||||
{
|
{
|
||||||
if (!template.resourceTrickle)
|
if (!template.resourceTrickle)
|
||||||
|
@ -10,14 +10,6 @@ function layoutSelectionMultiple()
|
|||||||
Engine.GetGUIObjectByName("detailsAreaSingle").hidden = true;
|
Engine.GetGUIObjectByName("detailsAreaSingle").hidden = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getResourceTypeDisplayName(resourceType)
|
|
||||||
{
|
|
||||||
return resourceNameFirstWord(
|
|
||||||
resourceType.generic == "treasure" ?
|
|
||||||
resourceType.specific :
|
|
||||||
resourceType.generic);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Updates the health bar of garrisoned units
|
// Updates the health bar of garrisoned units
|
||||||
function updateGarrisonHealthBar(entState, selection)
|
function updateGarrisonHealthBar(entState, selection)
|
||||||
{
|
{
|
||||||
@ -228,7 +220,7 @@ function displaySingle(entState)
|
|||||||
unitResourceBar.size = resourceSize;
|
unitResourceBar.size = resourceSize;
|
||||||
|
|
||||||
Engine.GetGUIObjectByName("resourceLabel").caption = sprintf(translate("%(resource)s:"), {
|
Engine.GetGUIObjectByName("resourceLabel").caption = sprintf(translate("%(resource)s:"), {
|
||||||
"resource": getResourceTypeDisplayName(entState.resourceSupply.type)
|
"resource": resourceNameFirstWord(entState.resourceSupply.type.generic)
|
||||||
});
|
});
|
||||||
Engine.GetGUIObjectByName("resourceStats").caption = resources;
|
Engine.GetGUIObjectByName("resourceStats").caption = resources;
|
||||||
|
|
||||||
@ -347,6 +339,7 @@ function displaySingle(entState)
|
|||||||
getVisibleEntityClassesFormatted,
|
getVisibleEntityClassesFormatted,
|
||||||
getAurasTooltip,
|
getAurasTooltip,
|
||||||
getEntityTooltip,
|
getEntityTooltip,
|
||||||
|
getTreasureTooltip,
|
||||||
showTemplateViewerOnRightClickTooltip
|
showTemplateViewerOnRightClickTooltip
|
||||||
].map(func => func(template)));
|
].map(func => func(template)));
|
||||||
|
|
||||||
|
@ -803,6 +803,49 @@ var g_UnitActions =
|
|||||||
"specificness": 40,
|
"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":
|
"remove-guard":
|
||||||
{
|
{
|
||||||
"execute": function(target, action, selection, queued)
|
"execute": function(target, action, selection, queued)
|
||||||
@ -932,10 +975,7 @@ var g_UnitActions =
|
|||||||
else if (targetState && targetState.resourceSupply)
|
else if (targetState && targetState.resourceSupply)
|
||||||
{
|
{
|
||||||
let resourceType = targetState.resourceSupply.type;
|
let resourceType = targetState.resourceSupply.type;
|
||||||
if (resourceType.generic == "treasure")
|
cursor = "action-gather-" + resourceType.specific;
|
||||||
cursor = "action-gather-" + resourceType.generic;
|
|
||||||
else
|
|
||||||
cursor = "action-gather-" + resourceType.specific;
|
|
||||||
|
|
||||||
data.command = "gather-near-position";
|
data.command = "gather-near-position";
|
||||||
data.resourceType = resourceType;
|
data.resourceType = resourceType;
|
||||||
@ -946,6 +986,12 @@ var g_UnitActions =
|
|||||||
data.target = targetState.id;
|
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 &&
|
else if (entState.market && targetState && targetState.market &&
|
||||||
entState.id != targetState.id &&
|
entState.id != targetState.id &&
|
||||||
(!entState.market.naval || targetState.market.naval) &&
|
(!entState.market.naval || targetState.market.naval) &&
|
||||||
|
@ -468,7 +468,7 @@ function placePlayersNomad(playerClass, constraints)
|
|||||||
|
|
||||||
let count = Math.max(0, Math.ceil(
|
let count = Math.max(0, Math.ceil(
|
||||||
(ccCost[resourceType] - (g_MapSettings.StartingResources || 0)) /
|
(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));
|
objects.push(new SimpleObject(treasureTemplate, count, count, 3, 5));
|
||||||
}
|
}
|
||||||
|
@ -380,14 +380,11 @@ m.Template = m.Class({
|
|||||||
let [type, subtype] = this.get("ResourceSupply/Type").split('.');
|
let [type, subtype] = this.get("ResourceSupply/Type").split('.');
|
||||||
return { "generic": type, "specific": subtype };
|
return { "generic": type, "specific": subtype };
|
||||||
},
|
},
|
||||||
// will return either "food", "wood", "stone", "metal" and not treasure.
|
|
||||||
"getResourceType": function() {
|
"getResourceType": function() {
|
||||||
if (!this.get("ResourceSupply"))
|
if (!this.get("ResourceSupply"))
|
||||||
return undefined;
|
return undefined;
|
||||||
let [type, subtype] = this.get("ResourceSupply/Type").split('.');
|
return this.get("ResourceSupply/Type").split('.')[0];
|
||||||
if (type == "treasure")
|
|
||||||
return subtype;
|
|
||||||
return type;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
"getDiminishingReturns": function() { return +(this.get("ResourceSupply/DiminishingReturns") || 1); },
|
"getDiminishingReturns": function() { return +(this.get("ResourceSupply/DiminishingReturns") || 1); },
|
||||||
@ -414,6 +411,17 @@ m.Template = m.Class({
|
|||||||
return types ? types.split(/\s+/) : [];
|
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"); },
|
"garrisonableClasses": function() { return this.get("GarrisonHolder/List/_string"); },
|
||||||
|
|
||||||
@ -557,6 +565,8 @@ m.Template = m.Class({
|
|||||||
"canGuard": function() { return this.get("UnitAI/CanGuard") === "true"; },
|
"canGuard": function() { return this.get("UnitAI/CanGuard") === "true"; },
|
||||||
|
|
||||||
"canGarrison": function() { return "Garrisonable" in this._template; },
|
"canGarrison": function() { return "Garrisonable" in this._template; },
|
||||||
|
|
||||||
|
"isTreasureCollecter": function() { return this.get("TreasureCollecter") !== undefined; },
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
@ -723,9 +733,6 @@ m.Entity = m.Class({
|
|||||||
if (!type)
|
if (!type)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (type.generic == "treasure")
|
|
||||||
return 1000;
|
|
||||||
|
|
||||||
let tstring = type.generic + "." + type.specific;
|
let tstring = type.generic + "." + type.specific;
|
||||||
let rate = +this.get("ResourceGatherer/BaseSpeed");
|
let rate = +this.get("ResourceGatherer/BaseSpeed");
|
||||||
rate *= +this.get("ResourceGatherer/Rates/" +tstring);
|
rate *= +this.get("ResourceGatherer/Rates/" +tstring);
|
||||||
@ -795,7 +802,7 @@ m.Entity = m.Class({
|
|||||||
let restrictedClasses = this.get("Attack/" + type + "/RestrictedClasses/_string");
|
let restrictedClasses = this.get("Attack/" + type + "/RestrictedClasses/_string");
|
||||||
if (!restrictedClasses || !MatchesClassList(target.classes(), restrictedClasses))
|
if (!restrictedClasses || !MatchesClassList(target.classes(), restrictedClasses))
|
||||||
return true;
|
return true;
|
||||||
};
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
@ -852,6 +859,16 @@ m.Entity = m.Class({
|
|||||||
return this;
|
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 from a point in the opposite direction with a distance dist
|
||||||
"moveApart": function(point, dist) {
|
"moveApart": function(point, dist) {
|
||||||
if (this.position() !== undefined) {
|
if (this.position() !== undefined) {
|
||||||
|
@ -117,6 +117,20 @@ m.Filters = {
|
|||||||
"dynamicProperties": []
|
"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 => ({
|
"byResource": resourceType => ({
|
||||||
"func": ent => {
|
"func": ent => {
|
||||||
if (!ent.resourceSupplyMax())
|
if (!ent.resourceSupplyMax())
|
||||||
@ -130,14 +144,6 @@ m.Filters = {
|
|||||||
if (!ent.isHuntable() || ent.hasClass("SeaCreature"))
|
if (!ent.isHuntable() || ent.hasClass("SeaCreature"))
|
||||||
return false;
|
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;
|
return resourceType == type.generic;
|
||||||
},
|
},
|
||||||
"dynamicProperties": []
|
"dynamicProperties": []
|
||||||
|
@ -397,7 +397,7 @@ m.SharedScript.prototype.createResourceMaps = function()
|
|||||||
}
|
}
|
||||||
for (let ent of this._entities.values())
|
for (let ent of this._entities.values())
|
||||||
{
|
{
|
||||||
if (!ent || !ent.position() || !ent.resourceSupplyType() || ent.resourceSupplyType().generic === "treasure")
|
if (!ent || !ent.position() || !ent.resourceSupplyType())
|
||||||
continue;
|
continue;
|
||||||
let resource = ent.resourceSupplyType().generic;
|
let resource = ent.resourceSupplyType().generic;
|
||||||
if (!this.resourceMaps[resource])
|
if (!this.resourceMaps[resource])
|
||||||
@ -439,7 +439,7 @@ m.SharedScript.prototype.updateResourceMaps = function(events)
|
|||||||
if (!e.entityObj)
|
if (!e.entityObj)
|
||||||
continue;
|
continue;
|
||||||
let ent = e.entityObj;
|
let ent = e.entityObj;
|
||||||
if (!ent || !ent.position() || !ent.resourceSupplyType() || ent.resourceSupplyType().generic === "treasure")
|
if (!ent || !ent.position() || !ent.resourceSupplyType())
|
||||||
continue;
|
continue;
|
||||||
let resource = ent.resourceSupplyType().generic;
|
let resource = ent.resourceSupplyType().generic;
|
||||||
if (!this.resourceMaps[resource])
|
if (!this.resourceMaps[resource])
|
||||||
@ -458,7 +458,7 @@ m.SharedScript.prototype.updateResourceMaps = function(events)
|
|||||||
if (!e.entity || !this._entities.has(e.entity))
|
if (!e.entity || !this._entities.has(e.entity))
|
||||||
continue;
|
continue;
|
||||||
let ent = this._entities.get(e.entity);
|
let ent = this._entities.get(e.entity);
|
||||||
if (!ent || !ent.position() || !ent.resourceSupplyType() || ent.resourceSupplyType().generic === "treasure")
|
if (!ent || !ent.position() || !ent.resourceSupplyType())
|
||||||
continue;
|
continue;
|
||||||
let resource = ent.resourceSupplyType().generic;
|
let resource = ent.resourceSupplyType().generic;
|
||||||
if (!this.resourceMaps[resource])
|
if (!this.resourceMaps[resource])
|
||||||
|
@ -170,8 +170,6 @@ PETRA.BaseManager.prototype.assignResourceToDropsite = function(gameState, drops
|
|||||||
return;
|
return;
|
||||||
if (supply.hasClass("Field")) // fields are treated separately
|
if (supply.hasClass("Field")) // fields are treated separately
|
||||||
return;
|
return;
|
||||||
if (supply.resourceSupplyType().generic == "treasure") // treasures are treated separately
|
|
||||||
return;
|
|
||||||
// quick accessibility check
|
// quick accessibility check
|
||||||
if (PETRA.getLandAccess(gameState, supply) != accessIndex)
|
if (PETRA.getLandAccess(gameState, supply) != accessIndex)
|
||||||
return;
|
return;
|
||||||
|
@ -382,16 +382,13 @@ PETRA.gatherTreasure = function(gameState, ent, water = false)
|
|||||||
return false;
|
return false;
|
||||||
if (!ent || !ent.position())
|
if (!ent || !ent.position())
|
||||||
return false;
|
return false;
|
||||||
let rates = ent.resourceGatherRates();
|
if (!ent.isTreasureCollecter)
|
||||||
if (!rates || !rates.treasure || rates.treasure <= 0)
|
|
||||||
return false;
|
return false;
|
||||||
let treasureFound;
|
let treasureFound;
|
||||||
let distmin = Math.min();
|
let distmin = Math.min();
|
||||||
let access = water ? PETRA.getSeaAccess(gameState, ent) : PETRA.getLandAccess(gameState, ent);
|
let access = water ? PETRA.getSeaAccess(gameState, ent) : PETRA.getLandAccess(gameState, ent);
|
||||||
for (let treasure of gameState.ai.HQ.treasures.values())
|
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 some time for the previous gatherer to reach the treasure before trying again
|
||||||
let lastGathered = treasure.getMetadata(PlayerID, "lastGathered");
|
let lastGathered = treasure.getMetadata(PlayerID, "lastGathered");
|
||||||
if (lastGathered && gameState.ai.elapsedTime - lastGathered < 20)
|
if (lastGathered && gameState.ai.elapsedTime - lastGathered < 20)
|
||||||
@ -414,9 +411,8 @@ PETRA.gatherTreasure = function(gameState, ent, water = false)
|
|||||||
if (!treasureFound)
|
if (!treasureFound)
|
||||||
return false;
|
return false;
|
||||||
treasureFound.setMetadata(PlayerID, "lastGathered", gameState.ai.elapsedTime);
|
treasureFound.setMetadata(PlayerID, "lastGathered", gameState.ai.elapsedTime);
|
||||||
ent.gather(treasureFound);
|
ent.collectTreasure(treasureFound);
|
||||||
gameState.ai.HQ.AddTCGatherer(treasureFound.id());
|
ent.setMetadata(PlayerID, "treasure", treasureFound.id());
|
||||||
ent.setMetadata(PlayerID, "supply", treasureFound.id());
|
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -65,10 +65,7 @@ PETRA.HQ.prototype.init = function(gameState, queues)
|
|||||||
this.navalMap = false;
|
this.navalMap = false;
|
||||||
this.navalRegions = {};
|
this.navalRegions = {};
|
||||||
|
|
||||||
this.treasures = gameState.getEntities().filter(ent => {
|
this.treasures = gameState.getEntities().filter(ent => ent.isTreasure());
|
||||||
let type = ent.resourceSupplyType();
|
|
||||||
return type && type.generic == "treasure";
|
|
||||||
});
|
|
||||||
this.treasures.registerUpdates();
|
this.treasures.registerUpdates();
|
||||||
this.currentPhase = gameState.currentPhase();
|
this.currentPhase = gameState.currentPhase();
|
||||||
this.decayingStructures = new Set();
|
this.decayingStructures = new Set();
|
||||||
|
@ -268,17 +268,17 @@ PETRA.HQ.prototype.buildFirstBase = function(gameState)
|
|||||||
if (ent.isIdle())
|
if (ent.isIdle())
|
||||||
PETRA.gatherTreasure(gameState, ent);
|
PETRA.gatherTreasure(gameState, ent);
|
||||||
// Then count the resources from the treasures being collected
|
// Then count the resources from the treasures being collected
|
||||||
let supplyId = ent.getMetadata(PlayerID, "supply");
|
let treasureId = ent.getMetadata(PlayerID, "treasure");
|
||||||
if (!supplyId)
|
if (!treasureId)
|
||||||
continue;
|
continue;
|
||||||
let supply = gameState.getEntityById(supplyId);
|
let treasure = gameState.getEntityById(treasureId);
|
||||||
if (!supply || supply.resourceSupplyType().generic != "treasure")
|
if (!treasure)
|
||||||
continue;
|
continue;
|
||||||
let type = supply.resourceSupplyType().specific;
|
let types = treasure.treasureResources();
|
||||||
if (!(type in totalExpected))
|
for (let type in types)
|
||||||
continue;
|
if (type in totalExpected)
|
||||||
totalExpected[type] += supply.resourceSupplyMax();
|
totalExpected[type] += types[type];
|
||||||
// If we can collect enough resources from these treasures, wait for them
|
// If we can collect enough resources from these treasures, wait for them.
|
||||||
if (totalExpected.canAfford(new API3.Resources(template.cost())))
|
if (totalExpected.canAfford(new API3.Resources(template.cost())))
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -220,7 +220,6 @@ PETRA.Worker.prototype.update = function(gameState, ent)
|
|||||||
let supplyId = ent.unitAIOrderData()[0].target;
|
let supplyId = ent.unitAIOrderData()[0].target;
|
||||||
let supply = gameState.getEntityById(supplyId);
|
let supply = gameState.getEntityById(supplyId);
|
||||||
if (supply && !supply.hasClass("Field") && !supply.hasClass("Animal") &&
|
if (supply && !supply.hasClass("Field") && !supply.hasClass("Animal") &&
|
||||||
supply.resourceSupplyType().generic != "treasure" &&
|
|
||||||
supplyId != ent.getMetadata(PlayerID, "supply"))
|
supplyId != ent.getMetadata(PlayerID, "supply"))
|
||||||
{
|
{
|
||||||
let nbGatherers = supply.resourceSupplyNumGatherers() + gameState.ai.HQ.GetTCGatherer(supplyId);
|
let nbGatherers = supply.resourceSupplyNumGatherers() + gameState.ai.HQ.GetTCGatherer(supplyId);
|
||||||
|
@ -552,6 +552,17 @@ GuiInterface.prototype.GetEntityState = function(player, ent)
|
|||||||
"rates": cmpResourceTrickle.GetRates()
|
"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);
|
let cmpUnitMotion = Engine.QueryInterface(ent, IID_UnitMotion);
|
||||||
if (cmpUnitMotion)
|
if (cmpUnitMotion)
|
||||||
ret.speed = {
|
ret.speed = {
|
||||||
|
@ -25,7 +25,7 @@ ResourceGatherer.prototype.Schema =
|
|||||||
"<ref name='positiveDecimal'/>" +
|
"<ref name='positiveDecimal'/>" +
|
||||||
"</element>" +
|
"</element>" +
|
||||||
"<element name='Rates' a:help='Per-resource-type gather rate multipliers. If a resource type is not specified then it cannot be gathered by this unit'>" +
|
"<element name='Rates' a:help='Per-resource-type gather rate multipliers. If a resource type is not specified then it cannot be gathered by this unit'>" +
|
||||||
Resources.BuildSchema("positiveDecimal", ["treasure"], true) +
|
Resources.BuildSchema("positiveDecimal", [], true) +
|
||||||
"</element>" +
|
"</element>" +
|
||||||
"<element name='Capacities' a:help='Per-resource-type maximum carrying capacity'>" +
|
"<element name='Capacities' a:help='Per-resource-type maximum carrying capacity'>" +
|
||||||
Resources.BuildSchema("positiveDecimal") +
|
Resources.BuildSchema("positiveDecimal") +
|
||||||
@ -114,7 +114,7 @@ ResourceGatherer.prototype.RecalculateGatherRates = function()
|
|||||||
{
|
{
|
||||||
let type = r.split(".");
|
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]);
|
error("Resource subtype not found: " + type[0] + "." + type[1]);
|
||||||
continue;
|
continue;
|
||||||
@ -164,35 +164,6 @@ ResourceGatherer.prototype.GetRange = function()
|
|||||||
// maybe this should depend on the unit or target or something?
|
// maybe this should depend on the unit or target or something?
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* 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,
|
* Gather from the target entity. This should only be called after a successful range check,
|
||||||
* and if the target has a compatible ResourceSupply.
|
* and if the target has a compatible ResourceSupply.
|
||||||
|
@ -45,7 +45,7 @@ ResourceSupply.prototype.Schema =
|
|||||||
"</element>" +
|
"</element>" +
|
||||||
"</optional>" +
|
"</optional>" +
|
||||||
"<element name='Type' a:help='Type and Subtype of resource available from this entity'>" +
|
"<element name='Type' a:help='Type and Subtype of resource available from this entity'>" +
|
||||||
Resources.BuildChoicesSchema(true, true) +
|
Resources.BuildChoicesSchema(true) +
|
||||||
"</element>" +
|
"</element>" +
|
||||||
"<element name='MaxGatherers' a:help='Amount of gatherers who can gather resources from this entity at the same time'>" +
|
"<element name='MaxGatherers' a:help='Amount of gatherers who can gather resources from this entity at the same time'>" +
|
||||||
"<data type='nonNegativeInteger'/>" +
|
"<data type='nonNegativeInteger'/>" +
|
||||||
|
111
binaries/data/mods/public/simulation/components/Treasure.js
Normal file
111
binaries/data/mods/public/simulation/components/Treasure.js
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
function Treasure() {}
|
||||||
|
|
||||||
|
Treasure.prototype.Schema =
|
||||||
|
"<a:help>Provides a bonus when taken. E.g. a supply of resources.</a:help>" +
|
||||||
|
"<a:example>" +
|
||||||
|
"<CollectTime>1000</CollectTime>" +
|
||||||
|
"<Resources>" +
|
||||||
|
"<Food>1000</Food>" +
|
||||||
|
"</Resources>" +
|
||||||
|
"</a:example>" +
|
||||||
|
"<element name='CollectTime' a:help='Amount of milliseconds that it takes to collect this treasure.'>" +
|
||||||
|
"<ref name='nonNegativeDecimal'/>" +
|
||||||
|
"</element>" +
|
||||||
|
"<optional>" +
|
||||||
|
"<element name='Resources' a:help='Amount of resources that are in this.'>" +
|
||||||
|
Resources.BuildSchema("positiveDecimal") +
|
||||||
|
"</element>" +
|
||||||
|
"</optional>";
|
||||||
|
|
||||||
|
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);
|
@ -0,0 +1,119 @@
|
|||||||
|
function TreasureCollecter() {}
|
||||||
|
|
||||||
|
TreasureCollecter.prototype.Schema =
|
||||||
|
"<a:help>Defines the treasure collecting abilities.</a:help>" +
|
||||||
|
"<a:example>" +
|
||||||
|
"<MaxDistance>2.0</MaxDistance>" +
|
||||||
|
"</a:example>" +
|
||||||
|
"<element name='MaxDistance' a:help='The maximum treasure taking distance in m.'>" +
|
||||||
|
"<ref name='positiveDecimal'/>" +
|
||||||
|
"</element>";
|
||||||
|
|
||||||
|
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);
|
@ -477,9 +477,8 @@ UnitAI.prototype.UnitFsmSpec = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// If the unit is full go to the nearest dropsite instead of trying to gather.
|
// 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);
|
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);
|
let nearestDropsite = this.FindNearestDropsite(msg.data.type.generic);
|
||||||
if (nearestDropsite)
|
if (nearestDropsite)
|
||||||
@ -645,6 +644,15 @@ UnitAI.prototype.UnitFsmSpec = {
|
|||||||
return this.FinishOrder();
|
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:
|
// States for the special entity representing a group of units moving in formation:
|
||||||
"FORMATIONCONTROLLER": {
|
"FORMATIONCONTROLLER": {
|
||||||
|
|
||||||
@ -2551,14 +2559,9 @@ UnitAI.prototype.UnitFsmSpec = {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Gather the resources:
|
|
||||||
|
|
||||||
let cmpResourceGatherer = Engine.QueryInterface(this.entity, IID_ResourceGatherer);
|
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,
|
// 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
|
// drop them first to ensure we're only ever carrying one type
|
||||||
if (cmpResourceGatherer.IsCarryingAnythingExcept(resourceType.generic))
|
if (cmpResourceGatherer.IsCarryingAnythingExcept(resourceType.generic))
|
||||||
@ -2566,11 +2569,8 @@ UnitAI.prototype.UnitFsmSpec = {
|
|||||||
|
|
||||||
this.FaceTowardsTarget(this.order.data.target);
|
this.FaceTowardsTarget(this.order.data.target);
|
||||||
|
|
||||||
// Collect from the target
|
|
||||||
let status = cmpResourceGatherer.PerformGather(this.gatheringTarget);
|
let status = cmpResourceGatherer.PerformGather(this.gatheringTarget);
|
||||||
|
|
||||||
// If we've collected as many resources as possible,
|
|
||||||
// return to the nearest dropsite
|
|
||||||
if (status.filled)
|
if (status.filled)
|
||||||
{
|
{
|
||||||
let nearestDropsite = this.FindNearestDropsite(resourceType.generic);
|
let nearestDropsite = this.FindNearestDropsite(resourceType.generic);
|
||||||
@ -2642,12 +2642,9 @@ UnitAI.prototype.UnitFsmSpec = {
|
|||||||
if (previousTarget == ent)
|
if (previousTarget == ent)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (type.generic == "treasure" && resourceType.generic == "treasure")
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return type.specific == resourceType.specific &&
|
return type.specific == resourceType.specific &&
|
||||||
(type.specific != "meat" || resourceTemplate == template);
|
(type.specific != "meat" || resourceTemplate == template);
|
||||||
});
|
});
|
||||||
|
|
||||||
if (nearbyResource)
|
if (nearbyResource)
|
||||||
{
|
{
|
||||||
@ -2874,6 +2871,76 @@ UnitAI.prototype.UnitFsmSpec = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
"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": {
|
"TRADE": {
|
||||||
"Attacked": function(msg) {
|
"Attacked": function(msg) {
|
||||||
// Ignore attack
|
// Ignore attack
|
||||||
@ -4240,6 +4307,16 @@ UnitAI.prototype.OnPackFinished = function(msg)
|
|||||||
this.UnitFsm.ProcessMessage(this, {"type": "PackFinished", "packed": msg.packed});
|
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 ////
|
//// Helper functions to be called by the FSM ////
|
||||||
|
|
||||||
UnitAI.prototype.GetWalkSpeed = function()
|
UnitAI.prototype.GetWalkSpeed = function()
|
||||||
@ -5607,6 +5684,14 @@ UnitAI.prototype.ReturnResource = function(target, queued)
|
|||||||
this.AddOrder("ReturnResource", { "target": target, "force": true }, queued);
|
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)
|
UnitAI.prototype.CancelSetupTradeRoute = function(target)
|
||||||
{
|
{
|
||||||
let cmpTrader = Engine.QueryInterface(this.entity, IID_Trader);
|
let cmpTrader = Engine.QueryInterface(this.entity, IID_Trader);
|
||||||
|
@ -0,0 +1 @@
|
|||||||
|
Engine.RegisterInterface("Treasure");
|
@ -0,0 +1 @@
|
|||||||
|
Engine.RegisterInterface("TreasureCollecter");
|
@ -32,6 +32,8 @@ Engine.LoadComponentScript("interfaces/TechnologyManager.js");
|
|||||||
Engine.LoadComponentScript("interfaces/Trader.js");
|
Engine.LoadComponentScript("interfaces/Trader.js");
|
||||||
Engine.LoadComponentScript("interfaces/TurretHolder.js");
|
Engine.LoadComponentScript("interfaces/TurretHolder.js");
|
||||||
Engine.LoadComponentScript("interfaces/Timer.js");
|
Engine.LoadComponentScript("interfaces/Timer.js");
|
||||||
|
Engine.LoadComponentScript("interfaces/Treasure.js");
|
||||||
|
Engine.LoadComponentScript("interfaces/TreasureCollecter.js");
|
||||||
Engine.LoadComponentScript("interfaces/StatisticsTracker.js");
|
Engine.LoadComponentScript("interfaces/StatisticsTracker.js");
|
||||||
Engine.LoadComponentScript("interfaces/StatusEffectsReceiver.js");
|
Engine.LoadComponentScript("interfaces/StatusEffectsReceiver.js");
|
||||||
Engine.LoadComponentScript("interfaces/UnitAI.js");
|
Engine.LoadComponentScript("interfaces/UnitAI.js");
|
||||||
|
@ -0,0 +1,56 @@
|
|||||||
|
Resources = {
|
||||||
|
"BuildSchema": () => {
|
||||||
|
let schema = "";
|
||||||
|
for (let res of ["food", "metal"])
|
||||||
|
{
|
||||||
|
for (let subtype in ["meat", "grain"])
|
||||||
|
schema += "<value>" + res + "." + subtype + "</value>";
|
||||||
|
schema += "<value> treasure." + res + "</value>";
|
||||||
|
}
|
||||||
|
return "<choice>" + schema + "</choice>";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
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);
|
@ -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);
|
@ -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 += "<value>" + res + "." + subtype + "</value>";
|
||||||
|
schema += "<value> treasure." + res + "</value>";
|
||||||
|
}
|
||||||
|
return "<choice>" + schema + "</choice>";
|
||||||
|
},
|
||||||
|
"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);
|
@ -16,15 +16,7 @@
|
|||||||
{ "value": "Loot/metal", "replace": 6, "affects": "Infantry" },
|
{ "value": "Loot/metal", "replace": 6, "affects": "Infantry" },
|
||||||
{ "value": "Loot/metal", "replace": 8, "affects": "Cavalry" },
|
{ "value": "Loot/metal", "replace": 8, "affects": "Cavalry" },
|
||||||
{ "value": "Loot/metal", "replace": 12, "affects": "Elephant" },
|
{ "value": "Loot/metal", "replace": 12, "affects": "Elephant" },
|
||||||
{ "value": "ResourceGatherer/Rates/food.fish", "replace": 0 },
|
{ "value": "ResourceGatherer/BaseSpeed", "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 }
|
|
||||||
],
|
],
|
||||||
"affects": ["Mercenary !Champion"]
|
"affects": ["Mercenary !Champion"]
|
||||||
}
|
}
|
||||||
|
@ -72,6 +72,13 @@ var g_Commands = {
|
|||||||
Cheat(cmd);
|
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)
|
"diplomacy": function(player, cmd, data)
|
||||||
{
|
{
|
||||||
let cmpCeasefireManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_CeasefireManager);
|
let cmpCeasefireManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_CeasefireManager);
|
||||||
|
@ -97,6 +97,14 @@ function GetRallyPointCommands(cmpRallyPoint, spawnedEnts)
|
|||||||
"queued": true
|
"queued": true
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
|
case "collect-treasure":
|
||||||
|
ret.push({
|
||||||
|
"type": "collect-treasure",
|
||||||
|
"entities": spawnedEnts,
|
||||||
|
"target": data[i].target,
|
||||||
|
"queued": true,
|
||||||
|
});
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
ret.push({
|
ret.push({
|
||||||
"type": "walk",
|
"type": "walk",
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
* To prevent validation errors, disabled resources are included in the schema.
|
* To prevent validation errors, disabled resources are included in the schema.
|
||||||
*
|
*
|
||||||
* @param datatype - The datatype of the element
|
* @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.
|
* @param subtypes - If true, resource subtypes will be included as well.
|
||||||
* @return RelaxNG schema string
|
* @return RelaxNG schema string
|
||||||
*/
|
*/
|
||||||
@ -47,15 +47,6 @@ Resources.prototype.BuildSchema = function(datatype, additional = [], subtypes =
|
|||||||
"</element>" +
|
"</element>" +
|
||||||
"</optional>";
|
"</optional>";
|
||||||
|
|
||||||
if (additional.indexOf("treasure") !== -1)
|
|
||||||
for (let res of resCodes)
|
|
||||||
schema +=
|
|
||||||
"<optional>" +
|
|
||||||
"<element name='" + "treasure." + res + "'>" +
|
|
||||||
datatype +
|
|
||||||
"</element>" +
|
|
||||||
"</optional>";
|
|
||||||
|
|
||||||
return "<interleave>" + schema + "</interleave>";
|
return "<interleave>" + schema + "</interleave>";
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -63,29 +54,19 @@ Resources.prototype.BuildSchema = function(datatype, additional = [], subtypes =
|
|||||||
* Builds the value choices for a RelaxNG `<choice></choice>` object, based on currently valid resources.
|
* Builds the value choices for a RelaxNG `<choice></choice>` object, based on currently valid resources.
|
||||||
*
|
*
|
||||||
* @oaram subtypes - If set to true, the choices returned will be resource subtypes, rather than main types
|
* @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 `<choice/>` values.
|
* @return String of RelaxNG Schema `<choice/>` values.
|
||||||
*/
|
*/
|
||||||
Resources.prototype.BuildChoicesSchema = function(subtypes = false, treasure = false)
|
Resources.prototype.BuildChoicesSchema = function(subtypes = false)
|
||||||
{
|
{
|
||||||
let schema = "";
|
let schema = "";
|
||||||
|
|
||||||
if (!subtypes)
|
if (!subtypes)
|
||||||
{
|
for (let res of this.resourceData.map(resource => resource.code))
|
||||||
let resCodes = this.resourceData.map(resource => resource.code);
|
|
||||||
if (treasure)
|
|
||||||
resCodes.push("treasure");
|
|
||||||
for (let res of resCodes)
|
|
||||||
schema += "<value>" + res + "</value>";
|
schema += "<value>" + res + "</value>";
|
||||||
}
|
|
||||||
else
|
else
|
||||||
for (let res of this.resourceData)
|
for (let res of this.resourceData)
|
||||||
{
|
|
||||||
for (let subtype in res.subtypes)
|
for (let subtype in res.subtypes)
|
||||||
schema += "<value>" + res.code + "." + subtype + "</value>";
|
schema += "<value>" + res.code + "." + subtype + "</value>";
|
||||||
if (treasure)
|
|
||||||
schema += "<value>" + "treasure." + res.code + "</value>";
|
|
||||||
}
|
|
||||||
|
|
||||||
return "<choice>" + schema + "</choice>";
|
return "<choice>" + schema + "</choice>";
|
||||||
};
|
};
|
||||||
|
@ -23,12 +23,8 @@ function LoadMapSettings(settings)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (settings.DisableTreasures)
|
if (settings.DisableTreasures)
|
||||||
for (let ent of Engine.GetEntitiesWithInterface(IID_ResourceSupply))
|
for (let ent of Engine.GetEntitiesWithInterface(IID_Treasure))
|
||||||
{
|
Engine.DestroyEntity(ent);
|
||||||
let cmpResourceSupply = Engine.QueryInterface(ent, IID_ResourceSupply);
|
|
||||||
if (cmpResourceSupply.GetType().generic == "treasure")
|
|
||||||
Engine.DestroyEntity(ent);
|
|
||||||
}
|
|
||||||
|
|
||||||
let cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
|
let cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
|
||||||
if (cmpRangeManager)
|
if (cmpRangeManager)
|
||||||
|
@ -8,10 +8,6 @@
|
|||||||
<SpecificName>Food Treasure</SpecificName>
|
<SpecificName>Food Treasure</SpecificName>
|
||||||
<Icon>gaia/special_treasure_food.png</Icon>
|
<Icon>gaia/special_treasure_food.png</Icon>
|
||||||
</Identity>
|
</Identity>
|
||||||
<ResourceSupply>
|
|
||||||
<Max>100</Max>
|
|
||||||
<Type>treasure.food</Type>
|
|
||||||
</ResourceSupply>
|
|
||||||
<Selectable replace="">
|
<Selectable replace="">
|
||||||
<Overlay>
|
<Overlay>
|
||||||
<Texture>
|
<Texture>
|
||||||
@ -20,6 +16,11 @@
|
|||||||
</Texture>
|
</Texture>
|
||||||
</Overlay>
|
</Overlay>
|
||||||
</Selectable>
|
</Selectable>
|
||||||
|
<Treasure>
|
||||||
|
<Resources>
|
||||||
|
<food>100</food>
|
||||||
|
</Resources>
|
||||||
|
</Treasure>
|
||||||
<VisualActor>
|
<VisualActor>
|
||||||
<Actor>props/special/eyecandy/barrel_a.xml</Actor>
|
<Actor>props/special/eyecandy/barrel_a.xml</Actor>
|
||||||
</VisualActor>
|
</VisualActor>
|
||||||
|
@ -15,10 +15,11 @@
|
|||||||
<Floating>false</Floating>
|
<Floating>false</Floating>
|
||||||
<FloatDepth>0.0</FloatDepth>
|
<FloatDepth>0.0</FloatDepth>
|
||||||
</Position>
|
</Position>
|
||||||
<ResourceSupply>
|
<Treasure>
|
||||||
<Max>200</Max>
|
<Resources>
|
||||||
<Type>treasure.food</Type>
|
<food>200</food>
|
||||||
</ResourceSupply>
|
</Resources>
|
||||||
|
</Treasure>
|
||||||
<VisualActor>
|
<VisualActor>
|
||||||
<Actor>props/special/eyecandy/barrels_buried.xml</Actor>
|
<Actor>props/special/eyecandy/barrels_buried.xml</Actor>
|
||||||
</VisualActor>
|
</VisualActor>
|
||||||
|
@ -11,10 +11,11 @@
|
|||||||
<Obstruction>
|
<Obstruction>
|
||||||
<Static width="2.0" depth="3.0"/>
|
<Static width="2.0" depth="3.0"/>
|
||||||
</Obstruction>
|
</Obstruction>
|
||||||
<ResourceSupply>
|
<Treasure>
|
||||||
<Max>300</Max>
|
<Resources>
|
||||||
<Type>treasure.food</Type>
|
<food>300</food>
|
||||||
</ResourceSupply>
|
</Resources>
|
||||||
|
</Treasure>
|
||||||
<VisualActor>
|
<VisualActor>
|
||||||
<Actor>props/special/eyecandy/produce_bin_a.xml</Actor>
|
<Actor>props/special/eyecandy/produce_bin_a.xml</Actor>
|
||||||
</VisualActor>
|
</VisualActor>
|
||||||
|
@ -11,10 +11,11 @@
|
|||||||
<Obstruction>
|
<Obstruction>
|
||||||
<Static width="1.75" depth="1.75"/>
|
<Static width="1.75" depth="1.75"/>
|
||||||
</Obstruction>
|
</Obstruction>
|
||||||
<ResourceSupply>
|
<Treasure>
|
||||||
<Max>200</Max>
|
<Resources>
|
||||||
<Type>treasure.food</Type>
|
<food>200</food>
|
||||||
</ResourceSupply>
|
</Resources>
|
||||||
|
</Treasure>
|
||||||
<VisualActor>
|
<VisualActor>
|
||||||
<Actor>props/special/eyecandy/crate_a.xml</Actor>
|
<Actor>props/special/eyecandy/crate_a.xml</Actor>
|
||||||
</VisualActor>
|
</VisualActor>
|
||||||
|
@ -11,10 +11,11 @@
|
|||||||
<Obstruction>
|
<Obstruction>
|
||||||
<Static width="6.5" depth="6.5"/>
|
<Static width="6.5" depth="6.5"/>
|
||||||
</Obstruction>
|
</Obstruction>
|
||||||
<ResourceSupply>
|
<Treasure>
|
||||||
<Max>300</Max>
|
<Resources>
|
||||||
<Type>treasure.food</Type>
|
<food>300</food>
|
||||||
</ResourceSupply>
|
</Resources>
|
||||||
|
</Treasure>
|
||||||
<VisualActor>
|
<VisualActor>
|
||||||
<Actor>props/special/eyecandy/amphorae.xml</Actor>
|
<Actor>props/special/eyecandy/amphorae.xml</Actor>
|
||||||
</VisualActor>
|
</VisualActor>
|
||||||
|
@ -11,10 +11,11 @@
|
|||||||
<Obstruction>
|
<Obstruction>
|
||||||
<Static width="8.0" depth="8.0"/>
|
<Static width="8.0" depth="8.0"/>
|
||||||
</Obstruction>
|
</Obstruction>
|
||||||
<ResourceSupply>
|
<Treasure>
|
||||||
<Max>600</Max>
|
<Resources>
|
||||||
<Type>treasure.food</Type>
|
<food>600</food>
|
||||||
</ResourceSupply>
|
</Resources>
|
||||||
|
</Treasure>
|
||||||
<VisualActor>
|
<VisualActor>
|
||||||
<Actor>props/special/eyecandy/treasure_persian_food_big.xml</Actor>
|
<Actor>props/special/eyecandy/treasure_persian_food_big.xml</Actor>
|
||||||
</VisualActor>
|
</VisualActor>
|
||||||
|
@ -11,10 +11,11 @@
|
|||||||
<Obstruction>
|
<Obstruction>
|
||||||
<Static width="5.0" depth="5.0"/>
|
<Static width="5.0" depth="5.0"/>
|
||||||
</Obstruction>
|
</Obstruction>
|
||||||
<ResourceSupply>
|
<Treasure>
|
||||||
<Max>400</Max>
|
<Resources>
|
||||||
<Type>treasure.food</Type>
|
<food>400</food>
|
||||||
</ResourceSupply>
|
</Resources>
|
||||||
|
</Treasure>
|
||||||
<VisualActor>
|
<VisualActor>
|
||||||
<Actor>props/special/eyecandy/treasure_persian_food_small.xml</Actor>
|
<Actor>props/special/eyecandy/treasure_persian_food_small.xml</Actor>
|
||||||
</VisualActor>
|
</VisualActor>
|
||||||
|
@ -7,10 +7,11 @@
|
|||||||
<Identity>
|
<Identity>
|
||||||
<SpecificName>Golden Fleece</SpecificName>
|
<SpecificName>Golden Fleece</SpecificName>
|
||||||
</Identity>
|
</Identity>
|
||||||
<ResourceSupply>
|
<Treasure>
|
||||||
<Max>1000</Max>
|
<Resources>
|
||||||
<Type>treasure.metal</Type>
|
<metal>1000</metal>
|
||||||
</ResourceSupply>
|
</Resources>
|
||||||
|
</Treasure>
|
||||||
<VisualActor>
|
<VisualActor>
|
||||||
<Actor>special/golden_fleece.xml</Actor>
|
<Actor>special/golden_fleece.xml</Actor>
|
||||||
</VisualActor>
|
</VisualActor>
|
||||||
|
@ -7,15 +7,16 @@
|
|||||||
<Identity>
|
<Identity>
|
||||||
<SpecificName>Secret Box</SpecificName>
|
<SpecificName>Secret Box</SpecificName>
|
||||||
</Identity>
|
</Identity>
|
||||||
<ResourceSupply>
|
|
||||||
<Max>300</Max>
|
|
||||||
<Type>treasure.metal</Type>
|
|
||||||
</ResourceSupply>
|
|
||||||
<Sound>
|
<Sound>
|
||||||
<SoundGroups>
|
<SoundGroups>
|
||||||
<select>interface/select/resource/sel_metal.xml</select>
|
<select>interface/select/resource/sel_metal.xml</select>
|
||||||
</SoundGroups>
|
</SoundGroups>
|
||||||
</Sound>
|
</Sound>
|
||||||
|
<Treasure>
|
||||||
|
<Resources>
|
||||||
|
<metal>300</metal>
|
||||||
|
</Resources>
|
||||||
|
</Treasure>
|
||||||
<VisualActor>
|
<VisualActor>
|
||||||
<Actor>props/special/eyecandy/barrel_a.xml</Actor>
|
<Actor>props/special/eyecandy/barrel_a.xml</Actor>
|
||||||
</VisualActor>
|
</VisualActor>
|
||||||
|
@ -10,15 +10,16 @@
|
|||||||
<Obstruction>
|
<Obstruction>
|
||||||
<Static width="7.0" depth="7.0"/>
|
<Static width="7.0" depth="7.0"/>
|
||||||
</Obstruction>
|
</Obstruction>
|
||||||
<ResourceSupply>
|
|
||||||
<Max>500</Max>
|
|
||||||
<Type>treasure.metal</Type>
|
|
||||||
</ResourceSupply>
|
|
||||||
<Sound>
|
<Sound>
|
||||||
<SoundGroups>
|
<SoundGroups>
|
||||||
<select>interface/select/resource/sel_metal.xml</select>
|
<select>interface/select/resource/sel_metal.xml</select>
|
||||||
</SoundGroups>
|
</SoundGroups>
|
||||||
</Sound>
|
</Sound>
|
||||||
|
<Treasure>
|
||||||
|
<Resources>
|
||||||
|
<metal>500</metal>
|
||||||
|
</Resources>
|
||||||
|
</Treasure>
|
||||||
<VisualActor>
|
<VisualActor>
|
||||||
<Actor>props/special/eyecandy/treasure_persian_metal_big.xml</Actor>
|
<Actor>props/special/eyecandy/treasure_persian_metal_big.xml</Actor>
|
||||||
</VisualActor>
|
</VisualActor>
|
||||||
|
@ -10,15 +10,16 @@
|
|||||||
<Obstruction>
|
<Obstruction>
|
||||||
<Static width="5.0" depth="3.0"/>
|
<Static width="5.0" depth="3.0"/>
|
||||||
</Obstruction>
|
</Obstruction>
|
||||||
<ResourceSupply>
|
|
||||||
<Max>300</Max>
|
|
||||||
<Type>treasure.metal</Type>
|
|
||||||
</ResourceSupply>
|
|
||||||
<Sound>
|
<Sound>
|
||||||
<SoundGroups>
|
<SoundGroups>
|
||||||
<select>interface/select/resource/sel_metal.xml</select>
|
<select>interface/select/resource/sel_metal.xml</select>
|
||||||
</SoundGroups>
|
</SoundGroups>
|
||||||
</Sound>
|
</Sound>
|
||||||
|
<Treasure>
|
||||||
|
<Resources>
|
||||||
|
<metal>300</metal>
|
||||||
|
</Resources>
|
||||||
|
</Treasure>
|
||||||
<VisualActor>
|
<VisualActor>
|
||||||
<Actor>props/special/eyecandy/treasure_persian_metal_small.xml</Actor>
|
<Actor>props/special/eyecandy/treasure_persian_metal_small.xml</Actor>
|
||||||
</VisualActor>
|
</VisualActor>
|
||||||
|
@ -7,10 +7,11 @@
|
|||||||
<Identity>
|
<Identity>
|
||||||
<SpecificName>Pegasus</SpecificName>
|
<SpecificName>Pegasus</SpecificName>
|
||||||
</Identity>
|
</Identity>
|
||||||
<ResourceSupply>
|
<Treasure>
|
||||||
<Max>1000</Max>
|
<Resources>
|
||||||
<Type>treasure.metal</Type>
|
<metal>1000</metal>
|
||||||
</ResourceSupply>
|
</Resources>
|
||||||
|
</Treasure>
|
||||||
<VisualActor>
|
<VisualActor>
|
||||||
<Actor>special/pegasus.xml</Actor>
|
<Actor>special/pegasus.xml</Actor>
|
||||||
</VisualActor>
|
</VisualActor>
|
||||||
|
@ -14,10 +14,11 @@
|
|||||||
<Floating>true</Floating>
|
<Floating>true</Floating>
|
||||||
<FloatDepth>0.0</FloatDepth>
|
<FloatDepth>0.0</FloatDepth>
|
||||||
</Position>
|
</Position>
|
||||||
<ResourceSupply>
|
<Treasure>
|
||||||
<Max>500</Max>
|
<Resources>
|
||||||
<Type>treasure.wood</Type>
|
<wood>500</wood>
|
||||||
</ResourceSupply>
|
</Resources>
|
||||||
|
</Treasure>
|
||||||
<VisualActor>
|
<VisualActor>
|
||||||
<Actor>props/special/eyecandy/shipwreck_ram_side.xml</Actor>
|
<Actor>props/special/eyecandy/shipwreck_ram_side.xml</Actor>
|
||||||
</VisualActor>
|
</VisualActor>
|
||||||
|
@ -17,10 +17,11 @@
|
|||||||
<Floating>true</Floating>
|
<Floating>true</Floating>
|
||||||
<FloatDepth>0.0</FloatDepth>
|
<FloatDepth>0.0</FloatDepth>
|
||||||
</Position>
|
</Position>
|
||||||
<ResourceSupply>
|
<Treasure>
|
||||||
<Max>200</Max>
|
<Resources>
|
||||||
<Type>treasure.food</Type>
|
<food>200</food>
|
||||||
</ResourceSupply>
|
</Resources>
|
||||||
|
</Treasure>
|
||||||
<VisualActor>
|
<VisualActor>
|
||||||
<Actor>props/special/eyecandy/barrels_floating.xml</Actor>
|
<Actor>props/special/eyecandy/barrels_floating.xml</Actor>
|
||||||
</VisualActor>
|
</VisualActor>
|
||||||
|
@ -14,10 +14,11 @@
|
|||||||
<Floating>true</Floating>
|
<Floating>true</Floating>
|
||||||
<FloatDepth>0.0</FloatDepth>
|
<FloatDepth>0.0</FloatDepth>
|
||||||
</Position>
|
</Position>
|
||||||
<ResourceSupply>
|
<Treasure>
|
||||||
<Max>550</Max>
|
<Resources>
|
||||||
<Type>treasure.wood</Type>
|
<wood>550</wood>
|
||||||
</ResourceSupply>
|
</Resources>
|
||||||
|
</Treasure>
|
||||||
<VisualActor>
|
<VisualActor>
|
||||||
<Actor>props/special/eyecandy/shipwreck_ram_bow.xml</Actor>
|
<Actor>props/special/eyecandy/shipwreck_ram_bow.xml</Actor>
|
||||||
</VisualActor>
|
</VisualActor>
|
||||||
|
@ -14,10 +14,11 @@
|
|||||||
<Floating>true</Floating>
|
<Floating>true</Floating>
|
||||||
<FloatDepth>0.0</FloatDepth>
|
<FloatDepth>0.0</FloatDepth>
|
||||||
</Position>
|
</Position>
|
||||||
<ResourceSupply>
|
<Treasure>
|
||||||
<Max>400</Max>
|
<Resources>
|
||||||
<Type>treasure.wood</Type>
|
<wood>400</wood>
|
||||||
</ResourceSupply>
|
</Resources>
|
||||||
|
</Treasure>
|
||||||
<VisualActor>
|
<VisualActor>
|
||||||
<Actor>props/special/eyecandy/shipwreck_sail_boat.xml</Actor>
|
<Actor>props/special/eyecandy/shipwreck_sail_boat.xml</Actor>
|
||||||
</VisualActor>
|
</VisualActor>
|
||||||
|
@ -14,10 +14,11 @@
|
|||||||
<Floating>true</Floating>
|
<Floating>true</Floating>
|
||||||
<FloatDepth>0.0</FloatDepth>
|
<FloatDepth>0.0</FloatDepth>
|
||||||
</Position>
|
</Position>
|
||||||
<ResourceSupply>
|
<Treasure>
|
||||||
<Max>450</Max>
|
<Resources>
|
||||||
<Type>treasure.wood</Type>
|
<wood>450</wood>
|
||||||
</ResourceSupply>
|
</Resources>
|
||||||
|
</Treasure>
|
||||||
<VisualActor>
|
<VisualActor>
|
||||||
<Actor>props/special/eyecandy/shipwreck_sail_boat_cut.xml</Actor>
|
<Actor>props/special/eyecandy/shipwreck_sail_boat_cut.xml</Actor>
|
||||||
</VisualActor>
|
</VisualActor>
|
||||||
|
@ -10,15 +10,16 @@
|
|||||||
<Obstruction>
|
<Obstruction>
|
||||||
<Static width="2.0" depth="2.0"/>
|
<Static width="2.0" depth="2.0"/>
|
||||||
</Obstruction>
|
</Obstruction>
|
||||||
<ResourceSupply>
|
|
||||||
<Max>300</Max>
|
|
||||||
<Type>treasure.stone</Type>
|
|
||||||
</ResourceSupply>
|
|
||||||
<Sound>
|
<Sound>
|
||||||
<SoundGroups>
|
<SoundGroups>
|
||||||
<select>interface/select/resource/sel_stone.xml</select>
|
<select>interface/select/resource/sel_stone.xml</select>
|
||||||
</SoundGroups>
|
</SoundGroups>
|
||||||
</Sound>
|
</Sound>
|
||||||
|
<Treasure>
|
||||||
|
<Resources>
|
||||||
|
<stone>300</stone>
|
||||||
|
</Resources>
|
||||||
|
</Treasure>
|
||||||
<VisualActor>
|
<VisualActor>
|
||||||
<Actor>props/special/eyecandy/standing_stones.xml</Actor>
|
<Actor>props/special/eyecandy/standing_stones.xml</Actor>
|
||||||
</VisualActor>
|
</VisualActor>
|
||||||
|
@ -10,15 +10,16 @@
|
|||||||
<Obstruction>
|
<Obstruction>
|
||||||
<Static width="6.5" depth="6.5"/>
|
<Static width="6.5" depth="6.5"/>
|
||||||
</Obstruction>
|
</Obstruction>
|
||||||
<ResourceSupply>
|
|
||||||
<Max>300</Max>
|
|
||||||
<Type>treasure.stone</Type>
|
|
||||||
</ResourceSupply>
|
|
||||||
<Sound>
|
<Sound>
|
||||||
<SoundGroups>
|
<SoundGroups>
|
||||||
<select>interface/select/resource/sel_stone.xml</select>
|
<select>interface/select/resource/sel_stone.xml</select>
|
||||||
</SoundGroups>
|
</SoundGroups>
|
||||||
</Sound>
|
</Sound>
|
||||||
|
<Treasure>
|
||||||
|
<Resources>
|
||||||
|
<stone>300</stone>
|
||||||
|
</Resources>
|
||||||
|
</Treasure>
|
||||||
<VisualActor>
|
<VisualActor>
|
||||||
<Actor>props/special/eyecandy/stone_pile.xml</Actor>
|
<Actor>props/special/eyecandy/stone_pile.xml</Actor>
|
||||||
</VisualActor>
|
</VisualActor>
|
||||||
|
@ -10,15 +10,16 @@
|
|||||||
<Obstruction>
|
<Obstruction>
|
||||||
<Static width="3.5" depth="6.5"/>
|
<Static width="3.5" depth="6.5"/>
|
||||||
</Obstruction>
|
</Obstruction>
|
||||||
<ResourceSupply>
|
|
||||||
<Max>300</Max>
|
|
||||||
<Type>treasure.wood</Type>
|
|
||||||
</ResourceSupply>
|
|
||||||
<Sound>
|
<Sound>
|
||||||
<SoundGroups>
|
<SoundGroups>
|
||||||
<select>interface/select/resource/sel_tree.xml</select>
|
<select>interface/select/resource/sel_tree.xml</select>
|
||||||
</SoundGroups>
|
</SoundGroups>
|
||||||
</Sound>
|
</Sound>
|
||||||
|
<Treasure>
|
||||||
|
<Resources>
|
||||||
|
<wood>300</wood>
|
||||||
|
</Resources>
|
||||||
|
</Treasure>
|
||||||
<VisualActor>
|
<VisualActor>
|
||||||
<Actor>props/special/eyecandy/wood_pile.xml</Actor>
|
<Actor>props/special/eyecandy/wood_pile.xml</Actor>
|
||||||
</VisualActor>
|
</VisualActor>
|
||||||
|
@ -16,11 +16,6 @@
|
|||||||
<Obstruction>
|
<Obstruction>
|
||||||
<Static width="1.5" depth="1.5"/>
|
<Static width="1.5" depth="1.5"/>
|
||||||
</Obstruction>
|
</Obstruction>
|
||||||
<ResourceSupply>
|
|
||||||
<KillBeforeGather>false</KillBeforeGather>
|
|
||||||
<Max>300</Max>
|
|
||||||
<MaxGatherers>1</MaxGatherers>
|
|
||||||
</ResourceSupply>
|
|
||||||
<Selectable>
|
<Selectable>
|
||||||
<Overlay>
|
<Overlay>
|
||||||
<Outline>
|
<Outline>
|
||||||
@ -36,4 +31,7 @@
|
|||||||
<StatusBars>
|
<StatusBars>
|
||||||
<HeightOffset>3.75</HeightOffset>
|
<HeightOffset>3.75</HeightOffset>
|
||||||
</StatusBars>
|
</StatusBars>
|
||||||
|
<Treasure>
|
||||||
|
<CollectTime>1000</CollectTime>
|
||||||
|
</Treasure>
|
||||||
</Entity>
|
</Entity>
|
||||||
|
@ -85,19 +85,6 @@
|
|||||||
</Damage>
|
</Damage>
|
||||||
</Entity>
|
</Entity>
|
||||||
</Resistance>
|
</Resistance>
|
||||||
<ResourceGatherer>
|
|
||||||
<MaxDistance>2.0</MaxDistance>
|
|
||||||
<BaseSpeed>1.0</BaseSpeed>
|
|
||||||
<Rates>
|
|
||||||
<treasure>1</treasure>
|
|
||||||
</Rates>
|
|
||||||
<Capacities>
|
|
||||||
<food>10</food>
|
|
||||||
<wood>10</wood>
|
|
||||||
<stone>10</stone>
|
|
||||||
<metal>10</metal>
|
|
||||||
</Capacities>
|
|
||||||
</ResourceGatherer>
|
|
||||||
<Selectable>
|
<Selectable>
|
||||||
<Overlay>
|
<Overlay>
|
||||||
<Texture>
|
<Texture>
|
||||||
@ -120,6 +107,9 @@
|
|||||||
<HeightOffset>5.0</HeightOffset>
|
<HeightOffset>5.0</HeightOffset>
|
||||||
</StatusBars>
|
</StatusBars>
|
||||||
<StatusEffectsReceiver/>
|
<StatusEffectsReceiver/>
|
||||||
|
<TreasureCollecter>
|
||||||
|
<MaxDistance>2</MaxDistance>
|
||||||
|
</TreasureCollecter>
|
||||||
<UnitAI>
|
<UnitAI>
|
||||||
<DefaultStance>aggressive</DefaultStance>
|
<DefaultStance>aggressive</DefaultStance>
|
||||||
<FleeDistance>12.0</FleeDistance>
|
<FleeDistance>12.0</FleeDistance>
|
||||||
|
@ -28,7 +28,6 @@
|
|||||||
<Anchor>pitch-roll</Anchor>
|
<Anchor>pitch-roll</Anchor>
|
||||||
</Position>
|
</Position>
|
||||||
<Resistance replace=""/>
|
<Resistance replace=""/>
|
||||||
<ResourceGatherer disable=""/>
|
|
||||||
<Selectable>
|
<Selectable>
|
||||||
<Overlay>
|
<Overlay>
|
||||||
<Texture>
|
<Texture>
|
||||||
@ -45,6 +44,7 @@
|
|||||||
<walk>actor/singlesteps/steps_grass.xml</walk>
|
<walk>actor/singlesteps/steps_grass.xml</walk>
|
||||||
</SoundGroups>
|
</SoundGroups>
|
||||||
</Sound>
|
</Sound>
|
||||||
|
<TreasureCollecter disable=""/>
|
||||||
<UnitAI>
|
<UnitAI>
|
||||||
<DefaultStance>standground</DefaultStance>
|
<DefaultStance>standground</DefaultStance>
|
||||||
<CanGuard>false</CanGuard>
|
<CanGuard>false</CanGuard>
|
||||||
|
@ -65,9 +65,6 @@
|
|||||||
</Rates>
|
</Rates>
|
||||||
<Capacities>
|
<Capacities>
|
||||||
<food>20</food>
|
<food>20</food>
|
||||||
<wood>20</wood>
|
|
||||||
<stone>20</stone>
|
|
||||||
<metal>20</metal>
|
|
||||||
</Capacities>
|
</Capacities>
|
||||||
</ResourceGatherer>
|
</ResourceGatherer>
|
||||||
<Selectable>
|
<Selectable>
|
||||||
|
@ -38,7 +38,6 @@
|
|||||||
<xp>100</xp>
|
<xp>100</xp>
|
||||||
<food>10</food>
|
<food>10</food>
|
||||||
</Loot>
|
</Loot>
|
||||||
<ResourceGatherer disable=""/>
|
|
||||||
<Selectable>
|
<Selectable>
|
||||||
<Overlay>
|
<Overlay>
|
||||||
<Texture>
|
<Texture>
|
||||||
@ -65,6 +64,7 @@
|
|||||||
<TrainingRestrictions>
|
<TrainingRestrictions>
|
||||||
<Category>WarDog</Category>
|
<Category>WarDog</Category>
|
||||||
</TrainingRestrictions>
|
</TrainingRestrictions>
|
||||||
|
<TreasureCollecter disable=""/>
|
||||||
<UnitMotion>
|
<UnitMotion>
|
||||||
<WalkSpeed op="mul">1.5</WalkSpeed>
|
<WalkSpeed op="mul">1.5</WalkSpeed>
|
||||||
<RunMultiplier>2</RunMultiplier>
|
<RunMultiplier>2</RunMultiplier>
|
||||||
|
@ -21,7 +21,6 @@
|
|||||||
<Position>
|
<Position>
|
||||||
<TurnRate>4</TurnRate>
|
<TurnRate>4</TurnRate>
|
||||||
</Position>
|
</Position>
|
||||||
<ResourceGatherer disable=""/>
|
|
||||||
<Selectable>
|
<Selectable>
|
||||||
<Overlay>
|
<Overlay>
|
||||||
<Texture>
|
<Texture>
|
||||||
@ -30,6 +29,7 @@
|
|||||||
</Texture>
|
</Texture>
|
||||||
</Overlay>
|
</Overlay>
|
||||||
</Selectable>
|
</Selectable>
|
||||||
|
<TreasureCollecter disable=""/>
|
||||||
<UnitAI>
|
<UnitAI>
|
||||||
<DefaultStance>passive</DefaultStance>
|
<DefaultStance>passive</DefaultStance>
|
||||||
<CanGuard>false</CanGuard>
|
<CanGuard>false</CanGuard>
|
||||||
|
@ -100,6 +100,12 @@
|
|||||||
<stone.ruins>2</stone.ruins>
|
<stone.ruins>2</stone.ruins>
|
||||||
<metal.ore>0.5</metal.ore>
|
<metal.ore>0.5</metal.ore>
|
||||||
</Rates>
|
</Rates>
|
||||||
|
<Capacities>
|
||||||
|
<food>10</food>
|
||||||
|
<wood>10</wood>
|
||||||
|
<stone>10</stone>
|
||||||
|
<metal>10</metal>
|
||||||
|
</Capacities>
|
||||||
</ResourceGatherer>
|
</ResourceGatherer>
|
||||||
<Sound>
|
<Sound>
|
||||||
<SoundGroups>
|
<SoundGroups>
|
||||||
|
@ -70,6 +70,7 @@
|
|||||||
<BarHeight>0.5</BarHeight>
|
<BarHeight>0.5</BarHeight>
|
||||||
<HeightOffset>6.0</HeightOffset>
|
<HeightOffset>6.0</HeightOffset>
|
||||||
</StatusBars>
|
</StatusBars>
|
||||||
|
<TreasureCollecter disable=""/>
|
||||||
<UnitMotion>
|
<UnitMotion>
|
||||||
<PassabilityClass>ship</PassabilityClass>
|
<PassabilityClass>ship</PassabilityClass>
|
||||||
</UnitMotion>
|
</UnitMotion>
|
||||||
|
@ -55,7 +55,6 @@
|
|||||||
<wood>25</wood>
|
<wood>25</wood>
|
||||||
<metal>15</metal>
|
<metal>15</metal>
|
||||||
</Loot>
|
</Loot>
|
||||||
<ResourceGatherer disable=""/>
|
|
||||||
<Sound>
|
<Sound>
|
||||||
<SoundGroups>
|
<SoundGroups>
|
||||||
<attack_impact_ranged>attack/impact/arrow_impact.xml</attack_impact_ranged>
|
<attack_impact_ranged>attack/impact/arrow_impact.xml</attack_impact_ranged>
|
||||||
|
@ -44,7 +44,6 @@
|
|||||||
</Identity>
|
</Identity>
|
||||||
<Loot disable=""/>
|
<Loot disable=""/>
|
||||||
<Repairable disable=""/>
|
<Repairable disable=""/>
|
||||||
<ResourceGatherer disable=""/>
|
|
||||||
<UnitMotion>
|
<UnitMotion>
|
||||||
<PassabilityClass>ship-small</PassabilityClass>
|
<PassabilityClass>ship-small</PassabilityClass>
|
||||||
<WalkSpeed op="mul">1.6</WalkSpeed>
|
<WalkSpeed op="mul">1.6</WalkSpeed>
|
||||||
|
@ -48,9 +48,9 @@
|
|||||||
</Resistance>
|
</Resistance>
|
||||||
<ResourceGatherer>
|
<ResourceGatherer>
|
||||||
<MaxDistance>6.0</MaxDistance>
|
<MaxDistance>6.0</MaxDistance>
|
||||||
|
<BaseSpeed>1.0</BaseSpeed>
|
||||||
<Rates>
|
<Rates>
|
||||||
<food.fish>1.8</food.fish>
|
<food.fish>1.8</food.fish>
|
||||||
<treasure disable=""/>
|
|
||||||
</Rates>
|
</Rates>
|
||||||
<Capacities>
|
<Capacities>
|
||||||
<food>40</food>
|
<food>40</food>
|
||||||
|
@ -34,13 +34,13 @@
|
|||||||
</Damage>
|
</Damage>
|
||||||
</Entity>
|
</Entity>
|
||||||
</Resistance>
|
</Resistance>
|
||||||
<ResourceGatherer>
|
|
||||||
<MaxDistance>12.0</MaxDistance>
|
|
||||||
</ResourceGatherer>
|
|
||||||
<Trader>
|
<Trader>
|
||||||
<GainMultiplier>0.75</GainMultiplier>
|
<GainMultiplier>0.75</GainMultiplier>
|
||||||
<GarrisonGainMultiplier>0.2</GarrisonGainMultiplier>
|
<GarrisonGainMultiplier>0.2</GarrisonGainMultiplier>
|
||||||
</Trader>
|
</Trader>
|
||||||
|
<TreasureCollecter>
|
||||||
|
<MaxDistance>12</MaxDistance>
|
||||||
|
</TreasureCollecter>
|
||||||
<UnitAI>
|
<UnitAI>
|
||||||
<DefaultStance>passive</DefaultStance>
|
<DefaultStance>passive</DefaultStance>
|
||||||
<CanGuard>false</CanGuard>
|
<CanGuard>false</CanGuard>
|
||||||
|
@ -59,7 +59,6 @@
|
|||||||
<Position>
|
<Position>
|
||||||
<TurnRate>2</TurnRate>
|
<TurnRate>2</TurnRate>
|
||||||
</Position>
|
</Position>
|
||||||
<ResourceGatherer disable=""/>
|
|
||||||
<Sound>
|
<Sound>
|
||||||
<SoundGroups>
|
<SoundGroups>
|
||||||
<attack_ranged>attack/siege/ballist_attack.xml</attack_ranged>
|
<attack_ranged>attack/siege/ballist_attack.xml</attack_ranged>
|
||||||
|
@ -58,7 +58,6 @@
|
|||||||
<Position>
|
<Position>
|
||||||
<TurnRate>2</TurnRate>
|
<TurnRate>2</TurnRate>
|
||||||
</Position>
|
</Position>
|
||||||
<ResourceGatherer disable=""/>
|
|
||||||
<Sound>
|
<Sound>
|
||||||
<SoundGroups>
|
<SoundGroups>
|
||||||
<attack_impact_ranged>attack/impact/arrow_impact.xml</attack_impact_ranged>
|
<attack_impact_ranged>attack/impact/arrow_impact.xml</attack_impact_ranged>
|
||||||
|
@ -85,6 +85,12 @@
|
|||||||
<stone.ruins>2</stone.ruins>
|
<stone.ruins>2</stone.ruins>
|
||||||
<metal.ore>0.35</metal.ore>
|
<metal.ore>0.35</metal.ore>
|
||||||
</Rates>
|
</Rates>
|
||||||
|
<Capacities>
|
||||||
|
<food>10</food>
|
||||||
|
<wood>10</wood>
|
||||||
|
<stone>10</stone>
|
||||||
|
<metal>10</metal>
|
||||||
|
</Capacities>
|
||||||
</ResourceGatherer>
|
</ResourceGatherer>
|
||||||
<Sound>
|
<Sound>
|
||||||
<SoundGroups>
|
<SoundGroups>
|
||||||
|
@ -53,6 +53,7 @@
|
|||||||
<metal>5</metal>
|
<metal>5</metal>
|
||||||
</Loot>
|
</Loot>
|
||||||
<ResourceGatherer>
|
<ResourceGatherer>
|
||||||
|
<MaxDistance>2.0</MaxDistance>
|
||||||
<BaseSpeed>1.0</BaseSpeed>
|
<BaseSpeed>1.0</BaseSpeed>
|
||||||
<Rates>
|
<Rates>
|
||||||
<food.fish>0.5</food.fish>
|
<food.fish>0.5</food.fish>
|
||||||
@ -64,9 +65,15 @@
|
|||||||
<stone.rock>1.0</stone.rock>
|
<stone.rock>1.0</stone.rock>
|
||||||
<stone.ruins>5</stone.ruins>
|
<stone.ruins>5</stone.ruins>
|
||||||
<metal.ore>1.0</metal.ore>
|
<metal.ore>1.0</metal.ore>
|
||||||
<treasure disable=""/>
|
|
||||||
</Rates>
|
</Rates>
|
||||||
|
<Capacities>
|
||||||
|
<food>10</food>
|
||||||
|
<wood>10</wood>
|
||||||
|
<stone>10</stone>
|
||||||
|
<metal>10</metal>
|
||||||
|
</Capacities>
|
||||||
</ResourceGatherer>
|
</ResourceGatherer>
|
||||||
|
<TreasureCollecter disable=""/>
|
||||||
<Sound>
|
<Sound>
|
||||||
<SoundGroups>
|
<SoundGroups>
|
||||||
<build>resource/construction/con_wood.xml</build>
|
<build>resource/construction/con_wood.xml</build>
|
||||||
|
Loading…
Reference in New Issue
Block a user