Index: ps/trunk/binaries/data/mods/public/gui/common/tooltips.js =================================================================== --- ps/trunk/binaries/data/mods/public/gui/common/tooltips.js (revision 27504) +++ ps/trunk/binaries/data/mods/public/gui/common/tooltips.js (revision 27505) @@ -1,1242 +1,1242 @@ var g_TooltipTextFormats = { "unit": { "font": "sans-10", "color": "orange" }, "header": { "font": "sans-bold-13" }, "body": { "font": "sans-13" }, "objection": { "font": "sans-bold-13", "color": "red" }, "comma": { "font": "sans-12" }, "namePrimaryBig": { "font": "sans-bold-16" }, "namePrimarySmall": { "font": "sans-bold-12" }, "nameSecondary": { "font": "sans-bold-16" } }; var g_SpecificNamesPrimary = Engine.ConfigDB_GetValue("user", "gui.session.howtoshownames") == 0 || Engine.ConfigDB_GetValue("user", "gui.session.howtoshownames") == 2; var g_ShowSecondaryNames = Engine.ConfigDB_GetValue("user", "gui.session.howtoshownames") == 0 || Engine.ConfigDB_GetValue("user", "gui.session.howtoshownames") == 1; function initDisplayedNames() { registerConfigChangeHandler(changes => { if (changes.has("gui.session.howtoshownames")) updateDisplayedNames(); }); } /** * String of four spaces to be used as indentation in gui strings. */ var g_Indent = " "; var g_DamageTypesMetadata = new DamageTypesMetadata(); var g_StatusEffectsMetadata = new StatusEffectsMetadata(); /** * If true, always shows whether the splash damage deals friendly fire. * Otherwise display the friendly fire tooltip only if it does. */ var g_AlwaysDisplayFriendlyFire = false; function getCostTypes() { return g_ResourceData.GetCodes().concat(["population", "time"]); } function resourceIcon(resource) { return '[icon="icon_' + resource + '"]'; } function resourceNameFirstWord(type) { return translateWithContext("firstWord", g_ResourceData.GetNames()[type]); } function resourceNameWithinSentence(type) { return translateWithContext("withinSentence", g_ResourceData.GetNames()[type]); } /** * Format resource amounts to proper english and translate (for example: "200 food, 100 wood and 300 metal"). */ function getLocalizedResourceAmounts(resources) { let amounts = g_ResourceData.GetCodes() .filter(type => !!resources[type]) .map(type => sprintf(translate("%(amount)s %(resourceType)s"), { "amount": resources[type], "resourceType": resourceNameWithinSentence(type) })); if (amounts.length < 2) return amounts.join(); let lastAmount = amounts.pop(); return sprintf(translate("%(previousAmounts)s and %(lastAmount)s"), { // Translation: This comma is used for separating first to penultimate elements in an enumeration. "previousAmounts": amounts.join(translate(", ")), "lastAmount": lastAmount }); } function bodyFont(text) { return setStringTags(text, g_TooltipTextFormats.body); } function objectionFont(text) { return setStringTags(text, g_TooltipTextFormats.objection); } function headerFont(text) { return setStringTags(text, g_TooltipTextFormats.header); } function unitFont(text) { return setStringTags(text, g_TooltipTextFormats.unit); } function commaFont(text) { return setStringTags(text, g_TooltipTextFormats.comma); } function getSecondsString(seconds) { return sprintf(translatePlural("%(time)s %(second)s", "%(time)s %(second)s", seconds), { "time": seconds, "second": unitFont(translatePlural("second", "seconds", seconds)) }); } /** * Entity templates have a `Tooltip` tag in the Identity component. * (The contents of which are copied to a `tooltip` attribute in globalscripts.) * * Technologies have a `tooltip` attribute. */ function getEntityTooltip(template) { if (!template.tooltip) return ""; return bodyFont(template.tooltip); } /** * Technologies have a `description` attribute, and Auras have an `auraDescription` * attribute, which becomes `description`. * * (For technologies, this happens in globalscripts.) * * (For auras, this happens either in the Auras component (for session gui) or * reference/common/load.js (for Reference Suite gui)) */ function getDescriptionTooltip(template) { if (!template.description) return ""; return bodyFont(template.description); } /** * Entity templates have a `History` tag in the Identity component. * (The contents of which are copied to a `history` attribute in globalscripts.) */ function getHistoryTooltip(template) { if (!template.history) return ""; return bodyFont(template.history); } function getHealthTooltip(template) { if (!template.health) return ""; return sprintf(translate("%(label)s %(details)s"), { "label": headerFont(translate("Health:")), "details": template.health }); } function getCurrentHealthTooltip(entState, label) { if (!entState.maxHitpoints) return ""; return sprintf(translate("%(healthLabel)s %(current)s / %(max)s"), { "healthLabel": headerFont(label || translate("Health:")), "current": Math.round(entState.hitpoints), "max": Math.round(entState.maxHitpoints) }); } function getCurrentCaptureTooltip(entState, label) { if (!entState.maxCapturePoints) return ""; return sprintf(translate("%(captureLabel)s %(current)s / %(max)s"), { "captureLabel": headerFont(label || translate("Capture points:")), "current": Math.round(entState.capturePoints[entState.player]), "max": Math.round(entState.maxCapturePoints) }); } /** * Converts an resistance level into the actual reduction percentage. */ function resistanceLevelToPercentageString(level) { return sprintf(translate("%(percentage)s%%"), { "percentage": (100 - Math.round(Math.pow(0.9, level) * 100)) }); } function getResistanceTooltip(template) { if (!template.resistance) return ""; let details = []; if (template.resistance.Damage) details.push(getDamageResistanceTooltip(template.resistance.Damage)); if (template.resistance.Capture) details.push(getCaptureResistanceTooltip(template.resistance.Capture)); if (template.resistance.ApplyStatus) details.push(getStatusEffectsResistanceTooltip(template.resistance.ApplyStatus)); return details.length ? sprintf(translate("%(label)s\n%(details)s"), { "label": headerFont(translate("Resistance:")), "details": g_Indent + details.join("\n" + g_Indent) }) : ""; } function getDamageResistanceTooltip(resistanceTypeTemplate) { if (!resistanceTypeTemplate) return ""; return sprintf(translate("%(label)s %(details)s"), { "label": headerFont(translate("Damage:")), "details": g_DamageTypesMetadata.sort(Object.keys(resistanceTypeTemplate)).map( dmgType => sprintf(translate("%(damage)s %(damageType)s %(resistancePercentage)s"), { "damage": resistanceTypeTemplate[dmgType].toFixed(1), "damageType": unitFont(translateWithContext("damage type", g_DamageTypesMetadata.getName(dmgType))), "resistancePercentage": '[font="sans-10"]' + sprintf(translate("(%(resistancePercentage)s)"), { "resistancePercentage": resistanceLevelToPercentageString(resistanceTypeTemplate[dmgType]) }) + '[/font]' }) ).join(commaFont(translate(", "))) }); } function getCaptureResistanceTooltip(resistanceTypeTemplate) { if (!resistanceTypeTemplate) return ""; return sprintf(translate("%(label)s %(details)s"), { "label": headerFont(translate("Capture:")), "details": sprintf(translate("%(damage)s %(damageType)s %(resistancePercentage)s"), { "damage": resistanceTypeTemplate.toFixed(1), "damageType": unitFont(translateWithContext("damage type", "Capture")), "resistancePercentage": '[font="sans-10"]' + sprintf(translate("(%(resistancePercentage)s)"), { "resistancePercentage": resistanceLevelToPercentageString(resistanceTypeTemplate) }) + '[/font]' }) }); } function getStatusEffectsResistanceTooltip(resistanceTypeTemplate) { if (!resistanceTypeTemplate) return ""; return sprintf(translate("%(label)s %(details)s"), { "label": headerFont(translate("Status Effects:")), "details": Object.keys(resistanceTypeTemplate).map( statusEffect => { if (resistanceTypeTemplate[statusEffect].blockChance == 1) return sprintf(translate("Blocks %(name)s"), { "name": unitFont(translateWithContext("status effect", g_StatusEffectsMetadata.getName(statusEffect))) }); if (resistanceTypeTemplate[statusEffect].blockChance == 0) return sprintf(translate("%(name)s %(details)s"), { "name": unitFont(translateWithContext("status effect", g_StatusEffectsMetadata.getName(statusEffect))), "details": sprintf(translate("Duration reduction: %(durationReduction)s%%"), { "durationReduction": (100 - resistanceTypeTemplate[statusEffect].duration * 100) }) }); if (resistanceTypeTemplate[statusEffect].duration == 1) return sprintf(translate("%(name)s %(details)s"), { "name": unitFont(translateWithContext("status effect", g_StatusEffectsMetadata.getName(statusEffect))), "details": sprintf(translate("Blocks: %(blockPercentage)s%%"), { "blockPercentage": resistanceTypeTemplate[statusEffect].blockChance * 100 }) }); return sprintf(translate("%(name)s %(details)s"), { "name": unitFont(translateWithContext("status effect", g_StatusEffectsMetadata.getName(statusEffect))), "details": sprintf(translate("Blocks: %(blockPercentage)s%%, Duration reduction: %(durationReduction)s%%"), { "blockPercentage": resistanceTypeTemplate[statusEffect].blockChance * 100, "durationReduction": (100 - resistanceTypeTemplate[statusEffect].duration * 100) }) }); } ).join(commaFont(translate(", "))) }); } function attackRateDetails(interval, projectiles) { if (!interval) return ""; if (projectiles === 0) return translate("Garrison to fire arrows"); let attackRateString = getSecondsString(interval / 1000); let header = headerFont(translate("Interval:")); if (projectiles && +projectiles > 1) { header = headerFont(translate("Rate:")); let projectileString = sprintf(translatePlural("%(projectileCount)s %(projectileName)s", "%(projectileCount)s %(projectileName)s", projectiles), { "projectileCount": projectiles, "projectileName": unitFont(translatePlural("arrow", "arrows", projectiles)) }); attackRateString = sprintf(translate("%(projectileString)s / %(attackRateString)s"), { "projectileString": projectileString, "attackRateString": attackRateString }); } return sprintf(translate("%(label)s %(details)s"), { "label": header, "details": attackRateString }); } function rangeDetails(attackTypeTemplate) { if (!attackTypeTemplate.maxRange) return ""; let rangeTooltipString = { "relative": { // Translation: For example: Range: 2 to 10 (+2) meters "minRange": translate("%(rangeLabel)s %(minRange)s to %(maxRange)s (%(relativeRange)s) %(rangeUnit)s"), // Translation: For example: Range: 10 (+2) meters "no-minRange": translate("%(rangeLabel)s %(maxRange)s (%(relativeRange)s) %(rangeUnit)s"), }, "non-relative": { // Translation: For example: Range: 2 to 10 meters "minRange": translate("%(rangeLabel)s %(minRange)s to %(maxRange)s %(rangeUnit)s"), // Translation: For example: Range: 10 meters "no-minRange": translate("%(rangeLabel)s %(maxRange)s %(rangeUnit)s"), } }; let minRange = Math.round(attackTypeTemplate.minRange); let maxRange = Math.round(attackTypeTemplate.maxRange); let realRange = attackTypeTemplate.elevationAdaptedRange; let relativeRange = realRange ? Math.round(realRange - maxRange) : 0; return sprintf(rangeTooltipString[relativeRange ? "relative" : "non-relative"][minRange ? "minRange" : "no-minRange"], { "rangeLabel": headerFont(translate("Range:")), "minRange": minRange, "maxRange": maxRange, "relativeRange": relativeRange > 0 ? sprintf(translate("+%(number)s"), { "number": relativeRange }) : relativeRange, "rangeUnit": unitFont(minRange || relativeRange ? // Translation: For example "0.5 to 1 meters", "1 (+1) meters" or "1 to 2 (+3) meters" translate("meters") : translatePlural("meter", "meters", maxRange)) }); } function damageDetails(damageTemplate) { if (!damageTemplate) return ""; return g_DamageTypesMetadata.sort(Object.keys(damageTemplate).filter(dmgType => damageTemplate[dmgType])).map( dmgType => sprintf(translate("%(damage)s %(damageType)s"), { "damage": (+damageTemplate[dmgType]).toFixed(1), "damageType": unitFont(translateWithContext("damage type", g_DamageTypesMetadata.getName(dmgType))) })).join(commaFont(translate(", "))); } function captureDetails(captureTemplate) { if (!captureTemplate) return ""; return sprintf(translate("%(amount)s %(name)s"), { "amount": (+captureTemplate).toFixed(1), "name": unitFont(translateWithContext("damage type", "Capture")) }); } function splashDetails(splashTemplate) { let splashLabel = sprintf(headerFont(translate("%(splashShape)s Splash")), { "splashShape": translate(splashTemplate.shape) }); let splashDamageTooltip = sprintf(translate("%(label)s: %(effects)s"), { "label": splashLabel, "effects": attackEffectsDetails(splashTemplate) }); if (g_AlwaysDisplayFriendlyFire || splashTemplate.friendlyFire) splashDamageTooltip += commaFont(translate(", ")) + sprintf(translate("Friendly Fire: %(enabled)s"), { "enabled": splashTemplate.friendlyFire ? translate("Yes") : translate("No") }); return splashDamageTooltip; } function applyStatusDetails(applyStatusTemplate) { if (!applyStatusTemplate) return ""; return sprintf(translate("gives %(name)s"), { "name": Object.keys(applyStatusTemplate).map(x => unitFont(translateWithContext("status effect", g_StatusEffectsMetadata.getName(x))) ).join(commaFont(translate(", "))), }); } function attackEffectsDetails(attackTypeTemplate) { if (!attackTypeTemplate) return ""; let effects = [ captureDetails(attackTypeTemplate.Capture || undefined), damageDetails(attackTypeTemplate.Damage || undefined), applyStatusDetails(attackTypeTemplate.ApplyStatus || undefined) ]; return effects.filter(effect => effect).join(commaFont(translate(", "))); } function getAttackTooltip(template) { if (!template.attack) return ""; let tooltips = []; for (let attackType in template.attack) { // Slaughter is used to kill animals, so do not show it. if (attackType == "Slaughter") continue; let attackTypeTemplate = template.attack[attackType]; let attackLabel = sprintf(headerFont(translate("%(attackType)s")), { "attackType": translateWithContext(attackTypeTemplate.attackName.context || "Name of an attack, usually the weapon.", attackTypeTemplate.attackName.name) }); let projectiles; // Use either current rate from simulation or default count if the sim is not running. // TODO: This ought to be extended to include units which fire multiple projectiles. if (template.buildingAI) projectiles = template.buildingAI.arrowCount || template.buildingAI.defaultArrowCount; let splashTemplate = attackTypeTemplate.splash; // Show the effects of status effects below. let statusEffectsDetails = []; if (attackTypeTemplate.ApplyStatus) for (let status in attackTypeTemplate.ApplyStatus) statusEffectsDetails.push("\n" + g_Indent + g_Indent + getStatusEffectsTooltip(status, attackTypeTemplate.ApplyStatus[status], true)); statusEffectsDetails = statusEffectsDetails.join(""); tooltips.push(sprintf(translate("%(attackLabel)s: %(effects)s, %(range)s, %(rate)s%(statusEffects)s%(splash)s"), { "attackLabel": attackLabel, "effects": attackEffectsDetails(attackTypeTemplate), "range": rangeDetails(attackTypeTemplate), "rate": attackRateDetails(attackTypeTemplate.repeatTime, projectiles), "splash": splashTemplate ? "\n" + g_Indent + g_Indent + splashDetails(splashTemplate) : "", "statusEffects": statusEffectsDetails })); } return sprintf(translate("%(label)s\n%(details)s"), { "label": headerFont(translate("Attack:")), "details": g_Indent + tooltips.join("\n" + g_Indent) }); } /** * @param applier - if true, return the tooltip for the Applier. If false, Receiver is returned. */ function getStatusEffectsTooltip(statusCode, template, applier) { let tooltipAttributes = []; let statusData = g_StatusEffectsMetadata.getData(statusCode); if (template.Damage || template.Capture) tooltipAttributes.push(attackEffectsDetails(template)); if (template.Interval) tooltipAttributes.push(attackRateDetails(+template.Interval)); if (template.Duration) tooltipAttributes.push(getStatusEffectDurationTooltip(template)); if (applier && statusData.applierTooltip) tooltipAttributes.push(translateWithContext("status effect", statusData.applierTooltip)); else if (!applier && statusData.receiverTooltip) tooltipAttributes.push(translateWithContext("status effect", statusData.receiverTooltip)); if (applier) return sprintf(translate("%(statusName)s: %(statusInfo)s %(stackability)s"), { "statusName": headerFont(translateWithContext("status effect", statusData.statusName)), "statusInfo": tooltipAttributes.join(commaFont(translate(", "))), "stackability": getStatusEffectStackabilityTooltip(template) }); return sprintf(translate("%(statusName)s: %(statusInfo)s"), { "statusName": headerFont(translateWithContext("status effect", statusData.statusName)), "statusInfo": tooltipAttributes.join(commaFont(translate(", "))) }); } function getStatusEffectDurationTooltip(template) { if (!template.Duration) return ""; return sprintf(translate("%(durName)s: %(duration)s"), { "durName": headerFont(translate("Duration")), "duration": getSecondsString((template._timeElapsed ? +template.Duration - template._timeElapsed : +template.Duration) / 1000) }); } function getStatusEffectStackabilityTooltip(template) { if (!template.Stackability || template.Stackability == "Ignore") return ""; let stackabilityString = ""; if (template.Stackability === "Extend") stackabilityString = translateWithContext("status effect stackability", "(extends)"); else if (template.Stackability === "Replace") stackabilityString = translateWithContext("status effect stackability", "(replaces)"); else if (template.Stackability === "Stack") stackabilityString = translateWithContext("status effect stackability", "(stacks)"); return sprintf(translate("%(stackability)s"), { "stackability": stackabilityString }); } function getGarrisonTooltip(template) { let tooltips = []; if (template.garrisonHolder) { tooltips.push ( sprintf(translate("%(label)s: %(garrisonLimit)s"), { "label": headerFont(translate("Garrison Limit")), "garrisonLimit": template.garrisonHolder.capacity }) ); if (template.garrisonHolder.buffHeal) tooltips.push( sprintf(translate("%(healRateLabel)s %(value)s %(health)s / %(second)s"), { "healRateLabel": headerFont(translate("Heal:")), "value": Math.round(template.garrisonHolder.buffHeal), "health": unitFont(translateWithContext("garrison tooltip", "Health")), "second": unitFont(translate("second")), }) ); tooltips.join(commaFont(translate(", "))); } if (template.garrisonable) { let extraSize; if (template.garrisonHolder) extraSize = template.garrisonHolder.occupiedSlots; if (template.garrisonable.size > 1 || extraSize) tooltips.push ( sprintf(translate("%(label)s: %(garrisonSize)s %(extraSize)s"), { "label": headerFont(translate("Garrison Size")), "garrisonSize": template.garrisonable.size, "extraSize": extraSize ? translateWithContext("nested garrison", "+ ") + extraSize : "" }) ); } return tooltips.join("\n"); } function getTurretsTooltip(template) { if (!template.turretHolder) return ""; return sprintf(translate("%(label)s: %(turretsLimit)s"), { "label": headerFont(translate("Turret Positions")), "turretsLimit": Object.keys(template.turretHolder.turretPoints).length }); } function getProjectilesTooltip(template) { if (!template.garrisonHolder || !template.buildingAI) return ""; let limit = Math.min( template.buildingAI.maxArrowCount || Infinity, template.buildingAI.defaultArrowCount + Math.round(template.buildingAI.garrisonArrowMultiplier * template.garrisonHolder.capacity) ); if (!limit) return ""; return [ sprintf(translate("%(label)s: %(value)s"), { "label": headerFont(translate("Projectile Limit")), "value": limit }), sprintf(translate("%(label)s: %(value)s"), { "label": headerFont(translateWithContext("projectiles", "Default")), "value": template.buildingAI.defaultArrowCount }), sprintf(translate("%(label)s: %(value)s"), { "label": headerFont(translateWithContext("projectiles", "Per Unit")), "value": +template.buildingAI.garrisonArrowMultiplier.toFixed(2) }) ].join(commaFont(translate(", "))); } function getRepairTimeTooltip(entState) { let result = []; result.push(sprintf(translate("%(label)s %(details)s"), { "label": headerFont(translate("Number of repairers:")), "details": entState.repairable.numBuilders })); if (entState.repairable.numBuilders) { result.push(sprintf(translate("%(label)s %(details)s"), { "label": headerFont(translate("Remaining repair time:")), "details": getSecondsString(Math.floor(entState.repairable.buildTime.timeRemaining)) })); let timeReduction = Math.round(entState.repairable.buildTime.timeRemaining - entState.repairable.buildTime.timeRemainingNew); result.push(sprintf(translatePlural( "Add another worker to speed up the repairs by %(second)s second.", "Add another worker to speed up the repairs by %(second)s seconds.", timeReduction), { "second": timeReduction })); } else result.push(sprintf(translatePlural( "Add a worker to finish the repairs in %(second)s second.", "Add a worker to finish the repairs in %(second)s seconds.", Math.round(entState.repairable.buildTime.timeRemainingNew)), { "second": Math.round(entState.repairable.buildTime.timeRemainingNew) })); return result.join("\n"); } function getBuildTimeTooltip(entState) { let result = []; result.push(sprintf(translate("%(label)s %(details)s"), { "label": headerFont(translate("Number of builders:")), "details": entState.foundation.numBuilders })); if (entState.foundation.numBuilders) { result.push(sprintf(translate("%(label)s %(details)s"), { "label": headerFont(translate("Remaining build time:")), "details": getSecondsString(Math.floor(entState.foundation.buildTime.timeRemaining)) })); let timeReduction = Math.round(entState.foundation.buildTime.timeRemaining - entState.foundation.buildTime.timeRemainingNew); result.push(sprintf(translatePlural( "Add another worker to speed up the construction by %(second)s second.", "Add another worker to speed up the construction by %(second)s seconds.", timeReduction), { "second": timeReduction })); } else result.push(sprintf(translatePlural( "Add a worker to finish the construction in %(second)s second.", "Add a worker to finish the construction in %(second)s seconds.", Math.round(entState.foundation.buildTime.timeRemainingNew)), { "second": Math.round(entState.foundation.buildTime.timeRemainingNew) })); return result.join("\n"); } /** * Multiplies the costs for a template by a given batch size. */ function multiplyEntityCosts(template, trainNum) { let totalCosts = {}; for (let r of getCostTypes()) if (template.cost[r]) totalCosts[r] = Math.floor(template.cost[r] * trainNum); return totalCosts; } /** * Helper function for getEntityCostTooltip. */ function getEntityCostComponentsTooltipString(template, entity, buildingsCountToTrainFullBatch = 1, fullBatchSize = 1, remainderBatch = 0) { if (!template.cost) return []; let totalCosts = multiplyEntityCosts(template, buildingsCountToTrainFullBatch * fullBatchSize + remainderBatch); if (template.cost.time) totalCosts.time = Math.ceil(template.cost.time * (entity ? Engine.GuiInterfaceCall("GetBatchTime", { "entity": entity, "batchSize": buildingsCountToTrainFullBatch > 0 ? fullBatchSize : remainderBatch }) : 1)); let costs = []; for (let type of getCostTypes()) if (totalCosts[type]) costs.push(sprintf(translate("%(component)s %(cost)s"), { "component": resourceIcon(type), "cost": totalCosts[type] })); return costs; } function getGatherTooltip(template) { if (!template.resourceGatherRates) return ""; let rates = {}; for (let resource of g_ResourceData.GetResources()) { let types = [resource.code]; for (let subtype in resource.subtypes) { // We ignore ruins as those are not that common if (subtype == "ruins") continue; let rate = template.resourceGatherRates[resource.code + "." + subtype]; if (rate > 0) rates[resource.code + "_" + subtype] = rate; } } if (!Object.keys(rates).length) return ""; return sprintf(translate("%(label)s %(details)s"), { "label": headerFont(translate("Gather Rates:")), "details": Object.keys(rates).map( type => sprintf(translate("%(resourceIcon)s %(rate)s"), { "resourceIcon": resourceIcon(type), "rate": rates[type].toFixed(2) }) ).join(" ") }); } /** * Returns the resources this entity supplies in the specified entity's tooltip */ function getResourceSupplyTooltip(template) { if (!template.supply) return ""; let supply = template.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"), { "label": headerFont(translate("Resource Supply:")), "component": resourceIcon(supply.type[0]), // Translation: Marks that a resource supply entity has an unending, infinite, supply of its resource. "amount": Number.isFinite(+supply.amount) ? supply.amount : translate("∞") }); } /** * @param {Object} template - The entity's template. * @return {string} - The resources this entity rewards to a collecter. */ function getTreasureTooltip(template) { if (!template.treasure) return ""; let resources = {}; for (let resource of g_ResourceData.GetResources()) { let type = resource.code; if (template.treasure.resources[type]) resources[type] = template.treasure.resources[type]; } let resourceNames = Object.keys(resources); if (!resourceNames.length) return ""; return sprintf(translate("%(label)s %(details)s"), { "label": headerFont(translate("Reward:")), "details": resourceNames.map( type => sprintf(translate("%(resourceIcon)s %(reward)s"), { "resourceIcon": resourceIcon(type), "reward": resources[type] }) ).join(" ") }); } function getResourceTrickleTooltip(template) { if (!template.resourceTrickle) return ""; let resCodes = g_ResourceData.GetCodes().filter(res => !!template.resourceTrickle.rates[res]); if (!resCodes.length) return ""; return sprintf(translate("%(label)s %(details)s"), { "label": headerFont(translate("Resource Trickle:")), "details": sprintf(translate("%(resources)s / %(time)s"), { "resources": resCodes.map( res => sprintf(translate("%(resourceIcon)s %(rate)s"), { "resourceIcon": resourceIcon(res), "rate": template.resourceTrickle.rates[res] }) ).join(" "), "time": getSecondsString(template.resourceTrickle.interval / 1000) }) }); } function getUpkeepTooltip(template) { if (!template.upkeep) return ""; let resCodes = g_ResourceData.GetCodes().filter(res => !!template.upkeep.rates[res]); if (!resCodes.length) return ""; return sprintf(translate("%(label)s %(details)s"), { "label": headerFont(translate("Upkeep:")), "details": sprintf(translate("%(resources)s / %(time)s"), { "resources": resCodes.map( res => sprintf(translate("%(resourceIcon)s %(rate)s"), { "resourceIcon": resourceIcon(res), "rate": template.upkeep.rates[res] }) ).join(" "), "time": getSecondsString(template.upkeep.interval / 1000) }) }); } /** * Returns an array of strings for a set of wall pieces. If the pieces share * resource type requirements, output will be of the form '10 to 30 Stone', * otherwise output will be, e.g. '10 Stone, 20 Stone, 30 Stone'. */ function getWallPieceTooltip(wallTypes) { let out = []; let resourceCount = {}; for (let resource of getCostTypes()) if (wallTypes[0].cost[resource]) resourceCount[resource] = [wallTypes[0].cost[resource]]; let sameTypes = true; for (let i = 1; i < wallTypes.length; ++i) { for (let resource in wallTypes[i].cost) // Break out of the same-type mode if this wall requires // resource types that the first didn't. if (wallTypes[i].cost[resource] && !resourceCount[resource]) { sameTypes = false; break; } for (let resource in resourceCount) if (wallTypes[i].cost[resource]) resourceCount[resource].push(wallTypes[i].cost[resource]); else { sameTypes = false; break; } } if (sameTypes) for (let resource in resourceCount) // Translation: This string is part of the resources cost string on // the tooltip for wall structures. out.push(sprintf(translate("%(resourceIcon)s %(minimum)s to %(resourceIcon)s %(maximum)s"), { "resourceIcon": resourceIcon(resource), "minimum": Math.min.apply(Math, resourceCount[resource]), "maximum": Math.max.apply(Math, resourceCount[resource]) })); else for (let i = 0; i < wallTypes.length; ++i) out.push(getEntityCostComponentsTooltipString(wallTypes[i]).join(", ")); return out; } /** * Returns the cost information to display in the specified entity's construction button tooltip. */ function getEntityCostTooltip(template, player, entity, buildingsCountToTrainFullBatch, fullBatchSize, remainderBatch) { // Entities with a wallset component are proxies for initiating wall placement and as such do not have a cost of // their own; the individual wall pieces within it do. if (template.wallSet) { let templateLong = GetTemplateData(template.wallSet.templates.long, player); let templateMedium = GetTemplateData(template.wallSet.templates.medium, player); let templateShort = GetTemplateData(template.wallSet.templates.short, player); let templateTower = GetTemplateData(template.wallSet.templates.tower, player); let wallCosts = getWallPieceTooltip([templateShort, templateMedium, templateLong]); let towerCosts = getEntityCostComponentsTooltipString(templateTower); return sprintf(translate("Walls: %(costs)s"), { "costs": wallCosts.join(" ") }) + "\n" + sprintf(translate("Towers: %(costs)s"), { "costs": towerCosts.join(" ") }); } if (template.cost) { let costs = getEntityCostComponentsTooltipString(template, entity, buildingsCountToTrainFullBatch, fullBatchSize, remainderBatch).join(" "); if (costs) // Translation: Label in tooltip showing cost of a unit, structure or technology. return sprintf(translate("%(label)s %(costs)s"), { "label": headerFont(translate("Cost:")), "costs": costs }); } return ""; } function getRequirementsTooltip(enabled, requirements, civ) { if (enabled) return ""; // Simple requirements (one tech) can be translated on the fly. - if ("Techs" in requirements && !requirements.Techs.includes(" ")) + if ("Techs" in requirements && !requirements.Techs._string.includes(" ")) return objectionFont(sprintf(translate("Requires %(technology)s"), { - "technology": getEntityNames(GetTechnologyData(requirements.Techs, civ)) + "technology": getEntityNames(GetTechnologyData(requirements.Techs._string, civ)) })); return objectionFont(translate(requirements.Tooltip)); } /** * Returns the population bonus information to display in the specified entity's construction button tooltip. */ function getPopulationBonusTooltip(template) { if (!template.population || !template.population.bonus) return ""; return sprintf(translate("%(label)s %(bonus)s"), { "label": headerFont(translate("Population Bonus:")), "bonus": template.population.bonus }); } /** * Returns a message with the amount of each resource needed to create an entity. */ function getNeededResourcesTooltip(resources) { if (!resources) return ""; let formatted = []; for (let resource in resources) formatted.push(sprintf(translate("%(component)s %(cost)s"), { "component": '[font="sans-12"]' + resourceIcon(resource) + '[/font]', "cost": Math.ceil(resources[resource]) })); return objectionFont(translate("Insufficient resources:")) + " " + formatted.join(" "); } function getSpeedTooltip(template) { if (!template.speed) return ""; const walk = template.speed.walk.toFixed(1); const run = template.speed.run.toFixed(1); if (walk == 0 && run == 0) return ""; const acceleration = template.speed.acceleration.toFixed(1); return sprintf(translate("%(label)s %(speeds)s"), { "label": headerFont(translate("Speed:")), "speeds": sprintf(translate("%(speed)s %(movementType)s"), { "speed": walk, "movementType": unitFont(translate("Walk")) }) + commaFont(translate(", ")) + sprintf(translate("%(speed)s %(movementType)s"), { "speed": run, "movementType": unitFont(translate("Run")) }) + commaFont(translate(", ")) + sprintf(translate("%(speed)s %(movementType)s"), { "speed": acceleration, "movementType": unitFont(translate("Acceleration")) }) }); } function getHealerTooltip(template) { if (!template.heal) return ""; let health = +(template.heal.health.toFixed(1)); let range = +(template.heal.range.toFixed(0)); let interval = +((template.heal.interval / 1000).toFixed(1)); return [ sprintf(translatePlural("%(label)s %(val)s %(unit)s", "%(label)s %(val)s %(unit)s", health), { "label": headerFont(translate("Heal:")), "val": health, "unit": unitFont(translatePlural("Health", "Health", health)) }), sprintf(translatePlural("%(label)s %(val)s %(unit)s", "%(label)s %(val)s %(unit)s", range), { "label": headerFont(translate("Range:")), "val": range, "unit": unitFont(translatePlural("meter", "meters", range)) }), sprintf(translatePlural("%(label)s %(val)s %(unit)s", "%(label)s %(val)s %(unit)s", interval), { "label": headerFont(translate("Interval:")), "val": interval, "unit": unitFont(translatePlural("second", "seconds", interval)) }) ].join(translate(", ")); } function getAurasTooltip(template) { let auras = template.auras || template.wallSet && GetTemplateData(template.wallSet.templates.long).auras; if (!auras) return ""; let tooltips = []; for (let auraID in auras) { let tooltip = sprintf(translate("%(auralabel)s %(aurainfo)s"), { "auralabel": headerFont(sprintf(translate("%(auraname)s:"), { "auraname": getEntityNames(auras[auraID]) })), "aurainfo": bodyFont(translate(auras[auraID].description)) }); let radius = +auras[auraID].radius; if (radius) tooltip += " " + sprintf(translatePlural("%(label)s %(val)s %(unit)s", "%(label)s %(val)s %(unit)s", radius), { "label": translateWithContext("aura", "Range:"), "val": radius, "unit": unitFont(translatePlural("meter", "meters", radius)) }); tooltips.push(tooltip); } return tooltips.join("\n"); } function getEntityNames(template) { if (!template.name.specific) return template.name.generic; if (template.name.specific == template.name.generic) return template.name.specific; let primaryName = g_SpecificNamesPrimary ? template.name.specific : template.name.generic; let secondaryName; if (g_ShowSecondaryNames) secondaryName = g_SpecificNamesPrimary ? template.name.generic : template.name.specific; if (secondaryName) return sprintf(translate("%(primaryName)s (%(secondaryName)s)"), { "primaryName": primaryName, "secondaryName": secondaryName }); return sprintf(translate("%(primaryName)s"), { "primaryName": primaryName }); } function getEntityNamesFormatted(template) { if (!template.name.specific) return setStringTags(template.name.generic, g_TooltipTextFormats.namePrimaryBig); let primaryName = g_SpecificNamesPrimary ? template.name.specific : template.name.generic; let secondaryName; if (g_ShowSecondaryNames) secondaryName = g_SpecificNamesPrimary ? template.name.generic : template.name.specific; if (!secondaryName || primaryName == secondaryName) return sprintf(translate("%(primaryName)s"), { "primaryName": setStringTags(primaryName[0], g_TooltipTextFormats.namePrimaryBig) + setStringTags(primaryName.slice(1).toUpperCase(), g_TooltipTextFormats.namePrimarySmall) }); // Translation: Example: "Epibátēs Athēnaîos [font="sans-bold-16"](Athenian Marine)[/font]" return sprintf(translate("%(primaryName)s (%(secondaryName)s)"), { "primaryName": setStringTags(primaryName[0], g_TooltipTextFormats.namePrimaryBig) + setStringTags(primaryName.slice(1).toUpperCase(), g_TooltipTextFormats.namePrimarySmall), "secondaryName": setStringTags(secondaryName, g_TooltipTextFormats.nameSecondary) }); } function getEntityPrimaryNameFormatted(template) { let primaryName = g_SpecificNamesPrimary ? template.name.specific : template.name.generic; if (!primaryName) return setStringTags(g_SpecificNamesPrimary ? template.name.generic : template.name.specific, g_TooltipTextFormats.namePrimaryBig); return setStringTags(primaryName[0], g_TooltipTextFormats.namePrimaryBig) + setStringTags(primaryName.slice(1).toUpperCase(), g_TooltipTextFormats.namePrimarySmall); } function getVisibleEntityClassesFormatted(template) { if (!template.visibleIdentityClasses || !template.visibleIdentityClasses.length) return ""; return headerFont(translate("Classes:")) + ' ' + bodyFont(template.visibleIdentityClasses.map(c => translate(c)).join(translate(", "))); } function getLootTooltip(template) { if (!template.loot && !template.resourceCarrying) return ""; let resourcesCarried = []; if (template.resourceCarrying) resourcesCarried = calculateCarriedResources( template.resourceCarrying, template.trader && template.trader.goods ); let lootLabels = []; for (let type of g_ResourceData.GetCodes().concat(["xp"])) { let loot = (template.loot && template.loot[type] || 0) + (resourcesCarried[type] || 0); if (!loot) continue; // Translation: %(component) will be the icon for the loot type and %(loot) will be the value. lootLabels.push(sprintf(translate("%(component)s %(loot)s"), { "component": resourceIcon(type), "loot": loot })); } if (!lootLabels.length) return ""; return sprintf(translate("%(label)s %(details)s"), { "label": headerFont(translate("Loot:")), "details": lootLabels.join(" ") }); } function getResourceDropsiteTooltip(template) { if (!template || !template.resourceDropsite || !template.resourceDropsite.types) return ""; return sprintf(translate("%(label)s %(icons)s"), { "label": headerFont(translate("Dropsite for:")), "icons": template.resourceDropsite.types.map(type => resourceIcon(type)).join(" ") }); } function showTemplateViewerOnRightClickTooltip() { // Translation: Appears in a tooltip to indicate that right-clicking the corresponding GUI element will open the Template Details GUI page. return translate("Right-click to view more information."); } function showTemplateViewerOnClickTooltip() { // Translation: Appears in a tooltip to indicate that clicking the corresponding GUI element will open the Template Details GUI page. return translate("Click to view more information."); } /** * @param {number} number - A number to shorten using SI prefix. */ function abbreviateLargeNumbers(number) { if (number >= 1e6) return Math.floor(number / 1e6) + translateWithContext("One letter abbreviation for million", 'M'); if (number >= 1e5) return Math.floor(number / 1e3) + translateWithContext("One letter abbreviation for thousand", 'k'); if (number >= 1e4) return (number / 1e3).toFixed(1).replace(/\.0$/, '') + translateWithContext("One letter abbreviation for thousand", 'k'); return number; } Index: ps/trunk/binaries/data/mods/public/gui/reference/common/TemplateParser.js =================================================================== --- ps/trunk/binaries/data/mods/public/gui/reference/common/TemplateParser.js (revision 27504) +++ ps/trunk/binaries/data/mods/public/gui/reference/common/TemplateParser.js (revision 27505) @@ -1,407 +1,419 @@ /** * This class parses and stores parsed template data. */ class TemplateParser { constructor(TemplateLoader) { this.TemplateLoader = TemplateLoader; /** * Parsed Data Stores */ this.auras = {}; this.entities = {}; this.techs = {}; this.phases = {}; this.modifiers = {}; this.players = {}; this.phaseList = []; } getAura(auraName) { if (auraName in this.auras) return this.auras[auraName]; if (!AuraTemplateExists(auraName)) return null; let template = this.TemplateLoader.loadAuraTemplate(auraName); let parsed = GetAuraDataHelper(template); if (template.civ) parsed.civ = template.civ; let affectedPlayers = template.affectedPlayers || this.AuraAffectedPlayerDefault; parsed.affectsTeam = this.AuraTeamIndicators.some(indicator => affectedPlayers.includes(indicator)); parsed.affectsSelf = this.AuraSelfIndicators.some(indicator => affectedPlayers.includes(indicator)); this.auras[auraName] = parsed; return this.auras[auraName]; } /** * Load and parse a structure, unit, resource, etc from its entity template file. * * @param {string} templateName * @param {string} civCode * @return {(object|null)} Sanitized object about the requested template or null if entity template doesn't exist. */ getEntity(templateName, civCode) { if (!(civCode in this.entities)) this.entities[civCode] = {}; else if (templateName in this.entities[civCode]) return this.entities[civCode][templateName]; if (!Engine.TemplateExists(templateName)) return null; let template = this.TemplateLoader.loadEntityTemplate(templateName, civCode); const parsed = GetTemplateDataHelper(template, null, this.TemplateLoader.auraData, g_ResourceData, this.modifiers[civCode] || {}); parsed.name.internal = templateName; parsed.history = template.Identity.History; parsed.production = this.TemplateLoader.deriveProduction(template, civCode); if (template.Builder) parsed.builder = this.TemplateLoader.deriveBuildQueue(template, civCode); // Set the minimum phase that this entity is available. // For gaia objects, this is meaningless. // Complex requirements are too difficult to process for now, so assume the first phase. if (!parsed.requirements?.Techs) parsed.phase = this.phaseList[0]; else { let highestPhaseIndex = 0; - for (const tech of parsed.requirements.Techs.split(" ")) + for (const tech of parsed.requirements.Techs._string.split(" ")) { if (tech[0] === "!") continue; const phaseIndex = this.phaseList.indexOf( this.TemplateLoader.isPhaseTech(tech) ? this.getActualPhase(tech) : this.getPhaseOfTechnology(tech, civCode)); if (phaseIndex > highestPhaseIndex) highestPhaseIndex = phaseIndex; } parsed.phase = this.phaseList[highestPhaseIndex]; } if (template.Identity.Rank) parsed.promotion = { "current_rank": template.Identity.Rank, "entity": template.Promotion && template.Promotion.Entity }; if (template.ResourceSupply) parsed.supply = { "type": template.ResourceSupply.Type.split("."), "amount": template.ResourceSupply.Max, }; if (parsed.upgrades) parsed.upgrades = this.getActualUpgradeData(parsed.upgrades, civCode); if (parsed.wallSet) { parsed.wallset = {}; if (!parsed.upgrades) parsed.upgrades = []; // Note: An assumption is made here that wall segments all have the same resistance and auras let struct = this.getEntity(parsed.wallSet.templates.long, civCode); parsed.resistance = struct.resistance; parsed.auras = struct.auras; // For technology cost multiplier, we need to use the tower struct = this.getEntity(parsed.wallSet.templates.tower, civCode); parsed.techCostMultiplier = struct.techCostMultiplier; let health; for (let wSegm in parsed.wallSet.templates) { if (wSegm == "fort" || wSegm == "curves") continue; let wPart = this.getEntity(parsed.wallSet.templates[wSegm], civCode); parsed.wallset[wSegm] = wPart; for (let research of wPart.production.techs) parsed.production.techs.push(research); if (wPart.upgrades) Array.prototype.push.apply(parsed.upgrades, wPart.upgrades); if (["gate", "tower"].indexOf(wSegm) != -1) continue; if (!health) { health = { "min": wPart.health, "max": wPart.health }; continue; } health.min = Math.min(health.min, wPart.health); health.max = Math.max(health.max, wPart.health); } if (parsed.wallSet.templates.curves) for (let curve of parsed.wallSet.templates.curves) { let wPart = this.getEntity(curve, civCode); health.min = Math.min(health.min, wPart.health); health.max = Math.max(health.max, wPart.health); } if (health.min == health.max) parsed.health = health.min; else parsed.health = sprintf(translate("%(health_min)s to %(health_max)s"), { "health_min": health.min, "health_max": health.max }); } this.entities[civCode][templateName] = parsed; return parsed; } /** * Load and parse technology from json template. * * @param {string} technologyName * @param {string} civCode * @return {Object} Sanitized data about the requested technology. */ getTechnology(technologyName, civCode) { if (!TechnologyTemplateExists(technologyName)) return null; if (this.TemplateLoader.isPhaseTech(technologyName) && technologyName in this.phases) return this.phases[technologyName]; if (!(civCode in this.techs)) this.techs[civCode] = {}; else if (technologyName in this.techs[civCode]) return this.techs[civCode][technologyName]; let template = this.TemplateLoader.loadTechnologyTemplate(technologyName); const tech = GetTechnologyDataHelper(template, civCode, g_ResourceData, this.modifiers[civCode] || {}); tech.name.internal = technologyName; if (template.pair !== undefined) { tech.pair = template.pair; tech.reqs = this.mergeRequirements(tech.reqs, this.TemplateLoader.loadTechnologyPairTemplate(template.pair).reqs); } if (this.TemplateLoader.isPhaseTech(technologyName)) { tech.actualPhase = technologyName; if (tech.replaces !== undefined) tech.actualPhase = tech.replaces[0]; this.phases[technologyName] = tech; } else this.techs[civCode][technologyName] = tech; return tech; } /** * @param {string} phaseCode * @param {string} civCode * @return {Object} Sanitized object containing phase data */ getPhase(phaseCode, civCode) { return this.getTechnology(phaseCode, civCode); } /** * Load and parse the relevant player_{civ}.xml template. */ getPlayer(civCode) { if (civCode in this.players) return this.players[civCode]; let template = this.TemplateLoader.loadPlayerTemplate(civCode); let parsed = { "civbonuses": [], "teambonuses": [], }; if (template.Auras) for (let auraTemplateName of template.Auras._string.split(/\s+/)) if (AuraTemplateExists(auraTemplateName)) if (this.getAura(auraTemplateName).affectsTeam) parsed.teambonuses.push(auraTemplateName); else parsed.civbonuses.push(auraTemplateName); this.players[civCode] = parsed; return parsed; } /** * Provided with an array containing basic information about possible * upgrades, such as that generated by globalscript's GetTemplateDataHelper, * this function loads the actual template data of the upgrades, overwrites * certain values within, then passes an array containing the template data * back to caller. */ getActualUpgradeData(upgradesInfo, civCode) { let newUpgrades = []; for (let upgrade of upgradesInfo) { upgrade.entity = upgrade.entity.replace(/\{(civ|native)\}/g, civCode); const data = GetTemplateDataHelper(this.TemplateLoader.loadEntityTemplate(upgrade.entity, civCode), null, this.TemplateLoader.auraData, g_ResourceData, this.modifiers[civCode] || {}); data.name.internal = upgrade.entity; data.cost = upgrade.cost; data.icon = upgrade.icon || data.icon; data.tooltip = upgrade.tooltip || data.tooltip; data.requirements = upgrade.requirements || data.requirements; - if (!data.requirements) + if (!data.requirements?.Techs) data.phase = this.phaseList[0]; - else if (this.TemplateLoader.isPhaseTech(data.requirements.Techs)) - data.phase = this.getActualPhase(data.requirements.Techs); else - data.phase = this.getPhaseOfTechnology(data.requirements.Techs, civCode); + { + let highestPhaseIndex = 0; + for (const tech of data.requirements.Techs._string.split(" ")) + { + if (tech[0] === "!") + continue; + + const phaseIndex = this.phaseList.indexOf( + this.TemplateLoader.isPhaseTech(tech) ? this.getActualPhase(tech) : + this.getPhaseOfTechnology(tech, civCode)); + if (phaseIndex > highestPhaseIndex) + highestPhaseIndex = phaseIndex; + } + data.phase = this.phaseList[highestPhaseIndex]; + } newUpgrades.push(data); } return newUpgrades; } /** * Determines and returns the phase in which a given technology can be * first researched. Works recursively through the given tech's * pre-requisite and superseded techs if necessary. * * @param {string} techName - The Technology's name * @param {string} civCode * @return The name of the phase the technology belongs to, or false if * the current civ can't research this tech */ getPhaseOfTechnology(techName, civCode) { let phaseIdx = -1; if (basename(techName).startsWith("phase")) { if (!this.phases[techName].reqs) return false; phaseIdx = this.phaseList.indexOf(this.getActualPhase(techName)); if (phaseIdx > 0) return this.phaseList[phaseIdx - 1]; } let techReqs = this.getTechnology(techName, civCode).reqs; if (!techReqs) return false; for (let option of techReqs) if (option.techs) for (let tech of option.techs) { if (basename(tech).startsWith("phase")) return tech; if (basename(tech).startsWith("pair")) continue; phaseIdx = Math.max(phaseIdx, this.phaseList.indexOf(this.getPhaseOfTechnology(tech, civCode))); } return this.phaseList[phaseIdx] || false; } /** * Returns the actual phase a certain phase tech represents or stands in for. * * For example, passing `phase_city_athen` would result in `phase_city`. * * @param {string} phaseName * @return {string} */ getActualPhase(phaseName) { if (this.phases[phaseName]) return this.phases[phaseName].actualPhase; warn("Unrecognized phase (" + phaseName + ")"); return this.phaseList[0]; } getModifiers(civCode) { return this.modifiers[civCode]; } deriveModifications(civCode) { const player = this.getPlayer(civCode); const auraList = clone(player.civbonuses); for (const bonusname of player.teambonuses) if (this.getAura(bonusname).affectsSelf) auraList.push(bonusname); this.modifiers[civCode] = this.TemplateLoader.deriveModifications(civCode, auraList); } derivePhaseList(technologyList, civCode) { // Load all of a civ's specific phase technologies for (let techcode of technologyList) if (this.TemplateLoader.isPhaseTech(techcode)) this.getTechnology(techcode, civCode); this.phaseList = UnravelPhases(this.phases); // Make sure all required generic phases are loaded and parsed for (let phasecode of this.phaseList) this.getTechnology(phasecode, civCode); } mergeRequirements(reqsA, reqsB) { if (!reqsA || !reqsB) return false; let finalReqs = clone(reqsA); for (let option of reqsB) for (let type in option) for (let opt in finalReqs) { if (!finalReqs[opt][type]) finalReqs[opt][type] = []; Array.prototype.push.apply(finalReqs[opt][type], option[type]); } return finalReqs; } } // Default affected player token list to use if an aura doesn't explicitly give one. // Keep in sync with simulation/components/Auras.js TemplateParser.prototype.AuraAffectedPlayerDefault = ["Player"]; // List of tokens that, if found in an aura's "affectedPlayers" attribute, indicate // that the aura applies to team members. TemplateParser.prototype.AuraTeamIndicators = ["MutualAlly", "ExclusiveMutualAlly"]; // List of tokens that, if found in an aura's "affectedPlayers" attribute, indicate // that the aura applies to the aura's owning civ. TemplateParser.prototype.AuraSelfIndicators = ["Player", "Ally", "MutualAlly"]; Index: ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_military_embassy.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_military_embassy.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_military_embassy.xml (revision 27505) @@ -1,58 +1,58 @@ Embassy 150 12.0 6 Support Infantry Cavalry 2000 decay|rubble/rubble_stone_3x3 Embassy template_structure_military_embassy Town Embassy - phase_town + phase_town 30 interface/complete/building/complete_gymnasium.xml 25 0.8 24 structures/fndn_4x4.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_military_range.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_military_range.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_military_range.xml (revision 27505) @@ -1,63 +1,63 @@ 120 200 12.0 10 Infantry 2000 decay|rubble/rubble_stone_5x5 Practice Range template_structure_military_range Train Ranged Infantry and research technologies. Village Range structures/range.png - phase_village + phase_village 40 interface/complete/building/complete_range.xml 0.8 units/{civ}/infantry_javelineer_b units/{civ}/infantry_slinger_b units/{civ}/infantry_archer_b units/{civ}/infantry_crossbowman_b units/{civ}/champion_infantry_javelineer units/{civ}/champion_infantry_slinger units/{civ}/champion_infantry_archer units/{civ}/champion_infantry_crossbowman 32 structures/fndn_7x7.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_special.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_special.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_special.xml (revision 27505) @@ -1,40 +1,40 @@ 8.0 5 0.1 Unit Support Infantry Cavalry 0 2 decay|rubble/rubble_stone_6x6 Special Structure City - phase_city + phase_city 20 30 3 structures/fndn_5x5.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_defensive_tower_sentry.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_defensive_tower_sentry.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_defensive_tower_sentry.xml (revision 27505) @@ -1,73 +1,73 @@ 0 9 0 4 40 100 9.0 3 400 Sentry Tower template_structure_defensive_tower_sentry Garrison Infantry for additional arrows. Needs the “Murder Holes” technology to protect its foot. SentryTower structures/sentry_tower.png - phase_village + phase_village 20 tower_watch false 16 30000 structures/{civ}/defense_tower Reinforce with stone and upgrade to a defense tower. 50 100 upgrading - phase_town + phase_town Index: ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_defensive_wall.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_defensive_wall.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_defensive_wall.xml (revision 27505) @@ -1,38 +1,38 @@ land-shore Wall 8.0 Wall template_structure_defensive_wall Wall off your town for a stout defense. Wall structures/wall.png - phase_town + phase_town 4.5 interface/complete/building/complete_wall.xml false 20 65535 Index: ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_economic_market.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_economic_market.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_economic_market.xml (revision 27505) @@ -1,78 +1,78 @@ Trader+!Ship -1 -1 100 150 300 8.0 1500 decay|rubble/rubble_stone_5x5 Market template_structure_economic_market Barter resources. Establish trade routes. Train Traders and research trade and barter technologies. Barter Trade Town Market structures/market.png - phase_town + phase_town 60 land 0.2 trader_health trade_gain_01 trade_gain_02 trade_commercial_treaty interface/complete/building/complete_market.xml interface/alarm/alarm_alert_0.xml interface/alarm/alarm_alert_1.xml false 40 30000 0.7 units/{civ}/support_trader 32 structures/fndn_8x8.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_military_arsenal.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_military_arsenal.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_military_arsenal.xml (revision 27505) @@ -1,78 +1,78 @@ structures/arsenal_repair 180 300 12.0 5 Siege 2000 decay|rubble/rubble_stone_6x6 Arsenal template_structure_military_arsenal Train Champion Infantry Crossbowmen, construct Siege Engines, and research Siege Engine technologies. City Arsenal structures/siege_workshop.png - phase_city + phase_city 60 siege_attack siege_cost_time siege_health siege_pack_unpack siege_bolt_accuracy interface/complete/building/complete_barracks.xml 38 0.7 units/{civ}/champion_infantry_crossbowman units/{civ}/siege_scorpio_packed units/{civ}/siege_polybolos_packed units/{civ}/siege_oxybeles_packed units/{civ}/siege_lithobolos_packed units/{civ}/siege_ballista_packed units/{civ}/siege_ram units/{civ}/siege_tower 40 structures/fndn_8x8.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_military_elephant_stable.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_military_elephant_stable.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_military_elephant_stable.xml (revision 27505) @@ -1,66 +1,66 @@ structures/xp_trickle 180 200 200 8.0 5 Elephant 3000 decay|rubble/rubble_stone_6x6 Elephant Stable template_structure_military_elephant_stable Train Elephants and research Elephant technologies. City ElephantStable structures/stable_elephant.png - phase_city + phase_city 40 40 interface/complete/building/complete_elephant_stable.xml 38 0.7 units/{civ}/support_elephant units/{civ}/elephant_archer_b units/{civ}/champion_elephant 40 structures/fndn_9x8.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_military_fortress.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_military_fortress.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_military_fortress.xml (revision 27505) @@ -1,114 +1,114 @@ Bow 10 60 1200 2000 100 1.5 50 false Human outline_border.png outline_border_mask.png 0.175 Fortress Fortress 80 4 1 Soldier 8 10.0 450 300 600 8.0 20 0.075 Support Infantry Cavalry Siege 6 5200 decay|rubble/rubble_stone_6x6 Fortress template_structure_military_fortress Garrison Soldiers for additional arrows. GarrisonFortress Defensive Fortress structures/fortress.png - phase_city + phase_city 60 120 attack_soldiers_will art_of_war poison_arrows poison_blades interface/complete/building/complete_fortress.xml attack/weapon/bow_attack.xml attack/impact/arrow_impact.xml 2 80 0.8 90 structures/fndn_8x8.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_resource_corral.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_resource_corral.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_resource_corral.xml (revision 27505) @@ -1,86 +1,86 @@ 50 100 5.0 8 0.5 Animal Animal 1 4 500 decay|rubble/rubble_stone_3x3 Corral template_structure_resource_corral Raise Domestic Animals for food. Garrison animals to gain a trickle of food. Economic Village Corral structures/corral.png - phase_village + phase_village 0 5000 20 gather_animals_stockbreeding 20 interface/complete/building/complete_corral.xml false 20 30000 0.7 gaia/fauna_goat_trainable gaia/fauna_sheep_trainable gaia/fauna_pig_trainable gaia/fauna_cattle_cow_trainable 20 structures/fndn_3x3.xml Index: ps/trunk/binaries/data/mods/public/simulation/helpers/Requirements.js =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/helpers/Requirements.js (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/helpers/Requirements.js (revision 27505) @@ -1,164 +1,167 @@ function RequirementsHelper() {} RequirementsHelper.prototype.DEFAULT_RECURSION_DEPTH = 1; RequirementsHelper.prototype.EntityRequirementsSchema = "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + ""; RequirementsHelper.prototype.TechnologyRequirementsSchema = "" + + "" + + "tokens" + + "" + "" + ""; /** * @param {number} recursionDepth - How deep we recurse. * @return {string} - A RelaxRNG schema for requirements. */ RequirementsHelper.prototype.RequirementsSchema = function(recursionDepth) { return "" + "" + this.ChoicesSchema(--recursionDepth) + ""; }; /** * @param {number} recursionDepth - How deep we recurse. * @return {string} - A RelaxRNG schema for chosing requirements. */ RequirementsHelper.prototype.ChoicesSchema = function(recursionDepth) { const allAnySchema = recursionDepth > 0 ? "" + "" + this.RequirementsSchema(recursionDepth) + "" + "" + this.RequirementsSchema(recursionDepth) + "" : ""; return "" + "" + allAnySchema + this.EntityRequirementsSchema + this.TechnologyRequirementsSchema + ""; }; /** * @param {number} recursionDepth - How deeply recursive we build the schema. * @return {string} - A RelaxRNG schema for requirements. */ RequirementsHelper.prototype.BuildSchema = function(recursionDepth = this.DEFAULT_RECURSION_DEPTH) { return "" + "" + "" + this.ChoicesSchema(recursionDepth) + "" + "" + "" + "" + "" + "" + ""; }; /** * @param {Object} template - The requirements template as defined above. * @param {number} playerID - * @return {boolean} - */ RequirementsHelper.prototype.AreRequirementsMet = function(template, playerID) { if (!template || !Object.keys(template).length) return true; const cmpTechManager = QueryPlayerIDInterface(playerID, IID_TechnologyManager); return cmpTechManager && this.AllRequirementsMet(template, cmpTechManager); }; /** * @param {Object} template - The requirements template for "all". * @param {component} cmpTechManager - * @return {boolean} - */ RequirementsHelper.prototype.AllRequirementsMet = function(template, cmpTechManager) { for (const requirementType in template) { const requirement = template[requirementType]; if (requirementType === "All" && !this.AllRequirementsMet(requirement, cmpTechManager)) return false; if (requirementType === "Any" && !this.AnyRequirementsMet(requirement, cmpTechManager)) return false; if (requirementType === "Entities") { for (const className in requirement) { const entReq = requirement[className]; if ("Count" in entReq && (!(className in cmpTechManager.classCounts) || cmpTechManager.classCounts[className] < entReq.Count)) return false; if ("Variants" in entReq && (!(className in cmpTechManager.typeCountsByClass) || Object.keys(cmpTechManager.typeCountsByClass[className]).length < entReq.Variants)) return false; } } - if (requirementType === "Techs") - for (const tech of requirement.split(" ")) + if (requirementType === "Techs" && requirement._string) + for (const tech of requirement._string.split(" ")) if (tech[0] === "!" ? cmpTechManager.IsTechnologyResearched(tech.substring(1)) : !cmpTechManager.IsTechnologyResearched(tech)) return false; } return true; }; /** * @param {Object} template - The requirements template for "any". * @param {component} cmpTechManager - * @return {boolean} - */ RequirementsHelper.prototype.AnyRequirementsMet = function(template, cmpTechManager) { for (const requirementType in template) { const requirement = template[requirementType]; if (requirementType === "All" && this.AllRequirementsMet(requirement, cmpTechManager)) return true; if (requirementType === "Any" && this.AnyRequirementsMet(requirement, cmpTechManager)) return true; if (requirementType === "Entities") { for (const className in requirement) { const entReq = requirement[className]; if ("Count" in entReq && className in cmpTechManager.classCounts && cmpTechManager.classCounts[className] >= entReq.Count) return true; if ("Variants" in entReq && className in cmpTechManager.typeCountsByClass && Object.keys(cmpTechManager.typeCountsByClass[className]).length >= entReq.Variants) return true; } } - if (requirementType === "Techs") - for (const tech of requirement.split(" ")) + if (requirementType === "Techs" && requirement._string) + for (const tech of requirement._string.split(" ")) if (tech[0] === "!" ? !cmpTechManager.IsTechnologyResearched(tech.substring(1)) : cmpTechManager.IsTechnologyResearched(tech)) return true; } return false; }; Engine.RegisterGlobal("RequirementsHelper", new RequirementsHelper()); Index: ps/trunk/binaries/data/mods/public/simulation/helpers/tests/test_Requirements.js =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/helpers/tests/test_Requirements.js (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/helpers/tests/test_Requirements.js (revision 27505) @@ -1,718 +1,718 @@ Engine.LoadComponentScript("interfaces/PlayerManager.js"); Engine.LoadComponentScript("interfaces/TechnologyManager.js"); Engine.LoadHelperScript("Player.js"); Engine.LoadHelperScript("Requirements.js"); const playerID = 1; const playerEnt = 11; AddMock(SYSTEM_ENTITY, IID_PlayerManager, { "GetPlayerByID": () => playerEnt }); // First test no requirements. let template = { }; const met = () => TS_ASSERT(RequirementsHelper.AreRequirementsMet(template, playerID)); const notMet = () => TS_ASSERT(!RequirementsHelper.AreRequirementsMet(template, playerID)); met(); // Simple requirements are assumed to be additive. template = { - "Techs": "phase_city" + "Techs": { "_string": "phase_city" } }; AddMock(playerEnt, IID_TechnologyManager, { "IsTechnologyResearched": (tech) => false }); notMet(); AddMock(playerEnt, IID_TechnologyManager, { "IsTechnologyResearched": (tech) => tech === "phase_town" }); notMet(); AddMock(playerEnt, IID_TechnologyManager, { "IsTechnologyResearched": (tech) => tech === "phase_town" || tech === "phase_city" }); met(); template = { - "Techs": "cartography phase_city" + "Techs": { "_string": "cartography phase_city" } }; AddMock(playerEnt, IID_TechnologyManager, { "IsTechnologyResearched": (tech) => false }); notMet(); AddMock(playerEnt, IID_TechnologyManager, { "IsTechnologyResearched": (tech) => tech === "phase_town" }); notMet(); AddMock(playerEnt, IID_TechnologyManager, { "IsTechnologyResearched": (tech) => tech === "phase_town" || tech === "phase_city" }); notMet(); AddMock(playerEnt, IID_TechnologyManager, { "IsTechnologyResearched": (tech) => tech === "cartography" || tech === "phase_town" }); notMet(); AddMock(playerEnt, IID_TechnologyManager, { "IsTechnologyResearched": (tech) => tech === "cartography" || tech === "phase_city" }); met(); // Additive requirements (all should to be met). // Entity requirements. template = { "All": { "Entities": { "class_1": { "Count": 1 } } } }; AddMock(playerEnt, IID_TechnologyManager, { "classCounts": {}, "typeCountsByClass": {} }); notMet(); AddMock(playerEnt, IID_TechnologyManager, { "classCounts": { "class_1": 0 }, "typeCountsByClass": {} }); notMet(); AddMock(playerEnt, IID_TechnologyManager, { "classCounts": { "class_2": 1 }, "typeCountsByClass": {} }); notMet(); AddMock(playerEnt, IID_TechnologyManager, { "classCounts": { "class_1": 1 }, "typeCountsByClass": {} }); met(); AddMock(playerEnt, IID_TechnologyManager, { "classCounts": { "class_1": 1 }, "typeCountsByClass": { "class_1": { "template_1": 1 } } }); met(); template = { "All": { "Entities": { "class_1": { "Variants": 2 } } } }; AddMock(playerEnt, IID_TechnologyManager, { "classCounts": { "class_1": 2 }, "typeCountsByClass": { "class_1": { "template_1": 2 } } }); notMet(); AddMock(playerEnt, IID_TechnologyManager, { "classCounts": { "class_1": 2 }, "typeCountsByClass": { "class_1": { "template_1": 1, "template_2": 1 } } }); met(); AddMock(playerEnt, IID_TechnologyManager, { "classCounts": { "class_1": 1 }, "typeCountsByClass": { "class_1": { "template_1": 1 } } }); notMet(); template = { "All": { "Entities": { "class_1": { "Count": 1, "Variants": 2 } } } }; AddMock(playerEnt, IID_TechnologyManager, { "classCounts": { "class_1": 1 }, "typeCountsByClass": { "class_1": { "template_1": 1 } } }); notMet(); AddMock(playerEnt, IID_TechnologyManager, { "classCounts": { "class_1": 2 }, "typeCountsByClass": { "class_1": { "template_1": 1, "template_2": 1 } } }); met(); template = { "All": { "Entities": { "class_1": { "Count": 3, "Variants": 2 } } } }; AddMock(playerEnt, IID_TechnologyManager, { "classCounts": { "class_1": 2 }, "typeCountsByClass": { "class_1": { "template_1": 1, "template_2": 1 } } }); notMet(); AddMock(playerEnt, IID_TechnologyManager, { "classCounts": { "class_1": 3 }, "typeCountsByClass": { "class_1": { "template_1": 2, "template_2": 1 } } }); met(); // Technology requirements. template = { "All": { - "Techs": "phase_town" + "Techs": { "_string": "phase_town" } } }; AddMock(playerEnt, IID_TechnologyManager, { "IsTechnologyResearched": (tech) => false }); notMet(); AddMock(playerEnt, IID_TechnologyManager, { "IsTechnologyResearched": (tech) => tech === "phase_town" }); met(); template = { "All": { - "Techs": "phase_city" + "Techs": { "_string": "phase_city" } } }; notMet(); template = { "All": { - "Techs": "phase_town phase_city" + "Techs": { "_string": "phase_town phase_city" } } }; notMet(); AddMock(playerEnt, IID_TechnologyManager, { "IsTechnologyResearched": (tech) => tech === "phase_town" || tech === "phase_city" }); met(); template = { "All": { - "Techs": "!phase_city" + "Techs": { "_string": "!phase_city" } } }; notMet(); template = { "All": { - "Techs": "!phase_town phase_city" + "Techs": { "_string": "!phase_town phase_city"} } }; notMet(); AddMock(playerEnt, IID_TechnologyManager, { "IsTechnologyResearched": (tech) => tech === "phase_city" }); met(); // Combination of Entity and Technology requirements. template = { "All": { "Entities": { "class_1": { "Count": 3, "Variants": 2 } }, - "Techs": "phase_town" + "Techs": { "_string": "phase_town" } } }; AddMock(playerEnt, IID_TechnologyManager, { "classCounts": { "class_1": 3 }, "IsTechnologyResearched": (tech) => false, "typeCountsByClass": { "class_1": { "template_1": 2, "template_2": 1 } } }); notMet(); AddMock(playerEnt, IID_TechnologyManager, { "classCounts": { "class_1": 3 }, "IsTechnologyResearched": (tech) => tech === "phase_town", "typeCountsByClass": { "class_1": { "template_1": 2, "template_2": 1 } } }); met(); AddMock(playerEnt, IID_TechnologyManager, { "classCounts": { "class_1": 3 }, "IsTechnologyResearched": (tech) => tech === "phase_city", "typeCountsByClass": { "class_1": { "template_1": 2, "template_2": 1 } } }); notMet(); // Choice requirements (at least one needs to be met). // Entity requirements. template = { "Any": { "Entities": { "class_1": { "Count": 1, } }, } }; AddMock(playerEnt, IID_TechnologyManager, { "classCounts": { "class_1": 0 } }); notMet(); AddMock(playerEnt, IID_TechnologyManager, { "classCounts": { "class_1": 1 } }); met(); template = { "Any": { "Entities": { "class_1": { "Count": 5, "Variants": 2 } }, } }; AddMock(playerEnt, IID_TechnologyManager, { "classCounts": { "class_1": 3 }, "typeCountsByClass": { "class_1": { "template_1": 3, } } }); notMet(); AddMock(playerEnt, IID_TechnologyManager, { "classCounts": { "class_1": 3 }, "typeCountsByClass": { "class_1": { "template_1": 2, "template_2": 1 } } }); met(); // Technology requirements. template = { "Any": { - "Techs": "phase_town" + "Techs": { "_string": "phase_town" } } }; AddMock(playerEnt, IID_TechnologyManager, { "IsTechnologyResearched": (tech) => tech === "phase_city" }); notMet(); AddMock(playerEnt, IID_TechnologyManager, { "IsTechnologyResearched": (tech) => tech === "phase_town" }); met(); template = { "Any": { - "Techs": "phase_town phase_city" + "Techs": { "_string": "phase_town phase_city" } } }; AddMock(playerEnt, IID_TechnologyManager, { "IsTechnologyResearched": (tech) => tech === "phase_city" }); met(); template = { "Any": { - "Techs": "!phase_town" + "Techs": { "_string": "!phase_town" } } }; AddMock(playerEnt, IID_TechnologyManager, { "IsTechnologyResearched": (tech) => tech === "phase_town" }); notMet(); AddMock(playerEnt, IID_TechnologyManager, { "IsTechnologyResearched": (tech) => tech === "phase_city" }); met(); template = { "Any": { - "Techs": "!phase_town phase_city" + "Techs": { "_string": "!phase_town phase_city" } } }; AddMock(playerEnt, IID_TechnologyManager, { "IsTechnologyResearched": (tech) => tech === "phase_town" || tech === "phase_city" }); met(); // Combinational requirements of entities and technologies. template = { "Any": { "Entities": { "class_1": { "Count": 3, "Variants": 2 } }, - "Techs": "!phase_town" + "Techs": { "_string": "!phase_town" } } }; AddMock(playerEnt, IID_TechnologyManager, { "classCounts": { "class_1": 3 }, "IsTechnologyResearched": (tech) => tech === "phase_town", "typeCountsByClass": { "class_1": { "template_1": 3 } } }); met(); // Nested requirements. template = { "All": { "All": { - "Techs": "!phase_town" + "Techs": { "_string": "!phase_town" } }, "Any": { "Entities": { "class_1": { "Count": 3, "Variants": 2 } }, - "Techs": "phase_city" + "Techs": { "_string": "phase_city" } } } }; AddMock(playerEnt, IID_TechnologyManager, { "classCounts": { "class_1": 3 }, "IsTechnologyResearched": (tech) => tech === "phase_town", "typeCountsByClass": { "class_1": { "template_1": 3 } } }); notMet(); AddMock(playerEnt, IID_TechnologyManager, { "classCounts": { "class_1": 3 }, "IsTechnologyResearched": (tech) => tech === "phase_town" || tech === "phase_city", "typeCountsByClass": { "class_1": { "template_1": 3 } } }); notMet(); AddMock(playerEnt, IID_TechnologyManager, { "classCounts": { "class_1": 2 }, "IsTechnologyResearched": (tech) => tech === "phase_city", "typeCountsByClass": { "class_1": { "template_1": 2 } } }); met(); AddMock(playerEnt, IID_TechnologyManager, { "classCounts": { "class_1": 2 }, "IsTechnologyResearched": (tech) => false, "typeCountsByClass": { "class_1": { "template_1": 1, "template_2": 1 } } }); met(); template = { "Any": { "All": { - "Techs": "!phase_town" + "Techs": { "_string": "!phase_town" } }, "Any": { "Entities": { "class_1": { "Count": 3, "Variants": 2 } }, - "Techs": "phase_city" + "Techs": { "_string": "phase_city" } } } }; AddMock(playerEnt, IID_TechnologyManager, { "classCounts": { "class_1": 2 }, "IsTechnologyResearched": (tech) => tech === "phase_town", "typeCountsByClass": { "class_1": { "template_1": 2 } } }); notMet(); AddMock(playerEnt, IID_TechnologyManager, { "classCounts": { "class_1": 3 }, "IsTechnologyResearched": (tech) => tech === "phase_town" || tech === "phase_city", "typeCountsByClass": { "class_1": { "template_1": 3 } } }); met(); AddMock(playerEnt, IID_TechnologyManager, { "classCounts": { "class_1": 2 }, "IsTechnologyResearched": (tech) => tech === "phase_city", "typeCountsByClass": { "class_1": { "template_1": 2 } } }); met(); AddMock(playerEnt, IID_TechnologyManager, { "classCounts": { "class_1": 2 }, "IsTechnologyResearched": (tech) => false, "typeCountsByClass": { "class_1": { "template_1": 1, "template_2": 1 } } }); met(); // Two levels deep nested. template = { "All": { "Any": { "All": { - "Techs": "cartography phase_imperial", + "Techs": { "_string": "cartography phase_imperial" } }, "Entities": { "class_1": { "Count": 3, "Variants": 2 } }, - "Techs": "phase_city" + "Techs": { "_string": "phase_city" } }, - "Techs": "!phase_town" + "Techs": { "_string": "!phase_town" } } }; AddMock(playerEnt, IID_TechnologyManager, { "classCounts": { "class_1": 2 }, "IsTechnologyResearched": (tech) => tech === "phase_town", "typeCountsByClass": { "class_1": { "template_1": 2 } } }); notMet(); AddMock(playerEnt, IID_TechnologyManager, { "classCounts": { "class_1": 2 }, "IsTechnologyResearched": (tech) => tech === "phase_city", "typeCountsByClass": { "class_1": { "template_1": 2 } } }); met(); AddMock(playerEnt, IID_TechnologyManager, { "classCounts": { "class_1": 2 }, "IsTechnologyResearched": (tech) => tech === "phase_imperial", "typeCountsByClass": { "class_1": { "template_1": 2 } } }); notMet(); AddMock(playerEnt, IID_TechnologyManager, { "classCounts": { "class_1": 2 }, "IsTechnologyResearched": (tech) => tech === "cartography" || tech === "phase_imperial", "typeCountsByClass": { "class_1": { "template_1": 2 } } }); met(); Index: ps/trunk/binaries/data/mods/public/simulation/templates/gaia/fauna_pig_trainable.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/gaia/fauna_pig_trainable.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/gaia/fauna_pig_trainable.xml (revision 27505) @@ -1,12 +1,12 @@ - phase_town + phase_town false Index: ps/trunk/binaries/data/mods/public/simulation/templates/special/spy.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/special/spy.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/special/spy.xml (revision 27505) @@ -1,28 +1,28 @@ 0 0 0 0 0 500 gaia Spy Spy technologies/spy_trader.png true - unlock_spies + unlock_spies false 15 0.25 Index: ps/trunk/binaries/data/mods/public/simulation/templates/structures/brit/crannog.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/structures/brit/crannog.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/structures/brit/crannog.xml (revision 27505) @@ -1,54 +1,54 @@ own ally neutral shore 8.0 brit Island Settlement Cranogion Build upon a shoreline in own, neutral, or allied territory. Acquire large tracts of territory. Territory root. Train Citizens, construct Ships, and research technologies. Garrison Soldiers for additional arrows. CivSpecific Naval structures/crannog.png - phase_town + phase_town true 0.0 ship -phase_town_{civ} -hellenistic_metropolis units/{civ}/infantry_spearman_b units/{civ}/infantry_slinger_b units/{civ}/cavalry_javelineer_b units/{civ}/ship_fishing units/{civ}/ship_merchant units/{civ}/ship_bireme units/{civ}/ship_trireme structures/britons/crannog.xml structures/fndn_8x8.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/structures/cart/wallset_short.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/structures/cart/wallset_short.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/structures/cart/wallset_short.xml (revision 27505) @@ -1,20 +1,20 @@ cart Low Wall structures/palisade_wall.png - phase_village + phase_village structures/cart/s_wall_tower structures/cart/s_wall_gate structures/cart/s_wall_long structures/cart/s_wall_medium structures/cart/s_wall_short Index: ps/trunk/binaries/data/mods/public/simulation/templates/structures/gaul/assembly.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/structures/gaul/assembly.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/structures/gaul/assembly.xml (revision 27505) @@ -1,80 +1,80 @@ 200 400 10.0 20 0.1 Unit Support Infantry Cavalry 0 2 2000 decay|rubble/rubble_stone_6x6 gaul Assembly of Princes Remogantion Train Champion Trumpeters and Heroes. ConquestCritical CivSpecific City Council structures/tholos.png - phase_city + phase_city 80 20 30 3 interface/complete/building/complete_iber_monument.xml false 40 40000 0.7 units/{civ}/champion_infantry_trumpeter units/{civ}/hero_brennus units/{civ}/hero_viridomarus units/{civ}/hero_vercingetorix 40 structures/gauls/theater.xml structures/fndn_6x6.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/structures/gaul/tavern.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/structures/gaul/tavern.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/structures/gaul/tavern.xml (revision 27505) @@ -1,51 +1,51 @@ 200 100 100 5.0 1500 decay|rubble/rubble_stone_4x4 gaul Tavern Taberna -Village Town structures/embassy_celtic.png - phase_town + phase_town 20 20 10 interface/complete/building/complete_broch.xml 30 structures/celts/tavern.xml structures/fndn_6x6.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/structures/han/civil_centre.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/structures/han/civil_centre.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/structures/han/civil_centre.xml (revision 27505) @@ -1,49 +1,49 @@ 8.0 Minister han Guān Shǔ -unlock_spies -spy_counter units/{civ}/infantry_spearman_b units/{civ}/infantry_crossbowman_b units/{civ}/cavalry_swordsman_b structures/{civ}/civil_centre_court This greatly increases the health, capture resistance, and garrison capacity of this specific Civic Center. Unlock training of Heroes here and reduce its research and batch training times by half. 300 300 upgrading - phase_city + phase_city structures/fndn_8x8.xml structures/han/civil_centre.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/structures/han/civil_centre_court.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/structures/han/civil_centre_court.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/structures/han/civil_centre_court.xml (revision 27505) @@ -1,46 +1,46 @@ ImperialCourt 1.5 1.5 1.5 han Imperial Court Cháotíng Defensive ImperialCourt City CivCentre CivSpecific structures/military_settlement.png - phase_city + phase_city 30 -phase_town_{civ} 0.5 units/{civ}/hero_han_xin_horse units/{civ}/hero_liu_bang_horse units/{civ}/hero_wei_qing_chariot structures/han/imperial_court.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/structures/han/defense_tower.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/structures/han/defense_tower.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/structures/han/defense_tower.xml (revision 27505) @@ -1,37 +1,37 @@ 15.0 Minister han Fángyù Tǎ 22.0 structures/{civ}/defense_tower_great This tower has greater range, greater attack, greater health, and is twice as difficult to capture. 200 upgrading - phase_city + phase_city structures/han/tower_large.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/structures/han/laozigate.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/structures/han/laozigate.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/structures/han/laozigate.xml (revision 27505) @@ -1,63 +1,63 @@ 120 100 200 12.0 1200 decay|rubble/rubble_stone_4x2 han LaoziGate Lǎozǐ Mén CivSpecific LaoziGate Town structures/paifang.png - phase_town + phase_town 20 20 false false 20 30 3 interface/complete/building/complete_iber_monument.xml structures/han/shrine.xml structures/fndn_6x2.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/structures/han/ministry.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/structures/han/ministry.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/structures/han/ministry.xml (revision 27505) @@ -1,93 +1,93 @@ ImperialMinistry 3000 5.0 200 0 200 200 8.0 9 0 Unit Support Minister Infantry 1 1 3000 decay|rubble/rubble_stone_6x6 han Imperial Ministry Gōngdiàn CivSpecific ImperialMinistry Town Train the Nine Ministers. Territory root. Research a powerful suite of Administrative technologies. structures/imperial_ministry.png - phase_town + phase_town 200 40 40 20 pair_unlock_civil_engineering_han pair_unlock_civil_service_han unlock_spies spy_counter 0.0 0.1 0.1 0.1 2000 true 60 30000 0.8 units/{civ}/support_minister 80 structures/fndn_8x8.xml structures/han/imperial_ministry.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/structures/iber/monument.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/structures/iber/monument.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/structures/iber/monument.xml (revision 27505) @@ -1,71 +1,71 @@ structures/iber_monument Monument Monument 150 120 100 100 8.0 1200 decay|rubble/rubble_stone_2x2 iber Revered Monument Gur Oroigarri CivSpecific Monument Town structures/iberian_bull.png - phase_town + phase_town 20 20 20 30 3 interface/complete/building/complete_iber_monument.xml structures/iberians/sb_1.xml structures/fndn_2x2.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/structures/kush/pyramid_large.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/structures/kush/pyramid_large.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/structures/kush/pyramid_large.xml (revision 27505) @@ -1,66 +1,66 @@ structures/kush_pyramids_military PyramidLarge 300 450 150 20.0 3000 decay|rubble/rubble_stone_6x6 kush Large Pyramid mr ʿȝ -ConquestCritical CivSpecific City Pyramid structures/kush_pyramid_big.png - phase_city + phase_city 90 30 interface/complete/building/complete_iber_monument.xml 15.0 false 40 40000 40 structures/kushites/pyramid_large.xml structures/fndn_5x7.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/structures/kush/pyramid_small.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/structures/kush/pyramid_small.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/structures/kush/pyramid_small.xml (revision 27505) @@ -1,60 +1,60 @@ structures/kush_pyramids_economic 120 150 75 15.0 2000 decay|rubble/rubble_stone_4x4 kush Small Pyramid mr -ConquestCritical CivSpecific Village Pyramid structures/kush_pyramid_small.png - phase_village + phase_village 30 15 interface/complete/building/complete_iber_monument.xml false 30 30000 30 structures/kushites/pyramid_small.xml structures/fndn_4x5.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/structures/rome/army_camp.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/structures/rome/army_camp.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/structures/rome/army_camp.xml (revision 27505) @@ -1,130 +1,130 @@ Bow 10 60 1200 2000 100 1.5 50 false Human outline_border.png outline_border_mask.png 0.175 neutral enemy ArmyCamp ArmyCamp 80 3 15 1 Soldier 3 10.0 1 250 400 150 12.0 20 0.1 Unit Support Infantry Cavalry Siege 0 6 1750 decay|rubble/rubble_rome_sb rome Army Camp Castra Build in neutral or enemy territory. Train Advanced Melee Infantry. Construct Rams. Garrison Soldiers for additional arrows. ConquestCritical CivSpecific Town ArmyCamp structures/roman_camp.png - phase_town + phase_town 80 30 15 35 3 interface/complete/building/complete_broch.xml attack/weapon/bow_attack.xml attack/impact/arrow_impact.xml 2 0.7 units/{civ}/infantry_axeman_a units/{civ}/infantry_swordsman_a units/{civ}/infantry_spearman_a units/{civ}/infantry_pikeman_a units/{civ}/siege_ram 90 structures/romans/camp.xml structures/fndn_8x8.xml 29.5 8 Index: ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_civic_civil_centre_military_colony.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_civic_civil_centre_military_colony.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_civic_civil_centre_military_colony.xml (revision 27505) @@ -1,56 +1,56 @@ own neutral Colony CivilCentre 120 1 300 200 200 150 2000 decay|rubble/rubble_stone_5x5 Military Colony template_structure_civic_civil_centre_military_colony Colony structures/military_settlement.png - phase_town + phase_town 40 40 30 -phase_town_{civ} -phase_city_{civ} -hellenistic_metropolis interface/complete/building/complete_gymnasium.xml 75 Index: ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_civic_house.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_civic_house.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_civic_house.xml (revision 27505) @@ -1,77 +1,77 @@ 30 75 5.0 3 0 0.1 Unit Support+!Elephant 1 800 decay|rubble/rubble_stone_2x2 House template_structure_civic_house Village House structures/house.png - phase_village + phase_village 15 5 health_females_01 pop_house_01 pop_house_02 unlock_females_house interface/complete/building/complete_house.xml 8.0 false 16 65535 units/{civ}/support_female_citizen_house 20 structures/fndn_3x3.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_civic_stoa.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_civic_stoa.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_civic_stoa.xml (revision 27505) @@ -1,54 +1,54 @@ 150 100 150 10.0 10 0.1 Unit Support Infantry Cavalry 0 2 2500 decay|rubble/rubble_stone_6x4 Stoa template_structure_civic_stoa -ConquestCritical Town Stoa structures/stoa.png - phase_town + phase_town 20 30 false 40 65535 40 structures/fndn_8x4.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_civic_temple.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_civic_temple.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_civic_temple.xml (revision 27505) @@ -1,78 +1,78 @@ structures/temple_heal 200 300 12.0 20 0.1 Unit Support Infantry Cavalry 3 2 2000 decay|rubble/rubble_stone_4x6 Temple template_structure_civic_temple Train Healers and research healing technologies. Town Temple structures/temple.png - phase_town + phase_town 60 heal_range heal_range_2 heal_rate heal_rate_2 garrison_heal health_regen_units interface/complete/building/complete_temple.xml false 40 30000 0.8 units/{civ}/support_healer_b 40 structures/fndn_4x6.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_defensive_tower_artillery.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_defensive_tower_artillery.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_defensive_tower_artillery.xml (revision 27505) @@ -1,86 +1,86 @@ Stone 90 0 80 40 0 15 0 4500 5000 40 6 9.81 false props/units/weapons/tower_artillery_projectile.xml props/units/weapons/tower_artillery_projectile_impact.xml 0.3 -Human !Organic 1 0 200 200 200 15.0 5 1400 Artillery Tower template_structure_defensive_tower_artillery ArtilleryTower structures/tower_artillery.png - phase_city + phase_city 40 40 tower_health attack/impact/siegeprojectilehit.xml attack/siege/ballist_attack.xml false 32 30000 Index: ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_defensive_tower_bolt.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_defensive_tower_bolt.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_defensive_tower_bolt.xml (revision 27505) @@ -1,83 +1,83 @@ Bolt 100 90 30 0 15 0 500 4000 150 1 9.81 false props/units/weapons/tower_artillery_projectile_impact.xml 0.1 1 0 200 200 100 15.0 5 1400 Bolt Tower template_structure_defensive_tower_bolt BoltTower structures/tower_bolt.png - phase_city + phase_city 40 20 tower_health attack/weapon/arrowfly.xml attack/impact/arrow_metal.xml false 32 30000 Index: ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_defensive_tower_stone.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_defensive_tower_stone.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_defensive_tower_stone.xml (revision 27505) @@ -1,61 +1,61 @@ 0 15 0 150 100 100 15.0 5 1000 Stone Tower template_structure_defensive_tower_stone Garrison Infantry for additional arrows. Needs the “Murder Holes” technology to protect its foot. StoneTower structures/defense_tower.png - phase_town + phase_town 20 20 tower_watch tower_crenellations tower_range tower_murderholes tower_health false 32 30000 Index: ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_economic_farmstead.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_economic_farmstead.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_economic_farmstead.xml (revision 27505) @@ -1,76 +1,76 @@ FemaleCitizen 50 100 100 300 45 100 8.0 900 decay|rubble/rubble_stone_4x4 Farmstead template_structure_economic_farmstead Research food gathering technologies. DropsiteFood Village Farmstead structures/farmstead.png - phase_village + phase_village 20 gather_wicker_baskets gather_farming_plows gather_farming_training gather_farming_fertilizer gather_farming_seed_drill gather_farming_water_weeding gather_farming_chain_pump gather_farming_harvester food true interface/complete/building/complete_farmstead.xml interface/alarm/alarm_alert_0.xml interface/alarm/alarm_alert_1.xml false 20 30000 20 structures/fndn_5x5.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_economic_storehouse.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_economic_storehouse.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_economic_storehouse.xml (revision 27505) @@ -1,81 +1,81 @@ FemaleCitizen 50 100 100 40 100 8.0 800 decay|rubble/rubble_stone_3x3 Storehouse template_structure_economic_storehouse Research gathering technologies. DropsiteWood DropsiteMetal DropsiteStone Village Storehouse structures/storehouse.png - phase_village + phase_village 20 gather_lumbering_ironaxes gather_lumbering_strongeraxes gather_lumbering_sharpaxes gather_mining_servants gather_mining_serfs gather_mining_slaves gather_mining_wedgemallet gather_mining_shaftmining gather_mining_silvermining gather_capacity_basket gather_capacity_wheelbarrow gather_capacity_carts wood stone metal true interface/complete/building/complete_storehouse.xml interface/alarm/alarm_alert_0.xml interface/alarm/alarm_alert_1.xml false 20 30000 20 structures/fndn_3x3.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_military_barracks.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_military_barracks.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_military_barracks.xml (revision 27505) @@ -1,83 +1,83 @@ structures/xp_trickle 150 200 100 12.0 10 Infantry 2000 decay|rubble/rubble_stone_4x4 Barracks template_structure_military_barracks Train Infantry and research Infantry technologies. Village Barracks structures/barracks.png - phase_village + phase_village 40 20 barracks_batch_training unlock_champion_infantry pair_unlock_champions_sele interface/complete/building/complete_barracks.xml 0.8 units/{civ}/infantry_spearman_b units/{civ}/infantry_pikeman_b units/{civ}/infantry_maceman_b units/{civ}/infantry_axeman_b units/{civ}/infantry_swordsman_b units/{civ}/infantry_javelineer_b units/{civ}/infantry_slinger_b units/{civ}/infantry_archer_b units/{civ}/champion_infantry_spearman units/{civ}/champion_infantry_pikeman units/{civ}/champion_infantry_maceman units/{civ}/champion_infantry_axeman units/{civ}/champion_infantry_swordsman units/{civ}/champion_infantry_javelineer units/{civ}/champion_infantry_slinger units/{civ}/champion_infantry_archer 32 structures/fndn_6x6.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_military_forge.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_military_forge.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_military_forge.xml (revision 27505) @@ -1,73 +1,73 @@ 120 200 12.0 1 Infantry Healer 2000 decay|rubble/rubble_stone_4x4 Forge template_structure_military_forge Research attack damage and damage resistance technologies. -ConquestCritical Town Forge structures/blacksmith.png - phase_town + phase_town 40 soldier_attack_melee_01 soldier_attack_melee_02 soldier_attack_melee_03 soldier_attack_melee_03_variant soldier_attack_ranged_01 soldier_attack_ranged_02 soldier_attack_ranged_03 soldier_resistance_hack_01 soldier_resistance_hack_02 soldier_resistance_hack_03 soldier_resistance_pierce_01 soldier_resistance_pierce_02 soldier_resistance_pierce_03 archer_attack_spread interface/complete/building/complete_forge.xml 38 30000 32 structures/fndn_5x5.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_military_stable.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_military_stable.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_military_stable.xml (revision 27505) @@ -1,79 +1,79 @@ structures/xp_trickle 120 200 50 12.0 10 Cavalry 2000 decay|rubble/rubble_stone_5x5 Stable template_structure_military_stable Train Cavalry and research Cavalry technologies. Village Stable structures/stable_01.png - phase_village + phase_village 40 10 stable_batch_training cavalry_movement_speed cavalry_health nisean_horses unlock_champion_cavalry unlock_champion_chariots interface/complete/building/complete_stable.xml 0.8 units/{civ}/cavalry_axeman_b units/{civ}/cavalry_swordsman_b units/{civ}/cavalry_spearman_b units/{civ}/cavalry_javelineer_b units/{civ}/cavalry_archer_b units/{civ}/champion_cavalry units/{civ}/champion_cavalry_spearman units/{civ}/champion_cavalry_swordsman units/{civ}/champion_cavalry_javelineer units/{civ}/champion_cavalry_archer units/{civ}/champion_chariot units/{civ}/war_dog 32 Index: ps/trunk/binaries/data/mods/public/simulation/templates/template_unit_champion_cavalry.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/template_unit_champion_cavalry.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/template_unit_champion_cavalry.xml (revision 27505) @@ -1,67 +1,67 @@ 25 150 80 100 6.0 240 FastMoving Cavalry Champion Cavalry - unlock_champion_cavalry + -phase_city unlock_champion_cavalry 200 15 8 10 5 7 5 20 actor/mounted/movement/walk.xml actor/mounted/movement/walk.xml actor/fauna/death/death_horse.xml interface/alarm/alarm_create_cav.xml 7.0 special/formations/wedge 2 1.4 80 Index: ps/trunk/binaries/data/mods/public/simulation/templates/template_unit_champion.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/template_unit_champion.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/template_unit_champion.xml (revision 27505) @@ -1,41 +1,41 @@ Capture 5 4 1000 Field Palisade Wall Human Soldier Champion Champion Unit - phase_city + phase_city 8 256x256/arrow.png 256x256/arrow_mask.png voice/{lang}/civ/civ_{phenotype}_attack.xml voice/{lang}/civ/civ_{phenotype}_attack.xml voice/{lang}/civ/civ_{phenotype}_garrison.xml voice/{lang}/civ/civ_{phenotype}_gather.xml voice/{lang}/civ/civ_{phenotype}_walk.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/template_unit_ship_fire.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/template_unit_ship_fire.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/template_unit_ship_fire.xml (revision 27505) @@ -1,65 +1,65 @@ Fire 20 12 50 100 !Ship 30 300 Circular 30 true 600 500 -6 0.85 0.65 0.35 Fire Ship Unrepairable. Gradually loses health. Can only attack Ships. Melee Warship Fireship - phase_town + phase_town 128x256/cartouche.png 128x256/cartouche_mask.png ship-small 1.6 1.6 60 Index: ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_wonder.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_wonder.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/template_structure_wonder.xml (revision 27505) @@ -1,101 +1,101 @@ structures/wonder_population_cap Wonder 4 1000 1000 1500 1000 10.0 50 0.1 Unit Support Soldier 5 2 5000 decay|rubble/rubble_stone_6x6 Wonder template_structure_wonder Bring glory to your civilization and add large tracts of land to your empire. ConquestCritical City Wonder structures/wonder.png - phase_city + phase_city 200 300 200 structure wonder.png wonder_population_cap 15 25 3 1.0 1.0 1.0 1.0 2000 interface/complete/building/complete_wonder.xml true 100 65535 72 structures/fndn_stonehenge.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/template_unit_hero.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/template_unit_hero.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/template_unit_hero.xml (revision 27505) @@ -1,72 +1,72 @@ Capture 10 4 1000 Field Palisade Wall units/heroes/hero_garrison 0 50 100 250 Human Soldier Hero Hero technologies/laurel_wreath.png - phase_city + phase_city 400 10 0 0 25 hero 256x256/star.png 256x256/star_mask.png voice/{lang}/civ/civ_{phenotype}_attack.xml voice/{lang}/civ/civ_{phenotype}_attack.xml voice/{lang}/civ/civ_{phenotype}_garrison.xml voice/{lang}/civ/civ_{phenotype}_gather.xml voice/{lang}/civ/civ_{phenotype}_walk.xml interface/alarm/alarm_create_infantry.xml actor/human/movement/walk.xml actor/human/movement/walk.xml actor/human/death/{phenotype}_death.xml Hero 1 100 Index: ps/trunk/binaries/data/mods/public/simulation/templates/template_unit_fauna_herd_domestic_cattle.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/template_unit_fauna_herd_domestic_cattle.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/template_unit_fauna_herd_domestic_cattle.xml (revision 27505) @@ -1,21 +1,21 @@ - phase_city + phase_city actor/fauna/animal/cattle_order.xml actor/fauna/animal/cattle_death.xml actor/fauna/animal/cattle_trained.xml 0.4 1.4 0.4 Index: ps/trunk/binaries/data/mods/public/simulation/templates/template_unit_ship_merchant.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/template_unit_ship_merchant.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/template_unit_ship_merchant.xml (revision 27505) @@ -1,60 +1,60 @@ 20 100 15 Support Cavalry 240 Merchantman template_unit_ship_merchant Trade between docks. Garrison a Trader aboard for additional profit (+20% for each garrisoned). Gather profitable aquatic treasures. -ConquestCritical Trader Bribable - phase_town + phase_town 20 128x256/ellipse.png 128x256/ellipse_mask.png 0.75 0.2 12 passive false false ship-small 1.35 1.6 50 true Index: ps/trunk/binaries/data/mods/public/simulation/templates/template_unit_siege.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/template_unit_siege.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/template_unit_siege.xml (revision 27505) @@ -1,76 +1,76 @@ 3 0.0 0.0 2.0 true -Organic Siege Siege - phase_city + phase_city pitch-roll 4 4.0 0.0 1 1 25 5 128x256/rounded_rectangle.png 128x256/rounded_rectangle_mask.png attack/siege/ram_move.xml attack/siege/ram_move.xml attack/siege/ram_move.xml attack/siege/ram_trained.xml 4.0 0.5 false large 1 0.75 0.15 5.0 Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/athen/infantry_javelineer_b.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/units/athen/infantry_javelineer_b.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/units/athen/infantry_javelineer_b.xml (revision 27505) @@ -1,18 +1,18 @@ units/athen/infantry_javelineer_b Thracian Peltast Peltastḗs Thrâx units/athen/infantry_javelinist.png - phase_town + phase_town units/athen/infantry_javelineer_a units/athenians/infantry_javelinist_b.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/brit/infantry_javelineer_b.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/units/brit/infantry_javelineer_b.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/units/brit/infantry_javelineer_b.xml (revision 27505) @@ -1,25 +1,25 @@ 0.80 0.50 0.20 brit units/brit/infantry_javelineer_b Adretos units/brit/infantry_javelinist.png - phase_town + phase_town units/brit/infantry_javelineer_a units/britons/infantry_javelinist_b.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/cart/cavalry_swordsman_iber_b.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/units/cart/cavalry_swordsman_iber_b.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/units/cart/cavalry_swordsman_iber_b.xml (revision 27505) @@ -1,24 +1,24 @@ Sword cart Iberian Heavy Cavalry Ḥayyāl Ḥerev Raḫūv units/cart/cavalry_swordsman_iber_b units/cart/cavalry_swordsman.png - phase_town + phase_town units/cart/cavalry_swordsman_iber_a units/iberians/cavalry_swordsman_b_m.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/cart/infantry_swordsman_ital_b.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/units/cart/infantry_swordsman_ital_b.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/units/cart/infantry_swordsman_ital_b.xml (revision 27505) @@ -1,27 +1,27 @@ structures/{civ}/super_dock structures/{civ}/embassy_celtic structures/{civ}/embassy_iberian structures/{civ}/embassy_italic cart Samnite Swordsman Seḫīr Romaḥ units/cart/infantry_swordsman_ital_b units/cart/infantry_swordsman_2.png - phase_town + phase_town units/cart/infantry_swordsman_ital_a units/carthaginians/infantry_swordsman_b.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/gaul/champion_fanatic.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/units/gaul/champion_fanatic.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/units/gaul/champion_fanatic.xml (revision 27505) @@ -1,39 +1,39 @@ 120 100 0 gaul Naked Fanatic Bariogaisatos units/gaul/champion_fanatic.png - phase_town + phase_town 12 10 0 -3 -4 1.4 1.4 units/gauls/infantry_spearman_c.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/han/cavalry_crossbowman_b.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/units/han/cavalry_crossbowman_b.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/units/han/cavalry_crossbowman_b.xml (revision 27505) @@ -1,18 +1,18 @@ han units/han/cavalry_crossbowman_b Han Cavalry Crossbowman units/han/cavalry_crossbowman.png - phase_town + phase_town units/han/cavalry_crossbowman_a units/han/cavalry_crossbowman_b_m.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/han/champion_infantry_archer_academy.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/units/han/champion_infantry_archer_academy.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/units/han/champion_infantry_archer_academy.xml (revision 27505) @@ -1,16 +1,13 @@ han Palace Guard Archer Yǔ Lín units/han/champion_infantry_archer units/han/champion_infantry_archer.png - - phase_city - units/han/infantry_archer_c.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/han/infantry_pikeman_b.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/units/han/infantry_pikeman_b.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/units/han/infantry_pikeman_b.xml (revision 27505) @@ -1,46 +1,46 @@ Ji 1 1 -structures/wallset_palisade han units/han/infantry_pikeman_b Halberdier Jǐ Bīng units/han/infantry_halberdman.png - phase_town + phase_town units/han/infantry_pikeman_a -2 -2 special/formations/anti_cavalry units/han/infantry_halberdman_b.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/template_unit_ship_warship_medium.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/template_unit_ship_warship_medium.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/template_unit_ship_warship_medium.xml (revision 27505) @@ -1,46 +1,46 @@ 3 13 3 25 200 100 30 Siege 1400 Medium Warship Garrison units for transport and to increase firepower. Deals triple damage against Ships. Medium Trireme - phase_town + phase_town 140 40 20 4 1.8 1.8 90 Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/athen/cavalry_swordsman_b.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/units/athen/cavalry_swordsman_b.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/units/athen/cavalry_swordsman_b.xml (revision 27505) @@ -1,23 +1,23 @@ Sword units/athen/cavalry_swordsman_b Greek Cavalry Hippeús units/athen/cavalry_swordsman.png - phase_town + phase_town units/athen/cavalry_swordsman_a units/athenians/cavalry_swordsman_b_m.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/brit/cavalry_swordsman_b.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/units/brit/cavalry_swordsman_b.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/units/brit/cavalry_swordsman_b.xml (revision 27505) @@ -1,19 +1,19 @@ brit units/brit/cavalry_swordsman_b Eporedos Celtic Cavalry units/brit/cavalry_swordsman.png - phase_town + phase_town units/brit/cavalry_swordsman_a units/britons/cavalry_swordsman_b_m.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/cart/cavalry_swordsman_gaul_b.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/units/cart/cavalry_swordsman_gaul_b.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/units/cart/cavalry_swordsman_gaul_b.xml (revision 27505) @@ -1,19 +1,19 @@ cart Gallic Mercenary Cavalry Ḥayyāl Ḥerev Raḫūv units/cart/cavalry_swordsman_gaul_b units/cart/cavalry_swordsman_2.png - phase_town + phase_town units/cart/cavalry_swordsman_gaul_a units/gauls/cavalry_swordsman_b_m.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/cart/infantry_swordsman_gaul_b.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/units/cart/infantry_swordsman_gaul_b.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/units/cart/infantry_swordsman_gaul_b.xml (revision 27505) @@ -1,27 +1,27 @@ structures/{civ}/super_dock structures/{civ}/embassy_celtic structures/{civ}/embassy_iberian structures/{civ}/embassy_italic cart Gallic Mercenary Swordsman Seḫīr Ḥerev units/cart/infantry_swordsman_gaul_b units/cart/infantry_swordsman.png - phase_town + phase_town units/cart/infantry_swordsman_gaul_a units/gauls/infantry_swordsman_b.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/gaul/cavalry_swordsman_b.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/units/gaul/cavalry_swordsman_b.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/units/gaul/cavalry_swordsman_b.xml (revision 27505) @@ -1,18 +1,18 @@ gaul units/gaul/cavalry_swordsman_b Eporedos units/gaul/cavalry_swordsman.png - phase_town + phase_town units/gaul/cavalry_swordsman_a units/gauls/cavalry_swordsman_b_m.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/han/cavalry_archer_b.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/units/han/cavalry_archer_b.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/units/han/cavalry_archer_b.xml (revision 27505) @@ -1,18 +1,18 @@ han units/han/cavalry_archer_b Gōng Qíbīng units/han/cavalry_archer.png - phase_town + phase_town units/han/cavalry_archer_a units/han/cavalry_archer_b_m.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/han/champion_chariot_academy.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/units/han/champion_chariot_academy.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/units/han/champion_chariot_academy.xml (revision 27505) @@ -1,20 +1,20 @@ 5.0 han Han War Chariot Zhanche Chariot units/han/chariot.png - phase_city + -unlock_champion_cavalry phase_city units/han/chariot_archer_m.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/han/infantry_archer_b.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/units/han/infantry_archer_b.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/units/han/infantry_archer_b.xml (revision 27505) @@ -1,23 +1,23 @@ -structures/wallset_palisade han units/han/infantry_archer_b Shè Shǒu units/han/infantry_archer.png - phase_town + phase_town units/han/infantry_archer_a units/han/infantry_archer_b.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/template_unit_ship_warship_light.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/template_unit_ship_warship_light.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/template_unit_ship_warship_light.xml (revision 27505) @@ -1,41 +1,41 @@ 2 10 2 20 120 60 20 800 Light Warship Light Bireme - phase_town + phase_town 80 24 12 1.55 1.55 90 Index: ps/trunk/binaries/data/mods/public/simulation/templates/template_wallset.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/template_wallset.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/template_wallset.xml (revision 27505) @@ -1,28 +1,28 @@ gaia Wall Wall off an area. Wall structures/wall.png true - phase_town + phase_town false false false false 0.85 0.05 Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/athen/support_female_citizen_house.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/units/athen/support_female_citizen_house.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/units/athen/support_female_citizen_house.xml (revision 27505) @@ -1,11 +1,11 @@ 30 - unlock_females_house + unlock_females_house Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/cart/cavalry_spearman_ital_b.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/units/cart/cavalry_spearman_ital_b.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/units/cart/cavalry_spearman_ital_b.xml (revision 27505) @@ -1,19 +1,19 @@ cart Italic Cavalry Ḥayyāl Romaḥ Raḫūv units/cart/cavalry_spearman_ital_b units/cart/cavalry_spearman.png - phase_town + phase_town units/cart/cavalry_spearman_ital_a units/carthaginians/cavalry_spearman_b_m.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/cart/infantry_slinger_iber_b.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/units/cart/infantry_slinger_iber_b.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/units/cart/infantry_slinger_iber_b.xml (revision 27505) @@ -1,27 +1,27 @@ structures/{civ}/super_dock structures/{civ}/embassy_celtic structures/{civ}/embassy_iberian structures/{civ}/embassy_italic cart Balearic Slinger Qallāʿ Ibušimi units/cart/infantry_slinger_iber_b units/cart/infantry_slinger.png - phase_town + phase_town units/cart/infantry_slinger_iber_a units/iberians/infantry_slinger_b.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/cart/support_female_citizen_house.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/units/cart/support_female_citizen_house.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/units/cart/support_female_citizen_house.xml (revision 27505) @@ -1,11 +1,11 @@ 30 - unlock_females_house + unlock_females_house Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/gaul/support_female_citizen_house.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/units/gaul/support_female_citizen_house.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/units/gaul/support_female_citizen_house.xml (revision 27505) @@ -1,11 +1,11 @@ 30 - unlock_females_house + unlock_females_house Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/han/champion_cavalry_spearman_academy.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/units/han/champion_cavalry_spearman_academy.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/units/han/champion_cavalry_spearman_academy.xml (revision 27505) @@ -1,15 +1,15 @@ han Wu Wei Yin Cao Cao Guard units/han/champion_cavalry units/han/champion_cavalry_spearman.png - phase_city + -unlock_champion_cavalry phase_city units/han/cavalry_spearman_c_m.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/han/champion_infantry_spearman_academy.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/units/han/champion_infantry_spearman_academy.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/units/han/champion_infantry_spearman_academy.xml (revision 27505) @@ -1,16 +1,13 @@ han Palace Guard Spearman Hǔ Bēn units/han/champion_infantry_spearman units/han/champion_infantry_swordsman.png - - phase_city - units/han/infantry_spearman_c.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/template_unit_ship_warship_heavy.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/template_unit_ship_warship_heavy.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/template_unit_ship_warship_heavy.xml (revision 27505) @@ -1,81 +1,81 @@ Stone 150 100 40 2000 5000 40 6 20 false Ship Structure outline_border.png outline_border_mask.png 0.175 1 10 StoneThrower 5 30 600 300 10.0 50 Support Soldier Siege 2000 Heavy Warship Garrison units for transport. Garrison Stone Throwers to increase firepower. Heavy Quinquereme - phase_city + phase_city 200 120 60 4 attack/siege/ballist_attack.xml 1.8 1.8 110 Index: ps/trunk/binaries/data/mods/public/simulation/templates/template_unit_support_healer.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/template_unit_support_healer.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/template_unit_support_healer.xml (revision 27505) @@ -1,60 +1,60 @@ 15 100 25 12 heal_overlay_range.png heal_overlay_range_mask.png 0.35 5 2000 Human 85 -ConquestCritical Healer Healer template_unit_support_healer Basic Heal units. - phase_town + phase_town 8 25 150 128x128/plus.png 128x128/plus_mask.png voice/{lang}/civ/civ_{phenotype}_heal.xml interface/alarm/alarm_create_priest.xml 30 Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/athen/infantry_marine_archer_b.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/units/athen/infantry_marine_archer_b.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/units/athen/infantry_marine_archer_b.xml (revision 27505) @@ -1,18 +1,18 @@ units/athen/infantry_marine_archer_b Cretan Mercenary Archer Toxótēs Krētikós units/mace/infantry_archer.png - iphicratean_reforms + iphicratean_reforms units/athen/infantry_marine_archer_a units/athenians/infantry_archer_b.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/brit/support_female_citizen_house.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/units/brit/support_female_citizen_house.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/units/brit/support_female_citizen_house.xml (revision 27505) @@ -1,11 +1,11 @@ 30 - unlock_females_house + unlock_females_house Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/cart/infantry_javelineer_iber_b.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/units/cart/infantry_javelineer_iber_b.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/units/cart/infantry_javelineer_iber_b.xml (revision 27505) @@ -1,27 +1,27 @@ structures/{civ}/super_dock structures/{civ}/embassy_celtic structures/{civ}/embassy_iberian structures/{civ}/embassy_italic cart Iberian Mercenary Skirmisher Sǝḫīr Kidōn units/cart/infantry_javelineer_iber_b units/cart/infantry_javelinist.png - phase_town + phase_town units/cart/infantry_javelineer_iber_a units/iberians/infantry_javelinist_b.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/cart/ship_merchant.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/units/cart/ship_merchant.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/units/cart/ship_merchant.xml (revision 27505) @@ -1,30 +1,30 @@ 8.0 cart Seḥer Trade between docks. Garrison a Trader aboard for additional profit (+20% for each garrisoned). Gather profitable aquatic treasures. Carthaginians have +25% sea trading bonus. units/cart/ship_merchant.png - phase_village + -phase_town phase_village 128x512/ellipse.png 128x512/ellipse_mask.png 1.25 structures/carthaginians/merchant_ship.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/gaul/infantry_slinger_b.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/units/gaul/infantry_slinger_b.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/units/gaul/infantry_slinger_b.xml (revision 27505) @@ -1,23 +1,23 @@ structures/gaul/assembly gaul units/gaul/infantry_slinger_b Talmoris units/gaul/infantry_slinger.png - phase_town + phase_town units/gaul/infantry_slinger_a units/gauls/infantry_slinger_b.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/han/cavalry_spearman_b.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/units/han/cavalry_spearman_b.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/units/han/cavalry_spearman_b.xml (revision 27505) @@ -1,18 +1,18 @@ han units/han/cavalry_spearman_b Máo Qíbīng units/han/cavalry_spearman.png - phase_town + phase_town units/han/cavalry_spearman_a units/han/cavalry_spearman_b_m.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/han/champion_infantry_crossbowman_academy.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/units/han/champion_infantry_crossbowman_academy.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/units/han/champion_infantry_crossbowman_academy.xml (revision 27505) @@ -1,14 +1,11 @@ han Juezhang units/han/champion_infantry_crossbowman.png - - phase_city - units/han/infantry_crossbowman_c.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/han/infantry_swordsman_special_b.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/units/han/infantry_swordsman_special_b.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/units/han/infantry_swordsman_special_b.xml (revision 27505) @@ -1,23 +1,23 @@ -structures/wallset_palisade han units/han/infantry_swordsman_b Dāo Bīng units/han/infantry_swordsman.png - phase_town + phase_town units/han/infantry_swordsman_special_a units/han/infantry_swordsman_b.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/iber/cavalry_spearman_b.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/units/iber/cavalry_spearman_b.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/units/iber/cavalry_spearman_b.xml (revision 27505) @@ -1,18 +1,18 @@ iber units/iber/cavalry_spearman_b Lantzari units/iber/cavalry_spearman.png - phase_town + phase_town units/iber/cavalry_spearman_a units/iberians/cavalry_spearman_b_m.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/han/support_minister.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/units/han/support_minister.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/units/han/support_minister.xml (revision 27505) @@ -1,109 +1,109 @@ Capture 8 4 1000 Field Palisade Wall Sword 10 3 500 1000 Unit+!Ship units/han_minister_garrison units/han_minister_gathering units/han_minister_building units/han_minister_garrison_ministry 1 15 100 100 200 han Imperial Minister Guānlì Use to boost the efficiency of nearby units and buildings. Garrison within a building to boost the efficiency of its production queue. Only Han buildings can garrison ministers. Organic Human Minister units/han/minister.png - phase_town + phase_town 150 10 10 hero 8 2 4 6 128x128/octagram.png 128x128/octagram_mask.png attack/weapon/sword_attack.xml resource/construction/con_wood.xml actor/human/death/{phenotype}_death.xml voice/{lang}/civ/civ_{phenotype}_attack.xml voice/{lang}/civ/civ_{phenotype}_attack.xml voice/{lang}/civ/civ_{phenotype}_garrison.xml voice/{lang}/civ/civ_{phenotype}_gather.xml voice/{lang}/civ/civ_{phenotype}_repair.xml voice/{lang}/civ/civ_{phenotype}_walk.xml actor/human/movement/run.xml interface/alarm/alarm_create_infantry.xml actor/human/movement/walk.xml Minister 40 units/han/minister.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/han/support_female_citizen_house.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/units/han/support_female_citizen_house.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/units/han/support_female_citizen_house.xml (revision 27505) @@ -1,11 +1,11 @@ 30 - unlock_females_house + unlock_females_house Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/iber/infantry_slinger_b.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/units/iber/infantry_slinger_b.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/units/iber/infantry_slinger_b.xml (revision 27505) @@ -1,23 +1,23 @@ structures/iber/monument iber units/iber/infantry_slinger_b Habailari units/iber/infantry_slinger.png - phase_town + phase_town units/iber/infantry_slinger_a units/iberians/infantry_slinger_b.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/iber/champion_infantry_swordsman.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/units/iber/champion_infantry_swordsman.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/units/iber/champion_infantry_swordsman.xml (revision 27505) @@ -1,19 +1,19 @@ Sword iber Leial Ezpatari units/iber/champion_infantry.png - unlock_champion_infantry + unlock_champion_infantry units/iberians/infantry_swordsman_c.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/iber/support_female_citizen_house.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/units/iber/support_female_citizen_house.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/units/iber/support_female_citizen_house.xml (revision 27505) @@ -1,11 +1,11 @@ 30 - unlock_females_house + unlock_females_house Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/kush/infantry_archer_b.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/units/kush/infantry_archer_b.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/units/kush/infantry_archer_b.xml (revision 27505) @@ -1,28 +1,28 @@ structures/kush/pyramid_large structures/kush/temple_amun structures/kush/camp_blemmye structures/kush/camp_noba kush napatan units/kush/infantry_archer_b Nubian Archer Pdty Nhsyw units/kush/infantry_archer.png - phase_village + phase_village units/kush/infantry_archer_a units/kushites/infantry_archer_b.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/kush/infantry_spearman_b.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/units/kush/infantry_spearman_b.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/units/kush/infantry_spearman_b.xml (revision 27505) @@ -1,28 +1,28 @@ structures/kush/pyramid_large structures/kush/temple_amun structures/kush/camp_blemmye structures/kush/camp_noba kush napatan units/kush/infantry_spearman_b Nubian Spearman iry-rdwy Nhsyw units/kush/infantry_spearman.png - phase_village + phase_village units/kush/infantry_spearman_a units/kushites/infantry_spearman_b.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/mace/champion_infantry_spearman.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/units/mace/champion_infantry_spearman.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/units/mace/champion_infantry_spearman.xml (revision 27505) @@ -1,21 +1,21 @@ mace greek Macedonian Shield Bearer Hypaspistḗs units/mace/champion_infantry_spearman units/mace/hypaspist.png - unlock_champion_infantry + unlock_champion_infantry units/mace/champion_infantry_spearman_02 2000 units/macedonians/infantry_spearman_c_a.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/maur/cavalry_swordsman_b.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/units/maur/cavalry_swordsman_b.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/units/maur/cavalry_swordsman_b.xml (revision 27505) @@ -1,19 +1,19 @@ maur units/maur/cavalry_swordsman_b Indian Raiding Cavalry Aśvārohagaṇaḥ units/maur/cavalry_swordsman.png - phase_town + phase_town units/maur/cavalry_swordsman_a units/mauryas/cavalry_swordsman_b_m.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/maur/support_female_citizen_house.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/units/maur/support_female_citizen_house.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/units/maur/support_female_citizen_house.xml (revision 27505) @@ -1,11 +1,11 @@ 30 - unlock_females_house + unlock_females_house Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/pers/cavalry_axeman_b_trireme.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/units/pers/cavalry_axeman_b_trireme.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/units/pers/cavalry_axeman_b_trireme.xml (revision 27505) @@ -1,11 +1,11 @@ - equine_transports + -phase_town equine_transports units/pers/cavalry_axeman_a_trireme Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/pers/cavalry_javelineer_e_trireme.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/units/pers/cavalry_javelineer_e_trireme.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/units/pers/cavalry_javelineer_e_trireme.xml (revision 27505) @@ -1,8 +1,8 @@ - equine_transports + equine_transports Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/ptol/cavalry_archer_b.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/units/ptol/cavalry_archer_b.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/units/ptol/cavalry_archer_b.xml (revision 27505) @@ -1,40 +1,40 @@ 7.5 ptol Camel units/ptol/cavalry_archer Nabataean Camel Archer Mutsābiq Gamal Nabatu units/ptol/camel_archer.png - phase_village + phase_village units/ptol/cavalry_archer_a actor/fauna/movement/camel_order.xml actor/fauna/death/death_camel.xml 8.5 units/ptolemies/camel_archer_b_m.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/ptol/infantry_archer_b.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/units/ptol/infantry_archer_b.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/units/ptol/infantry_archer_b.xml (revision 27505) @@ -1,25 +1,25 @@ structures/ptol/lighthouse structures/ptol/library ptol units/ptol/infantry_archer_b Cretan Mercenary Archer Toxótēs Krētikós units/mace/infantry_archer.png - phase_town + phase_town units/ptol/infantry_archer_a units/ptolemies/infantry_archer_b.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/iber/infantry_spearman_b.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/units/iber/infantry_spearman_b.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/units/iber/infantry_spearman_b.xml (revision 27505) @@ -1,23 +1,23 @@ structures/iber/monument iber units/iber/infantry_spearman_b Ezkutari units/iber/infantry_spearman.png - phase_town + phase_town units/iber/infantry_spearman_a units/iberians/infantry_spearman_b.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/kush/cavalry_spearman_b.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/units/kush/cavalry_spearman_b.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/units/kush/cavalry_spearman_b.xml (revision 27505) @@ -1,20 +1,20 @@ kush napatan units/kush/cavalry_spearman_b Meroitic Heavy Cavalry Htr units/kush/cavalry_spearman.png - phase_town + phase_town units/kush/cavalry_spearman_a units/kushites/cavalry_spearman_b_m.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/kush/infantry_pikeman_b.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/units/kush/infantry_pikeman_b.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/units/kush/infantry_pikeman_b.xml (revision 27505) @@ -1,28 +1,28 @@ structures/kush/pyramid_large structures/kush/temple_amun structures/kush/camp_blemmye structures/kush/camp_noba kush napatan units/kush/infantry_pikeman_b Meroitic Pikeman siȝwrd units/kush/infantry_pikeman.png - phase_town + phase_town units/kush/infantry_pikeman_a units/kushites/infantry_pikeman_b.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/mace/cavalry_javelineer_b.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/units/mace/cavalry_javelineer_b.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/units/mace/cavalry_javelineer_b.xml (revision 27505) @@ -1,20 +1,20 @@ mace greek units/mace/cavalry_javelineer_b Odrysian Skirmish Cavalry Hippakontistḕs Odrysós units/mace/cavalry_javelinist.png - phase_town + phase_town units/mace/cavalry_javelineer_a units/macedonians/cavalry_javelinist_b_m.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/mace/support_female_citizen_house.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/units/mace/support_female_citizen_house.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/units/mace/support_female_citizen_house.xml (revision 27505) @@ -1,11 +1,11 @@ 30 - unlock_females_house + unlock_females_house Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/maur/infantry_swordsman_b.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/units/maur/infantry_swordsman_b.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/units/maur/infantry_swordsman_b.xml (revision 27505) @@ -1,30 +1,30 @@ Sword structures/maur/palace structures/maur/pillar_ashoka maur units/maur/infantry_swordsman_b Indian Swordsman Khadagdhari units/maur/infantry_swordsman.png - phase_town + phase_town units/maur/infantry_swordsman_a units/mauryas/infantry_swordsman_b.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/pers/cavalry_axeman_b.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/units/pers/cavalry_axeman_b.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/units/pers/cavalry_axeman_b.xml (revision 27505) @@ -1,20 +1,20 @@ pers persian units/pers/cavalry_axeman_b Hyrcanian Cavalry Asabāra Varkaniya units/pers/cavalry_axeman.png - phase_town + phase_town units/pers/cavalry_axeman_a units/persians/cavalry_axeman_b_m.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/pers/cavalry_javelineer_b_trireme.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/units/pers/cavalry_javelineer_b_trireme.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/units/pers/cavalry_javelineer_b_trireme.xml (revision 27505) @@ -1,11 +1,11 @@ - equine_transports + equine_transports units/pers/cavalry_javelineer_a_trireme Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/pers/support_female_citizen_house.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/units/pers/support_female_citizen_house.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/units/pers/support_female_citizen_house.xml (revision 27505) @@ -1,11 +1,11 @@ 30 - unlock_females_house + unlock_females_house Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/ptol/champion_infantry_pikeman.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/units/ptol/champion_infantry_pikeman.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/units/ptol/champion_infantry_pikeman.xml (revision 27505) @@ -1,16 +1,16 @@ ptol greek Royal Guard Infantry Phalangitès Agema units/ptol/champion_infantry.png - unlock_champion_infantry + unlock_champion_infantry units/ptolemies/infantry_pikeman_c.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/kush/cavalry_javelineer_merc_b.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/units/kush/cavalry_javelineer_merc_b.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/units/kush/cavalry_javelineer_merc_b.xml (revision 27505) @@ -1,41 +1,41 @@ 7.5 kush napatan units/kush/cavalry_javelineer_merc_b Blemmye Desert Raider nhw Bulahau gml Camel units/kush/camel_javelinist.png - phase_town + phase_town units/kush/cavalry_javelineer_merc_a actor/fauna/movement/camel_order.xml actor/fauna/death/death_camel.xml 8.5 units/kushites/camel_javelinist_b_m.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/kush/infantry_maceman_merc_b.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/units/kush/infantry_maceman_merc_b.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/units/kush/infantry_maceman_merc_b.xml (revision 27505) @@ -1,28 +1,28 @@ structures/kush/pyramid_large structures/kush/temple_amun structures/kush/camp_blemmye structures/kush/camp_noba kush napatan units/kush/infantry_maceman_b Noba Maceman nhw Noba units/kush/infantry_maceman.png - phase_town + phase_town units/kush/infantry_maceman_merc_a units/kushites/infantry_maceman_b.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/kush/support_female_citizen_house.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/units/kush/support_female_citizen_house.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/units/kush/support_female_citizen_house.xml (revision 27505) @@ -1,11 +1,11 @@ 30 - unlock_females_house + unlock_females_house Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/mace/infantry_slinger_b.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/units/mace/infantry_slinger_b.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/units/mace/infantry_slinger_b.xml (revision 27505) @@ -1,20 +1,20 @@ mace greek units/mace/infantry_slinger_b Rhodian Slinger Sphendonḗtēs Rhódios units/mace/infantry_slinger.png - phase_town + phase_town units/mace/infantry_slinger_a units/macedonians/infantry_slinger_b.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/maur/hero_chandragupta_infantry.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/units/maur/hero_chandragupta_infantry.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/units/maur/hero_chandragupta_infantry.xml (revision 27505) @@ -1,26 +1,26 @@ maur Chandragupta Maurya Chandragupta Maurya units/maur/hero_chandragupta.png units/maur/hero_chandragupta This gives Chandragupta Maurya his War Elephant. 200 200 - phase_city + phase_city units/mauryas/hero_infantry_swordsman_chandragupta.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/pers/cavalry_axeman_a_trireme.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/units/pers/cavalry_axeman_a_trireme.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/units/pers/cavalry_axeman_a_trireme.xml (revision 27505) @@ -1,11 +1,11 @@ - equine_transports + -phase_town equine_transports units/pers/cavalry_axeman_e_trireme Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/pers/cavalry_javelineer_a_trireme.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/units/pers/cavalry_javelineer_a_trireme.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/units/pers/cavalry_javelineer_a_trireme.xml (revision 27505) @@ -1,11 +1,11 @@ - equine_transports + equine_transports units/pers/cavalry_javelineer_e_trireme Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/pers/infantry_javelineer_b.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/units/pers/infantry_javelineer_b.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/units/pers/infantry_javelineer_b.xml (revision 27505) @@ -1,20 +1,20 @@ pers persian units/pers/infantry_javelineer_b Lydian Auxiliary Pastiš Spardiya units/pers/infantry_javelinist.png - phase_town + phase_town units/pers/infantry_javelineer_a units/persians/infantry_javelinist_b.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/ptol/cavalry_spearman_merc_b.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/units/ptol/cavalry_spearman_merc_b.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/units/ptol/cavalry_spearman_merc_b.xml (revision 27505) @@ -1,19 +1,19 @@ ptol units/ptol/cavalry_spearman_merc_b Macedonian Settler Cavalry Hippeús Makedonikós units/ptol/cavalry_spearman.png - phase_town + phase_town units/ptol/cavalry_spearman_merc_a units/ptolemies/cavalry_spearman_b_m.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/kush/cavalry_javelineer_b.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/units/kush/cavalry_javelineer_b.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/units/kush/cavalry_javelineer_b.xml (revision 27505) @@ -1,20 +1,20 @@ kush napatan units/kush/cavalry_javelineer_b iry hr ssmwtt Napatan Light Cavalry units/kush/cavalry_javelinist.png - phase_village + phase_village units/kush/cavalry_javelineer_a units/kushites/cavalry_javelinist_b_m.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/kush/infantry_javelineer_merc_b.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/units/kush/infantry_javelineer_merc_b.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/units/kush/infantry_javelineer_merc_b.xml (revision 27505) @@ -1,28 +1,28 @@ structures/kush/pyramid_large structures/kush/temple_amun structures/kush/camp_blemmye structures/kush/camp_noba kush napatan units/kush/infantry_javelineer_merc_b Noba Skirmisher nhw ʿhȝw Noba units/kush/infantry_javelinist.png - phase_town + phase_town units/kush/infantry_javelineer_merc_a units/kushites/infantry_javelinist_b.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/kush/infantry_swordsman_b.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/units/kush/infantry_swordsman_b.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/units/kush/infantry_swordsman_b.xml (revision 27505) @@ -1,28 +1,28 @@ structures/kush/pyramid_large structures/kush/temple_amun structures/kush/camp_blemmye structures/kush/camp_noba kush napatan units/kush/infantry_swordsman_b Meroitic Swordsman knw hps units/kush/infantry_swordsman.png - phase_town + phase_town units/kush/infantry_swordsman_a units/kushites/infantry_swordsman_b.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/mace/infantry_archer_b.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/units/mace/infantry_archer_b.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/units/mace/infantry_archer_b.xml (revision 27505) @@ -1,20 +1,20 @@ mace greek units/mace/infantry_archer_b Cretan Mercenary Archer Toxótēs Krētikós units/mace/infantry_archer.png - phase_town + phase_town units/mace/infantry_archer_a units/macedonians/infantry_archer_b.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/maur/elephant_archer_b.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/units/maur/elephant_archer_b.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/units/maur/elephant_archer_b.xml (revision 27505) @@ -1,19 +1,19 @@ maur Elephant Archer Vachii Gaja units/maur/elephant_archer_b units/maur/elephant_archer.png - phase_town + phase_town units/maur/elephant_archer_a units/mauryas/elephantry_archer_b_m.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/pers/cavalry_archer_b.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/units/pers/cavalry_archer_b.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/units/pers/cavalry_archer_b.xml (revision 27505) @@ -1,20 +1,20 @@ pers persian units/pers/cavalry_archer_b Parthian Horse Archer Asabāra Parθava units/pers/cavalry_archer.png - phase_town + phase_town units/pers/cavalry_archer_a units/persians/cavalry_archer_b_m.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/pers/cavalry_axeman_e_trireme.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/units/pers/cavalry_axeman_e_trireme.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/units/pers/cavalry_axeman_e_trireme.xml (revision 27505) @@ -1,8 +1,8 @@ - equine_transports + -phase_town equine_transports Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/pers/cavalry_spearman_b.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/units/pers/cavalry_spearman_b.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/units/pers/cavalry_spearman_b.xml (revision 27505) @@ -1,20 +1,20 @@ pers persian units/pers/cavalry_spearman_b Cappadocian Cavalry Asabāra Katpatuka units/pers/cavalry_spearman.png - phase_town + phase_town units/pers/cavalry_spearman_a units/persians/cavalry_spearman_b_m.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/ptol/cavalry_javelineer_merc_b.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/units/ptol/cavalry_javelineer_merc_b.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/units/ptol/cavalry_javelineer_merc_b.xml (revision 27505) @@ -1,19 +1,19 @@ ptol units/ptol/cavalry_javelineer_merc_b Tarantine Settler Cavalry Hippeús Tarantînos units/hele/tarentine_cavalry_e.png - phase_town + phase_town units/ptol/cavalry_javelineer_merc_a units/ptolemies/cavalry_javelinist_b_m.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/ptol/infantry_javelineer_b.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/units/ptol/infantry_javelineer_b.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/units/ptol/infantry_javelineer_b.xml (revision 27505) @@ -1,25 +1,25 @@ structures/ptol/lighthouse structures/ptol/library ptol units/ptol/infantry_javelineer_b Mercenary Thureos Skirmisher Thureophóros Akrobolistḗs units/ptol/infantry_javelinist_merc.png - phase_town + phase_town units/ptol/infantry_javelineer_a units/ptolemies/infantry_javelinist_b.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/ptol/infantry_swordsman_merc_b.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/units/ptol/infantry_swordsman_merc_b.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/units/ptol/infantry_swordsman_merc_b.xml (revision 27505) @@ -1,25 +1,25 @@ structures/ptol/lighthouse structures/ptol/library ptol Gallic Mercenary Swordsman Gallikós Mistophorós units/ptol/infantry_swordsman_merc_b units/cart/infantry_swordsman.png - phase_town + phase_town units/ptol/infantry_swordsman_merc_a units/ptolemies/infantry_swordsman_b.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/ptol/infantry_spearman_merc_b.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/units/ptol/infantry_spearman_merc_b.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/units/ptol/infantry_spearman_merc_b.xml (revision 27505) @@ -1,25 +1,25 @@ structures/ptol/lighthouse structures/ptol/library ptol units/ptol/infantry_spearman_merc_b Mercenary Thureos Spearman Thureophóros Misthophóros units/ptol/infantry_spearman_2.png - phase_town + phase_town units/ptol/infantry_spearman_merc_a units/ptolemies/infantry_spearman_b.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/ptol/infantry_slinger_b.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/units/ptol/infantry_slinger_b.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/units/ptol/infantry_slinger_b.xml (revision 27505) @@ -1,25 +1,25 @@ structures/ptol/lighthouse structures/ptol/library ptol units/ptol/infantry_slinger_b Judean Slinger Hebraikós Sphendonḗtēs units/ptol/infantry_slinger.png - phase_village + phase_village units/ptol/infantry_slinger_a units/ptolemies/infantry_slinger_b.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/rome/cavalry_javelineer_b.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/units/rome/cavalry_javelineer_b.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/units/rome/cavalry_javelineer_b.xml (revision 27505) @@ -1,20 +1,20 @@ rome latin Allied Cavalry Eques Socius units/rome/cavalry_javelineer_b units/rome/cavalry_javelinist.png - phase_town + phase_town units/rome/cavalry_javelineer_a units/romans/cavalry_javelinist_b_m.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/ptol/support_female_citizen_house.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/units/ptol/support_female_citizen_house.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/units/ptol/support_female_citizen_house.xml (revision 27505) @@ -1,11 +1,11 @@ 30 - unlock_females_house + unlock_females_house Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/rome/champion_infantry_sword_gladiator.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/units/rome/champion_infantry_sword_gladiator.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/units/rome/champion_infantry_sword_gladiator.xml (revision 27505) @@ -1,50 +1,50 @@ structures/rome/army_camp structures/rome/temple_vesta -10 20 5 Gladiator rome latin Gladiator Swordsman Murmillo Elite units/rome/champion_infantry_gladiator_sword.png - phase_town + phase_town -1 -1 Gladiator 1.4 1.4 0.5 units/romans/infantry_gladiator_swordsman.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/sele/cavalry_spearman_merc_b.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/units/sele/cavalry_spearman_merc_b.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/units/sele/cavalry_spearman_merc_b.xml (revision 27505) @@ -1,20 +1,20 @@ sele greek units/sele/cavalry_spearman_merc_b Companion Cavalry Hippos Hetairike units/sele/cavalry_spearman_merc.png - phase_town + phase_town units/sele/cavalry_spearman_merc_a units/seleucids/cavalry_spearman_b_m.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/sele/infantry_javelineer_b.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/units/sele/infantry_javelineer_b.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/units/sele/infantry_javelineer_b.xml (revision 27505) @@ -1,20 +1,20 @@ sele greek units/sele/infantry_javelineer_b Arab Javelineer Pezakontistès Aravikós units/sele/infantry_javelinist.png - phase_village + phase_village units/sele/infantry_javelineer_a units/seleucids/infantry_javelinist_b.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/spart/champion_infantry_swordsman.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/units/spart/champion_infantry_swordsman.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/units/spart/champion_infantry_swordsman.xml (revision 27505) @@ -1,32 +1,32 @@ structures/spart/syssiton -structures/{civ}/wallset_stone 25 spart greek Skiritai Commando Ékdromos Skirítēs Elite units/spart/champion_infantry_sword.png - phase_town + phase_town 3 units/spartans/infantry_swordsman_c.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/rome/champion_infantry_spear_gladiator.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/units/rome/champion_infantry_spear_gladiator.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/units/rome/champion_infantry_spear_gladiator.xml (revision 27505) @@ -1,49 +1,49 @@ structures/rome/army_camp structures/rome/temple_vesta -10 20 5 Gladiator rome latin Gladiator Spearman Hoplomachus Elite units/rome/champion_infantry_gladiator_spear.png - phase_town + phase_town -2 Gladiator 1.5 1.5 0.5 units/romans/infantry_gladiator_spearman.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/sele/cavalry_archer_b.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/units/sele/cavalry_archer_b.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/units/sele/cavalry_archer_b.xml (revision 27505) @@ -1,20 +1,20 @@ sele greek units/sele/cavalry_archer_b Dahae Horse Archer Hippotoxotès Dahae units/pers/cavalry_archer.png - phase_town + phase_town units/sele/cavalry_archer_a units/persians/cavalry_archer_b_m.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/sele/infantry_archer_merc_b.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/units/sele/infantry_archer_merc_b.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/units/sele/infantry_archer_merc_b.xml (revision 27505) @@ -1,20 +1,20 @@ sele greek units/sele/infantry_archer_merc_b Syrian Archer Toxótēs Syrías units/sele/infantry_archer.png - phase_town + phase_town units/sele/infantry_archer_merc_a units/seleucids/infantry_archer_b.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/spart/cavalry_spearman_b.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/units/spart/cavalry_spearman_b.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/units/spart/cavalry_spearman_b.xml (revision 27505) @@ -1,20 +1,20 @@ spart greek units/spart/cavalry_spearman_b Greek Allied Cavalry Hippeús Symmakhikós units/spart/cavalry_spearman.png - phase_town + phase_town units/spart/cavalry_spearman_a units/spartans/cavalry_spearman_b_m.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/rome/support_female_citizen_house.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/units/rome/support_female_citizen_house.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/units/rome/support_female_citizen_house.xml (revision 27505) @@ -1,11 +1,11 @@ 30 - unlock_females_house + unlock_females_house Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/sele/champion_infantry_swordsman.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/units/sele/champion_infantry_swordsman.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/units/sele/champion_infantry_swordsman.xml (revision 27505) @@ -1,16 +1,16 @@ sele greek Romanized Heavy Swordsman Thorakitès Rhomaïkós units/sele/champion_swordsman.png - reformed_army_sele + -phase_city reformed_army_sele units/seleucids/infantry_swordsman_c.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/sele/support_female_citizen_house.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/units/sele/support_female_citizen_house.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/units/sele/support_female_citizen_house.xml (revision 27505) @@ -1,11 +1,11 @@ 30 - unlock_females_house + unlock_females_house Index: ps/trunk/source/tools/entity/checkrefs.py =================================================================== --- ps/trunk/source/tools/entity/checkrefs.py (revision 27504) +++ ps/trunk/source/tools/entity/checkrefs.py (revision 27505) @@ -1,685 +1,686 @@ #!/usr/bin/env python3 from argparse import ArgumentParser from io import BytesIO from json import load, loads from pathlib import Path from re import split, match from struct import unpack, calcsize from os.path import sep, exists, basename from xml.etree import ElementTree import sys from scriptlib import SimulTemplateEntity, find_files from logging import WARNING, getLogger, StreamHandler, INFO, Formatter, Filter class SingleLevelFilter(Filter): def __init__(self, passlevel, reject): self.passlevel = passlevel self.reject = reject def filter(self, record): if self.reject: return (record.levelno != self.passlevel) else: return (record.levelno == self.passlevel) class CheckRefs: def __init__(self): # list of relative root file:str self.files = [] # list of relative file:str self.roots = [] # list of tuple (parent_file:str, dep_file:str) self.deps = [] self.vfs_root = Path(__file__).resolve().parents[3] / 'binaries' / 'data' / 'mods' self.supportedTextureFormats = ('dds', 'png') self.supportedMeshesFormats = ('pmd', 'dae') self.supportedAnimationFormats = ('psa', 'dae') self.supportedAudioFormats = ('ogg') self.mods = [] self.__init_logger @property def __init_logger(self): logger = getLogger(__name__) logger.setLevel(INFO) # create a console handler, seems nicer to Windows and for future uses ch = StreamHandler(sys.stdout) ch.setLevel(INFO) ch.setFormatter(Formatter('%(levelname)s - %(message)s')) f1 = SingleLevelFilter(INFO, False) ch.addFilter(f1) logger.addHandler(ch) errorch = StreamHandler(sys.stderr) errorch.setLevel(WARNING) errorch.setFormatter(Formatter('%(levelname)s - %(message)s')) logger.addHandler(errorch) self.logger = logger def main(self): ap = ArgumentParser(description="Checks the game files for missing dependencies, unused files," " and for file integrity.") ap.add_argument('-u', '--check-unused', action='store_true', help="check for all the unused files in the given mods and their dependencies." " Implies --check-map-xml. Currently yields a lot of false positives.") ap.add_argument('-x', '--check-map-xml', action='store_true', help="check maps for missing actor and templates.") ap.add_argument('-a', '--validate-actors', action='store_true', help="run the validator.py script to check if the actors files have extra or missing textures." " This currently only works for the public mod.") ap.add_argument('-t', '--validate-templates', action='store_true', help="run the validator.py script to check if the xml files match their (.rng) grammar file.") ap.add_argument('-m', '--mods', metavar="MOD", dest='mods', nargs='+', default=['public'], help="specify which mods to check. Default to public.") args = ap.parse_args() # force check_map_xml if check_unused is used to avoid false positives. args.check_map_xml |= args.check_unused # ordered uniq mods (dict maintains ordered keys from python 3.6) self.mods = list(dict.fromkeys([*args.mods, *self.get_mod_dependencies(*args.mods), 'mod']).keys()) self.logger.info(f"Checking {'|'.join(args.mods)}'s integrity.") self.logger.info(f"The following mods will be loaded: {'|'.join(self.mods)}.") if args.check_map_xml: self.add_maps_xml() self.add_maps_pmp() self.add_entities() self.add_actors() self.add_variants() self.add_art() self.add_materials() self.add_particles() self.add_soundgroups() self.add_audio() self.add_gui_xml() self.add_gui_data() self.add_civs() self.add_rms() self.add_techs() self.add_terrains() self.add_auras() self.add_tips() self.check_deps() if args.check_unused: self.check_unused() if args.validate_templates: sys.path.append("../xmlvalidator/") from validate_grammar import RelaxNGValidator validate = RelaxNGValidator(self.vfs_root, self.mods) validate.run() if args.validate_actors: sys.path.append("../xmlvalidator/") from validator import Validator validator = Validator(self.vfs_root, self.mods) validator.run() def get_mod_dependencies(self, *mods): modjsondeps = [] for mod in mods: mod_json_path = self.vfs_root / mod / 'mod.json' if not exists(mod_json_path): continue with open(mod_json_path, encoding='utf-8') as f: modjson = load(f) # 0ad's folder isn't named like the mod. modjsondeps.extend(['public' if '0ad' in dep else dep for dep in modjson.get('dependencies', [])]) return modjsondeps def vfs_to_relative_to_mods(self, vfs_path): for dep in self.mods: fn = Path(dep) / vfs_path if (self.vfs_root / fn).exists(): return fn return None def vfs_to_physical(self, vfs_path): fn = self.vfs_to_relative_to_mods(vfs_path) return self.vfs_root / fn def find_files(self, vfs_path, *ext_list): return find_files(self.vfs_root, self.mods, vfs_path, *ext_list) def add_maps_xml(self): self.logger.info("Loading maps XML...") mapfiles = self.find_files('maps/scenarios', 'xml') mapfiles.extend(self.find_files('maps/skirmishes', 'xml')) mapfiles.extend(self.find_files('maps/tutorials', 'xml')) actor_prefix = 'actor|' resource_prefix = 'resource|' for (fp, ffp) in sorted(mapfiles): self.files.append(str(fp)) self.roots.append(str(fp)) et_map = ElementTree.parse(ffp).getroot() entities = et_map.find('Entities') used = {entity.find('Template').text.strip() for entity in entities.findall('Entity')} if entities is not None else {} for template in used: if template.startswith(actor_prefix): self.deps.append((str(fp), f'art/actors/{template[len(actor_prefix):]}')) elif template.startswith(resource_prefix): self.deps.append((str(fp), f'simulation/templates/{template[len(resource_prefix):]}.xml')) else: self.deps.append((str(fp), f'simulation/templates/{template}.xml')) # Map previews settings = loads(et_map.find('ScriptSettings').text) if settings.get('Preview', None): self.deps.append((str(fp), f'art/textures/ui/session/icons/mappreview/{settings["Preview"]}')) def add_maps_pmp(self): self.logger.info("Loading maps PMP...") # Need to generate terrain texture filename=>relative path lookup first terrains = dict() for (fp, ffp) in self.find_files('art/terrains', 'xml'): name = fp.stem # ignore terrains.xml if name != 'terrains': if name in terrains: self.logger.warning(f"Duplicate terrain name '{name}' (from '{terrains[name]}' and '{ffp}')") terrains[name] = str(fp) mapfiles = self.find_files('maps/scenarios', 'pmp') mapfiles.extend(self.find_files('maps/skirmishes', 'pmp')) for (fp, ffp) in sorted(mapfiles): self.files.append(str(fp)) self.roots.append(str(fp)) with open(ffp, 'rb') as f: expected_header = b'PSMP' header = f.read(len(expected_header)) if header != expected_header: raise ValueError(f"Invalid PMP header {header} in '{ffp}'") int_fmt = ' 0: recursionDepth -= 1 allReqTag = req.find('All') if allReqTag is not None: parse_requirements(allReqTag, recursionDepth) anyReqTag = req.find('Any') if anyReqTag is not None: parse_requirements(anyReqTag, recursionDepth) parse_requirements(reqTag) cmp_researcher = entity.find('Researcher') if cmp_researcher is not None: techString = cmp_researcher.find('Technologies') if techString is not None: for tech in split(r'\s+', techString.text): if not tech: continue if tech.startswith('-'): continue if '{civ}' in tech and cmp_identity is not None and cmp_identity.find('Civ') is not None: civ = cmp_identity.find('Civ').text # Fallback for non specific phase techs. if tech.startswith('phase') and not bool([phase_tech for phase_tech in custom_phase_techs if (tech.replace('{civ}', civ) + ".json") == phase_tech]) : civ = 'generic' tech = tech.replace('{civ}', civ) self.deps.append((str(fp), f'simulation/data/technologies/{tech}.json')) def append_variant_dependencies(self, variant, fp): variant_file = variant.get('file') mesh = variant.find('mesh') particles = variant.find('particles') texture_files = [tex.get('file') for tex in variant.find('textures').findall('texture')] \ if variant.find('textures') is not None else [] prop_actors = [prop.get('actor') for prop in variant.find('props').findall('prop')] \ if variant.find('props') is not None else [] animation_files = [anim.get('file') for anim in variant.find('animations').findall('animation')] \ if variant.find('animations') is not None else [] if variant_file: self.deps.append((str(fp), f'art/variants/{variant_file}')) if mesh is not None and mesh.text: self.deps.append((str(fp), f'art/meshes/{mesh.text}')) if particles is not None and particles.get('file'): self.deps.append((str(fp), f'art/particles/{particles.get("file")}')) for texture_file in [x for x in texture_files if x]: self.deps.append((str(fp), f'art/textures/skins/{texture_file}')) for prop_actor in [x for x in prop_actors if x]: self.deps.append((str(fp), f'art/actors/{prop_actor}')) for animation_file in [x for x in animation_files if x]: self.deps.append((str(fp), f'art/animation/{animation_file}')) def append_actor_dependencies(self, actor, fp): for group in actor.findall('group'): for variant in group.findall('variant'): self.append_variant_dependencies(variant, fp) material = actor.find('material') if material is not None and material.text: self.deps.append((str(fp), f'art/materials/{material.text}')) def add_actors(self): self.logger.info("Loading actors...") for (fp, ffp) in sorted(self.find_files('art/actors', 'xml')): self.files.append(str(fp)) self.roots.append(str(fp)) root = ElementTree.parse(ffp).getroot() if root.tag == 'actor': self.append_actor_dependencies(root, fp) # model has lods elif root.tag == 'qualitylevels': qualitylevels = root for actor in qualitylevels.findall('actor'): self.append_actor_dependencies(actor, fp) for actor in qualitylevels.findall('inline'): self.append_actor_dependencies(actor, fp) def add_variants(self): self.logger.info("Loading variants...") for (fp, ffp) in sorted(self.find_files('art/variants', 'xml')): self.files.append(str(fp)) self.roots.append(str(fp)) variant = ElementTree.parse(ffp).getroot() self.append_variant_dependencies(variant, fp) def add_art(self): self.logger.info("Loading art files...") self.files.extend([str(fp) for (fp, ffp) in self.find_files('art/textures/particles', *self.supportedTextureFormats)]) self.files.extend([str(fp) for (fp, ffp) in self.find_files('art/textures/terrain', *self.supportedTextureFormats)]) self.files.extend([str(fp) for (fp, ffp) in self.find_files('art/textures/skins', *self.supportedTextureFormats)]) self.files.extend([str(fp) for (fp, ffp) in self.find_files('art/meshes', *self.supportedMeshesFormats)]) self.files.extend([str(fp) for (fp, ffp) in self.find_files('art/animation', *self.supportedAnimationFormats)]) def add_materials(self): self.logger.info("Loading materials...") for (fp, ffp) in sorted(self.find_files('art/materials', 'xml')): self.files.append(str(fp)) material_elem = ElementTree.parse(ffp).getroot() for alternative in material_elem.findall('alternative'): material = alternative.get('material') if material: self.deps.append((str(fp), f'art/materials/{material}')) def add_particles(self): self.logger.info("Loading particles...") for (fp, ffp) in sorted(self.find_files('art/particles', 'xml')): self.files.append(str(fp)) self.roots.append(str(fp)) particle = ElementTree.parse(ffp).getroot() texture = particle.find('texture') if texture: self.deps.append((str(fp), texture.text)) def add_soundgroups(self): self.logger.info("Loading sound groups...") for (fp, ffp) in sorted(self.find_files('audio', 'xml')): self.files.append(str(fp)) self.roots.append(str(fp)) sound_group = ElementTree.parse(ffp).getroot() path = sound_group.find('Path').text.rstrip('/') for sound in sound_group.findall('Sound'): self.deps.append((str(fp), f'{path}/{sound.text}')) def add_audio(self): self.logger.info("Loading audio files...") self.files.extend([str(fp) for (fp, ffp) in self.find_files('audio/', self.supportedAudioFormats)]) def add_gui_object_repeat(self, obj, fp): for repeat in obj.findall('repeat'): for sub_obj in repeat.findall('object'): # TODO: look at sprites, styles, etc self.add_gui_object_include(sub_obj, fp) for sub_obj in repeat.findall('objects'): # TODO: look at sprites, styles, etc self.add_gui_object_include(sub_obj, fp) self.add_gui_object_include(repeat, fp) def add_gui_object_include(self, obj, fp): for include in obj.findall('include'): included_file = include.get('file') if included_file: self.deps.append((str(fp), f'{included_file}')) def add_gui_object(self, parent, fp): if parent is None: return for obj in parent.findall('object'): # TODO: look at sprites, styles, etc self.add_gui_object_repeat(obj, fp) self.add_gui_object_include(obj, fp) self.add_gui_object(obj, fp) for obj in parent.findall('objects'): # TODO: look at sprites, styles, etc self.add_gui_object_repeat(obj, fp) self.add_gui_object_include(obj, fp) self.add_gui_object(obj, fp) def add_gui_xml(self): self.logger.info("Loading GUI XML...") for (fp, ffp) in sorted(self.find_files('gui', 'xml')): self.files.append(str(fp)) # GUI page definitions are assumed to be named page_[something].xml and alone in that. if match(r".*[\\\/]page(_[^.\/\\]+)?\.xml$", str(fp)): self.roots.append(str(fp)) root_xml = ElementTree.parse(ffp).getroot() for include in root_xml.findall('include'): # If including an entire directory, find all the *.xml files if include.text.endswith('/'): self.deps.extend([(str(fp), str(sub_fp)) for (sub_fp, sub_ffp) in self.find_files(f'gui/{include.text}', 'xml')]) else: self.deps.append((str(fp), f'gui/{include.text}')) else: xml = ElementTree.parse(ffp) root_xml = xml.getroot() name = root_xml.tag self.roots.append(str(fp)) if name in ('objects', 'object'): for script in root_xml.findall('script'): if script.get('file'): self.deps.append((str(fp), script.get('file'))) if script.get('directory'): # If including an entire directory, find all the *.js files self.deps.extend([(str(fp), str(sub_fp)) for (sub_fp, sub_ffp) in self.find_files(script.get('directory'), 'js')]) self.add_gui_object(root_xml, fp) elif name == 'setup': # TODO: look at sprites, styles, etc pass elif name == 'styles': for style in root_xml.findall('style'): if(style.get('sound_opened')): self.deps.append((str(fp), f"{style.get('sound_opened')}")) if(style.get('sound_closed')): self.deps.append((str(fp), f"{style.get('sound_closed')}")) if(style.get('sound_selected')): self.deps.append((str(fp), f"{style.get('sound_selected')}")) if(style.get('sound_disabled')): self.deps.append((str(fp), f"{style.get('sound_disabled')}")) # TODO: look at sprites, styles, etc pass elif name == 'sprites': for sprite in root_xml.findall('sprite'): for image in sprite.findall('image'): if image.get('texture'): self.deps.append((str(fp), f"art/textures/ui/{image.get('texture')}")) else: bio = BytesIO() xml.write(bio) bio.seek(0) raise ValueError(f"Unexpected GUI XML root element '{name}':\n{bio.read().decode('ascii')}") def add_gui_data(self): self.logger.info("Loading GUI data...") self.files.extend([str(fp) for (fp, ffp) in self.find_files('gui', 'js')]) self.files.extend([str(fp) for (fp, ffp) in self.find_files('gamesettings', 'js')]) self.files.extend([str(fp) for (fp, ffp) in self.find_files('autostart', 'js')]) self.roots.extend([str(fp) for (fp, ffp) in self.find_files('autostart', 'js')]) self.files.extend([str(fp) for (fp, ffp) in self.find_files('art/textures/ui', *self.supportedTextureFormats)]) self.files.extend([str(fp) for (fp, ffp) in self.find_files('art/textures/selection', *self.supportedTextureFormats)]) def add_civs(self): self.logger.info("Loading civs...") for (fp, ffp) in sorted(self.find_files('simulation/data/civs', 'json')): self.files.append(str(fp)) self.roots.append(str(fp)) with open(ffp, encoding='utf-8') as f: civ = load(f) for music in civ.get('Music', []): self.deps.append((str(fp), f"audio/music/{music['File']}")) def add_tips(self): self.logger.info("Loading tips...") for (fp, ffp) in sorted(self.find_files('gui/text/tips', 'txt')): relative_path = str(fp) self.files.append(relative_path) self.roots.append(relative_path) self.deps.append((relative_path, f"art/textures/ui/loading/tips/{basename(relative_path).split('.')[0]}.png")) def add_rms(self): self.logger.info("Loading random maps...") self.files.extend([str(fp) for (fp, ffp) in self.find_files('maps/random', 'js')]) for (fp, ffp) in sorted(self.find_files('maps/random', 'json')): if str(fp).startswith('maps/random/rmbiome'): continue self.files.append(str(fp)) self.roots.append(str(fp)) with open(ffp, encoding='utf-8') as f: randmap = load(f) settings = randmap.get('settings', {}) if settings.get('Script', None): self.deps.append((str(fp), f"maps/random/{settings['Script']}")) # Map previews if settings.get('Preview', None): self.deps.append((str(fp), f'art/textures/ui/session/icons/mappreview/{settings["Preview"]}')) def add_techs(self): self.logger.info("Loading techs...") for (fp, ffp) in sorted(self.find_files('simulation/data/technologies', 'json')): self.files.append(str(fp)) with open(ffp, encoding='utf-8') as f: tech = load(f) if tech.get('autoResearch', None): self.roots.append(str(fp)) if tech.get('icon', None): self.deps.append((str(fp), f"art/textures/ui/session/portraits/technologies/{tech['icon']}")) if tech.get('supersedes', None): self.deps.append((str(fp), f"simulation/data/technologies/{tech['supersedes']}.json")) if tech.get('top', None): self.deps.append((str(fp), f"simulation/data/technologies/{tech['top']}.json")) if tech.get('bottom', None): self.deps.append((str(fp), f"simulation/data/technologies/{tech['bottom']}.json")) def add_terrains(self): self.logger.info("Loading terrains...") for (fp, ffp) in sorted(self.find_files('art/terrains', 'xml')): # ignore terrains.xml if str(fp).endswith('terrains.xml'): continue self.files.append(str(fp)) self.roots.append(str(fp)) terrain = ElementTree.parse(ffp).getroot() for texture in terrain.find('textures').findall('texture'): if texture.get('file'): self.deps.append((str(fp), f"art/textures/terrain/{texture.get('file')}")) if terrain.find('material') is not None: material = terrain.find('material').text self.deps.append((str(fp), f"art/materials/{material}")) def add_auras(self): self.logger.info("Loading auras...") for (fp, ffp) in sorted(self.find_files('simulation/data/auras', 'json')): self.files.append(str(fp)) with open(ffp, encoding='utf-8') as f: aura = load(f) if aura.get('overlayIcon', None): self.deps.append((str(fp), aura['overlayIcon'])) range_overlay = aura.get('rangeOverlay', {}) for prop in ('lineTexture', 'lineTextureMask'): if range_overlay.get(prop, None): self.deps.append((str(fp), f"art/textures/selection/{range_overlay[prop]}")) def check_deps(self): self.logger.info("Looking for missing files...") uniq_files = set(self.files) uniq_files = [r.replace(sep, '/') for r in uniq_files] lower_case_files = {f.lower(): f for f in uniq_files} reverse_deps = dict() for parent, dep in self.deps: if sep != '/': parent = parent.replace(sep, '/') dep = dep.replace(sep, '/') if dep not in reverse_deps: reverse_deps[dep] = {parent} else: reverse_deps[dep].add(parent) for dep in sorted(reverse_deps.keys()): if "simulation/templates" in dep and ( dep.replace("templates/", "template/special/filter/") in uniq_files or dep.replace("templates/", "template/mixins/") in uniq_files ): continue if dep in uniq_files: continue callers = [str(self.vfs_to_relative_to_mods(ref)) for ref in reverse_deps[dep]] self.logger.warning(f"Missing file '{dep}' referenced by: {', '.join(sorted(callers))}") if dep.lower() in lower_case_files: self.logger.warning(f"### Case-insensitive match (found '{lower_case_files[dep.lower()]}')") def check_unused(self): self.logger.info("Looking for unused files...") deps = dict() for parent, dep in self.deps: if sep != '/': parent = parent.replace(sep, '/') dep = dep.replace(sep, '/') if parent not in deps: deps[parent] = {dep} else: deps[parent].add(dep) uniq_files = set(self.files) uniq_files = [r.replace(sep, '/') for r in uniq_files] reachable = list(set(self.roots)) reachable = [r.replace(sep, '/') for r in reachable] while True: new_reachable = [] for r in reachable: new_reachable.extend([x for x in deps.get(r, {}) if x not in reachable]) if new_reachable: reachable.extend(new_reachable) else: break for f in sorted(uniq_files): if any(( f in reachable, 'art/terrains/' in f, 'maps/random/' in f, )): continue self.logger.warning(f"Unused file '{str(self.vfs_to_relative_to_mods(f))}'") if __name__ == '__main__': check_ref = CheckRefs() check_ref.main() Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/rome/infantry_spearman_b.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/units/rome/infantry_spearman_b.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/units/rome/infantry_spearman_b.xml (revision 27505) @@ -1,38 +1,38 @@ structures/rome/army_camp structures/rome/temple_vesta 0.85 0.45 rome latin units/rome/infantry_spearman_b Veteran Spearman Triārius units/rome/infantry_spearman.png - phase_town + phase_town Elite rank Spearmen can be promoted to champion Centurions. units/rome/infantry_spearman_a special/formations/anti_cavalry units/romans/infantry_spearman_b.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/sele/champion_infantry_pikeman.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/units/sele/champion_infantry_pikeman.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/units/sele/champion_infantry_pikeman.xml (revision 27505) @@ -1,16 +1,16 @@ sele greek Silver Shield Argyraspis units/sele/champion_pikeman.png - traditional_army_sele + -phase_city traditional_army_sele units/seleucids/infantry_pikeman_c.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/sele/infantry_swordsman_merc_b.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/units/sele/infantry_swordsman_merc_b.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/units/sele/infantry_swordsman_merc_b.xml (revision 27505) @@ -1,25 +1,25 @@ Rhomphaia sele greek units/sele/infantry_swordsman_merc_b Thracian Mercenary Swordsman Rhomphaiaphoros Thrakikós units/sele/infantry_swordsman.png - phase_town + phase_town units/sele/infantry_swordsman_merc_a units/seleucids/infantry_swordsman_b.xml Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/spart/support_female_citizen_house.xml =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/templates/units/spart/support_female_citizen_house.xml (revision 27504) +++ ps/trunk/binaries/data/mods/public/simulation/templates/units/spart/support_female_citizen_house.xml (revision 27505) @@ -1,11 +1,11 @@ 30 - unlock_females_house + unlock_females_house