define the limit changing elements together with the limits, so they can be queried by the GUI and the AI. Fixes #2187

This was SVN commit r14408.
This commit is contained in:
sanderd17 2013-12-27 10:58:48 +00:00
parent 040e15ed51
commit 659736301a
12 changed files with 117 additions and 153 deletions

View File

@ -1666,14 +1666,16 @@ function getEntityLimitAndCount(playerState, entType)
entCategory = template.buildRestrictions.category;
var entLimit = undefined;
var entCount = undefined;
var entLimitChangers = undefined;
var canBeAddedCount = undefined;
if (entCategory && playerState.entityLimits[entCategory] != null)
{
entLimit = playerState.entityLimits[entCategory];
entCount = playerState.entityCounts[entCategory];
entLimitChangers = playerState.entityLimitChangers[entCategory];
canBeAddedCount = Math.max(entLimit - entCount, 0);
}
return [entLimit, entCount, canBeAddedCount];
return [entLimit, entCount, canBeAddedCount, entLimitChangers];
}
// Add the unit shown at position to the training queue for all entities in the selection

View File

@ -139,19 +139,26 @@ function setOverlay(object, value)
object.hidden = !value;
}
/**
* Format entity count/limit message for the tooltip
*/
function formatLimitString(trainEntLimit, trainEntCount)
{
if (trainEntLimit == undefined)
return "";
var text = "\n\nCurrent Count: " + trainEntCount + ", Limit: " + trainEntLimit + ".";
if (trainEntCount >= trainEntLimit)
text = "[color=\"red\"]" + text + "[/color]";
return text;
}
/**
* Format entity count/limit message for the tooltip
*/
function formatLimitString(trainEntLimit, trainEntCount, trainEntLimitChangers)
{
if (trainEntLimit == undefined)
return "";
var text = "\n\nCurrent Count: " + trainEntCount + ", Limit: " + trainEntLimit + ".";
if (trainEntCount >= trainEntLimit)
text = "[color=\"red\"]" + text + "[/color]";
for (var c in trainEntLimitChangers)
{
if (trainEntLimitChangers[c] > 0)
text += "\n" + c + " enlarges the limit with " + trainEntLimitChangers[c] + ".";
else if (trainEntLimitChangers[c] < 0)
text += "\n" + c + " lessens the limit with " + (-trainEntLimitChangers[c]) + ".";
}
return text;
}
/**
* Format batch training string for the tooltip
* Examples:
@ -457,15 +464,15 @@ function setupUnitPanel(guiName, usedPanels, unitEntState, playerState, items, c
getTrainingBatchStatus(playerState, unitEntState.id, entType, selection);
if (Engine.HotkeyIsPressed("session.batchtrain"))
trainNum = buildingsCountToTrainFullBatch * fullBatchSize + remainderBatch;
tooltip += "\n" + getEntityCostTooltip(template, trainNum, unitEntState.id);
var [trainEntLimit, trainEntCount, canBeAddedCount] =
getEntityLimitAndCount(playerState, entType);
tooltip += formatLimitString(trainEntLimit, trainEntCount);
tooltip += "[color=\"255 251 131\"]" + formatBatchTrainingString(buildingsCountToTrainFullBatch, fullBatchSize, remainderBatch) + "[/color]";
break;
tooltip += "\n" + getEntityCostTooltip(template, trainNum, unitEntState.id);
var [trainEntLimit, trainEntCount, canBeAddedCount, trainEntLimitChangers] =
getEntityLimitAndCount(playerState, entType);
tooltip += formatLimitString(trainEntLimit, trainEntCount, trainEntLimitChangers);
tooltip += "[color=\"255 251 131\"]" + formatBatchTrainingString(buildingsCountToTrainFullBatch, fullBatchSize, remainderBatch) + "[/color]";
break;
case RESEARCH:
var tooltip = getEntityNamesFormatted(template);
@ -492,9 +499,9 @@ function setupUnitPanel(guiName, usedPanels, unitEntState, playerState, items, c
tooltip += "\n" + getEntityCostTooltip(template);
tooltip += getPopulationBonusTooltip(template);
var [entLimit, entCount, canBeAddedCount] =
var [entLimit, entCount, canBeAddedCount, entLimitChangers] =
getEntityLimitAndCount(playerState, entType);
tooltip += formatLimitString(entLimit, entCount);
tooltip += formatLimitString(entLimit, entCount, entLimitChangers);
break;

View File

@ -4,18 +4,19 @@ EntityLimits.prototype.Schema =
"<a:help>Specifies per category limits on number of entities (buildings or units) that can be created for each player</a:help>" +
"<a:example>" +
"<Limits>" +
"<CivilCentre/>" +
"<DefenseTower>25</DefenseTower>" +
"<Fortress>10</Fortress>" +
"<Wonder>1</Wonder>" +
"<Hero>1</Hero>" +
"<Apadana>1</Apadana>" +
"<Monument>5</Monument>" +
"<DefenseTower>25</DefenseTower>" +
"<Fortress>10</Fortress>" +
"<Wonder>1</Wonder>" +
"<Hero>1</Hero>" +
"<Apadana>1</Apadana>" +
"<Monument>5</Monument>" +
"</Limits>" +
"<LimitChangers>" +
"<Monument>" +
"<CivCentre>2</CivCentre>" +
"</Monument>" +
"</LimitChangers>" +
"</a:example>" +
"<element name='LimitMultiplier'>" +
"<ref name='positiveDecimal'/>" +
"</element>" +
"<element name='Limits'>" +
"<zeroOrMore>" +
"<element a:help='Specifies a category of building/unit on which to apply this limit. See BuildRestrictions/TrainingRestrictions for possible categories'>" +
@ -23,8 +24,22 @@ EntityLimits.prototype.Schema =
"<data type='integer'/>" +
"</element>" +
"</zeroOrMore>" +
"</element>" +
"<element name='LimitChangers'>" +
"<zeroOrMore>" +
"<element a:help='Specifies a category of building/unit on which to apply this limit. See BuildRestrictions/TrainingRestrictions for possible categories'>" +
"<anyName />" +
"<zeroOrMore>" +
"<element a:help='Specifies the class that changes the entity limit'>" +
"<anyName />" +
"<data type='integer'/>" +
"</element>" +
"</zeroOrMore>" +
"</element>" +
"</zeroOrMore>" +
"</element>";
/*
* TODO: Use an inheriting player_{civ}.xml template for civ-specific limits
*/
@ -36,50 +51,30 @@ EntityLimits.prototype.Init = function()
{
this.limit = {};
this.count = {};
this.changers = {};
for (var category in this.template.Limits)
{
this.limit[category] = +this.template.Limits[category];
this.count[category] = 0;
if (!(category in this.template.LimitChangers))
continue;
this.changers[category] = {};
for (var c in this.template.LimitChangers[category])
this.changers[category][c] = +this.template.LimitChangers[category][c];
}
};
EntityLimits.prototype.IncreaseLimit = function(category, value)
EntityLimits.prototype.ChangeLimit = function(category, value)
{
if (!this.limit[category])
this.limit[category] = 0;
this.limit[category] += value;
};
EntityLimits.prototype.DecreaseLimit = function(category, value)
{
if (!this.limit[category])
this.limit[category] = 0;
this.limit[category] -= value;
};
EntityLimits.prototype.IncreaseCount = function(category, value)
EntityLimits.prototype.ChangeCount = function(category, value)
{
if (this.count[category] !== undefined)
this.count[category] += value;
};
EntityLimits.prototype.DecreaseCount = function(category, value)
{
if (this.count[category] !== undefined)
this.count[category] -= value;
};
EntityLimits.prototype.IncrementCount = function(category)
{
this.IncreaseCount(category, 1);
};
EntityLimits.prototype.DecrementCount = function(category)
{
this.DecreaseCount(category, 1);
};
EntityLimits.prototype.GetLimits = function()
{
return this.limit;
@ -90,11 +85,13 @@ EntityLimits.prototype.GetCounts = function()
return this.count;
};
EntityLimits.prototype.GetLimitChangers = function()
{
return this.changers;
};
EntityLimits.prototype.AllowedToCreate = function(limitType, category, count)
{
// TODO: The UI should reflect this before the user tries to place the building,
// since the limits are independent of placement location
// Allow unspecified categories and those with no limit
if (this.count[category] === undefined || this.limit[category] === undefined)
return true;
@ -116,9 +113,6 @@ EntityLimits.prototype.AllowedToCreate = function(limitType, category, count)
EntityLimits.prototype.AllowedToBuild = function(category)
{
// TODO: The UI should reflect this before the user tries to place the building,
// since the limits are independent of placement location
// We pass count 0 as the creation of the building has already taken place and
// the ownership has been set (triggering OnGlobalOwnershipChanged)
return this.AllowedToCreate(BUILD, category, 0);
@ -130,8 +124,22 @@ EntityLimits.prototype.AllowedToTrain = function(category, count)
};
EntityLimits.prototype.OnGlobalOwnershipChanged = function(msg)
{
// This automatically updates entity counts
{
// check if we are adding or removing an entity from this player
var cmpPlayer = Engine.QueryInterface(this.entity, IID_Player);
if (!cmpPlayer)
{
error("EntityLimits component is defined on a non-player entity");
return;
}
if (msg.from == cmpPlayer.GetPlayerID())
var modifier = -1;
else if (msg.to == cmpPlayer.GetPlayerID())
var modifier = 1;
else
return;
// Update entity counts
var category = null;
var cmpBuildRestrictions = Engine.QueryInterface(msg.entity, IID_BuildRestrictions);
if (cmpBuildRestrictions)
@ -140,13 +148,17 @@ EntityLimits.prototype.OnGlobalOwnershipChanged = function(msg)
if (cmpTrainingRestrictions)
category = cmpTrainingRestrictions.GetCategory();
if (category)
{
var playerID = (Engine.QueryInterface(this.entity, IID_Player)).GetPlayerID();
if (msg.from == playerID)
this.DecrementCount(category);
if (msg.to == playerID)
this.IncrementCount(category);
}
this.ChangeCount(category,modifier);
// Update entity limits
var cmpIdentity = Engine.QueryInterface(msg.entity, IID_Identity);
if (!cmpIdentity)
return;
var classes = cmpIdentity.GetClassesList();
for (var category in this.changers)
for (var c in this.changers[category])
if (classes.indexOf(c) >= 0)
this.ChangeLimit(category, modifier * this.changers[category][c]);
};
Engine.RegisterComponentType(IID_EntityLimits, "EntityLimits", EntityLimits);

View File

@ -1,58 +0,0 @@
function EntityLimitsChanger() {}
EntityLimitsChanger.prototype.Schema =
"<oneOrMore>" +
"<element a:help='Take as name the name of the category, and as value the number you want to increase the limit with.'>" +
"<anyName/>" +
"<data type='integer'/>" +
"</element>" +
"</oneOrMore>";
EntityLimitsChanger.prototype.init = function()
{
};
EntityLimitsChanger.prototype.OnOwnershipChanged = function(msg)
{
if (!this.changes)
{
this.changes = {};
for (var cat in this.template)
this.changes[cat] = ApplyValueModificationsToEntity("EntityLimitsChanger/Value", +this.template[cat], this.entity);
}
if (msg.from > -1)
{
var cmpEntityLimits = QueryPlayerIDInterface(msg.from, IID_EntityLimits);
if (cmpEntityLimits)
for (var cat in this.changes)
cmpEntityLimits.DecreaseLimit(cat, this.changes[cat]);
}
if (msg.to > -1)
{
var cmpEntityLimits = QueryPlayerIDInterface(msg.to, IID_EntityLimits);
if (cmpEntityLimits)
for (var cat in this.changes)
cmpEntityLimits.IncreaseLimit(cat, this.changes[cat]);
}
}
EntityLimitsChanger.prototype.OnValueModification = function(msg)
{
if (msg.component != "EntityLimitsChanger")
return;
var cmpEntityLimits = Engine.QueryOwnerInterface(this.entity, IID_EntityLimits);
if (!cmpEntityLimits)
return;
for (var cat in this.changes)
{
cmpEntityLimits.DecreaseLimit(cat, this.changes[cat]);
this.changes[cat] = ApplyValueModificationsToEntity("EntityLimitsChanger/Value", +this.template[cat], this.entity);
cmpEntityLimits.IncreaseLimit(cat, this.changes[cat]);
}
};
Engine.RegisterComponentType(IID_EntityLimitsChanger, "EntityLimitsChanger", EntityLimitsChanger);

View File

@ -94,6 +94,7 @@ GuiInterface.prototype.GetSimulationState = function(player)
"isEnemy": enemies,
"entityLimits": cmpPlayerEntityLimits.GetLimits(),
"entityCounts": cmpPlayerEntityLimits.GetCounts(),
"entityLimitChangers": cmpPlayerEntityLimits.GetLimitChangers(),
"techModifications": cmpTechnologyManager.GetTechModifications(),
"researchQueued": cmpTechnologyManager.GetQueuedResearch(),
"researchStarted": cmpTechnologyManager.GetStartedResearch(),

View File

@ -255,7 +255,7 @@ ProductionQueue.prototype.AddBatch = function(templateName, type, count, metadat
{
var unitCategory = template.TrainingRestrictions.Category;
var cmpPlayerEntityLimits = QueryOwnerInterface(this.entity, IID_EntityLimits);
cmpPlayerEntityLimits.IncreaseCount(unitCategory, count);
cmpPlayerEntityLimits.ChangeCount(unitCategory, count);
}
this.queue.push({
@ -362,7 +362,7 @@ ProductionQueue.prototype.RemoveBatch = function(id)
{
var unitCategory = template.TrainingRestrictions.Category;
var cmpPlayerEntityLimits = QueryPlayerIDInterface(item.player, IID_EntityLimits);
cmpPlayerEntityLimits.DecreaseCount(unitCategory, item.count);
cmpPlayerEntityLimits.ChangeCount(unitCategory, -item.count);
}
}
@ -508,7 +508,7 @@ ProductionQueue.prototype.SpawnUnits = function(templateName, count, metadata)
{
var unitCategory = cmpTrainingRestrictions.GetCategory();
var cmpPlayerEntityLimits = QueryOwnerInterface(this.entity, IID_EntityLimits);
cmpPlayerEntityLimits.DecrementCount(unitCategory);
cmpPlayerEntityLimits.ChangeCount(unitCategory,-1);
}
}
}

View File

@ -1 +0,0 @@
Engine.RegisterInterface("EntityLimitsChanger");

View File

@ -14,7 +14,6 @@
<AlertnessMax>8</AlertnessMax>
</BattleDetection>
<EntityLimits>
<LimitMultiplier>1.0</LimitMultiplier>
<Limits>
<DefenseTower>30</DefenseTower>
<Fortress>10</Fortress>
@ -30,6 +29,14 @@
<Library>1</Library>
<Lighthouse>1</Lighthouse>
</Limits>
<LimitChangers>
<WarDog>
<Kennel>10</Kennel>
</WarDog>
<Pillar>
<Ashoka>5</Ashoka>
</Pillar>
</LimitChangers>
</EntityLimits>
<Player/>
<StatisticsTracker/>

View File

@ -18,9 +18,6 @@
<stone>50</stone>
</Resources>
</Cost>
<EntityLimitsChanger>
<WarDog>10</WarDog>
</EntityLimitsChanger>
<Footprint>
<Square width="8.0" depth="7.0"/>
<Height>5.0</Height>
@ -34,7 +31,8 @@
<Civ>brit</Civ>
<GenericName>Special Building</GenericName>
<SpecificName>Kennel</SpecificName>
<Tooltip>Train Celtic war dogs. One kennel can only house 10 dogs.</Tooltip>
<Classes>Kennel</Classes>
<Tooltip>Train Celtic war dogs.</Tooltip>
<Icon>structures/kennel.png</Icon>
<RequiredTechnology>phase_town</RequiredTechnology>
</Identity>

View File

@ -18,9 +18,6 @@
<stone>50</stone>
</Resources>
</Cost>
<EntityLimitsChanger>
<WarDog>10</WarDog>
</EntityLimitsChanger>
<Footprint>
<Square width="8.0" depth="7.0"/>
<Height>5.0</Height>
@ -34,7 +31,8 @@
<Civ>celt</Civ>
<GenericName>Special Building</GenericName>
<SpecificName>Kennel</SpecificName>
<Tooltip>Train Celtic war dogs. One kennel can only house 10 dogs.</Tooltip>
<Classes>Kennel</Classes>
<Tooltip>Train Celtic war dogs.</Tooltip>
<Icon>structures/kennel.png</Icon>
<RequiredTechnology>phase_town</RequiredTechnology>
</Identity>

View File

@ -26,7 +26,7 @@
<GenericName>Edict Pillar of Ashoka</GenericName>
<SpecificName>Śāsana Stambha Aśokā</SpecificName>
<Icon>structures/monument.png</Icon>
<Tooltip>The famous pillar of Ashoka. Can only be build when the hero Ashoka is alive. Currently a useless structure.</Tooltip>
<Tooltip>The famous pillar of Ashoka. Currently a useless structure.</Tooltip>
<History>.</History>
</Identity>
<Obstruction>

View File

@ -20,9 +20,6 @@
<metal>100</metal>
</Resources>
</Cost>
<EntityLimitsChanger>
<Pillar>5</Pillar>
</EntityLimitsChanger>
<Footprint replace="">
<Square width="6.0" depth="12.0"/>
<Height>5.0</Height>
@ -34,6 +31,7 @@
<Civ>maur</Civ>
<GenericName>Ashoka the Great</GenericName>
<SpecificName>Aśoka Devānāmpriya</SpecificName>
<Classes>Ashoka</Classes>
<Icon>units/maur_hero_ashoka.png</Icon>
<Tooltip>Hero Chariot Archer.
Hero Aura: TBD.