Ticket #1432: one_hero_2012_10_23_v2.diff
File one_hero_2012_10_23_v2.diff, 53.4 KB (added by , 12 years ago) |
---|
-
binaries/data/mods/public/gui/session/input.js
1466 1466 var batchTrainingEntities; 1467 1467 var batchTrainingType; 1468 1468 var batchTrainingCount; 1469 var batchTrainingEntityAllowedCount; 1469 1470 const batchIncrementSize = 5; 1470 1471 1471 1472 function flushTrainingBatch() 1472 1473 { 1473 Engine.PostNetworkCommand({"type": "train", "entities": batchTrainingEntities, "template": batchTrainingType, "count": batchTrainingCount}); 1474 var appropriateBuildings = getBuidlingsWhichCanTrainEntity(batchTrainingEntities, batchTrainingType); 1475 // If training limits don't allow us to train batchTrainingCount in each appropriate building 1476 if (batchTrainingEntityAllowedCount !== undefined && batchTrainingEntityAllowedCount < batchTrainingCount * appropriateBuildings.length) 1477 { 1478 // Train as many full batches as we can 1479 var buildingsCountToTrainFullBatch = Math.floor(batchTrainingEntityAllowedCount / batchTrainingCount); 1480 var buildingsToTrainFullBatch = appropriateBuildings.slice(0, buildingsCountToTrainFullBatch); 1481 Engine.PostNetworkCommand({"type": "train", "entities": buildingsToTrainFullBatch, "template": batchTrainingType, "count": batchTrainingCount}); 1482 1483 // Train remainer in one more building 1484 var remainderToTrain = batchTrainingEntityAllowedCount % batchTrainingCount; 1485 Engine.PostNetworkCommand({"type": "train", "entities": [ appropriateBuildings[buildingsCountToTrainFullBatch] ], "template": batchTrainingType, "count": remainderToTrain}); 1486 } 1487 else 1488 { 1489 Engine.PostNetworkCommand({"type": "train", "entities": appropriateBuildings, "template": batchTrainingType, "count": batchTrainingCount}); 1490 } 1474 1491 } 1475 1492 1493 function getBuidlingsWhichCanTrainEntity(entitiesToCheck, trainEntType) 1494 { 1495 return entitiesToCheck.filter(function(entity) { 1496 var state = GetEntityState(entity); 1497 var canTrain = state && state.production && state.production.entities.length && state.production.entities.indexOf(trainEntType) != -1; 1498 return canTrain; 1499 }); 1500 } 1501 1502 function getEntityLimitAndCount(playerState, entType) 1503 { 1504 var template = GetTemplateData(entType); 1505 var trainingCategory = null; 1506 if (template.trainingRestrictions) 1507 trainingCategory = template.trainingRestrictions.category; 1508 var trainEntLimit = undefined; 1509 var trainEntCount = undefined; 1510 var canBeTrainedCount = undefined; 1511 if (trainingCategory && playerState.entityLimits[trainingCategory]) 1512 { 1513 trainEntLimit = playerState.entityLimits[trainingCategory]; 1514 trainEntCount = playerState.entityCounts[trainingCategory]; 1515 canBeTrainedCount = trainEntLimit - trainEntCount; 1516 } 1517 return [trainEntLimit, trainEntCount, canBeTrainedCount]; 1518 } 1519 1476 1520 // Called by GUI when user clicks training button 1477 function addTrainingToQueue(selection, trainEntType )1521 function addTrainingToQueue(selection, trainEntType, playerState) 1478 1522 { 1479 if (Engine.HotkeyIsPressed("session.batchtrain")) 1523 // Create list of buildings which can train trainEntType 1524 var appropriateBuildings = getBuidlingsWhichCanTrainEntity(selection, trainEntType); 1525 1526 // Check trainEntType entity limit and count 1527 var [trainEntLimit, trainEntCount, canBeTrainedCount] = getEntityLimitAndCount(playerState, trainEntType) 1528 1529 // Batch training possible if we can train at least 2 units 1530 var batchTrainingPossible = canBeTrainedCount !== undefined && canBeTrainedCount > 1; 1531 1532 if (Engine.HotkeyIsPressed("session.batchtrain") && batchTrainingPossible) 1480 1533 { 1481 1534 if (inputState == INPUT_BATCHTRAINING) 1482 1535 { … … 1493 1546 } 1494 1547 } 1495 1548 // If we're already creating a batch of this unit (in the same building(s)), then just extend it 1549 // (if training limits allow) 1496 1550 if (sameEnts && batchTrainingType == trainEntType) 1497 1551 { 1498 batchTrainingCount += batchIncrementSize; 1552 if (canBeTrainedCount !== undefined && canBeTrainedCount > batchTrainingCount * appropriateBuildings.length) 1553 batchTrainingCount += batchIncrementSize; 1554 batchTrainingEntityAllowedCount = canBeTrainedCount; 1499 1555 return; 1500 1556 } 1501 1557 // Otherwise start a new one … … 1508 1564 inputState = INPUT_BATCHTRAINING; 1509 1565 batchTrainingEntities = selection; 1510 1566 batchTrainingType = trainEntType; 1567 batchTrainingEntityAllowedCount = canBeTrainedCount; 1511 1568 batchTrainingCount = batchIncrementSize; 1512 1569 } 1513 1570 else 1514 1571 { 1515 // Non-batched - just create a single entity 1516 Engine.PostNetworkCommand({"type": "train", "template": trainEntType, "count": 1, "entities": selection}); 1572 // Non-batched - just create a single entity in each building 1573 // (but no more than entity limit allows) 1574 var buildingsForTraining = appropriateBuildings; 1575 if (trainEntLimit) 1576 buildingsForTraining = buildingsForTraining.slice(0, canBeTrainedCount); 1577 Engine.PostNetworkCommand({"type": "train", "template": trainEntType, "count": 1, "entities": buildingsForTraining}); 1517 1578 } 1518 1579 } 1519 1580 … … 1525 1586 1526 1587 // Returns the number of units that will be present in a batch if the user clicks 1527 1588 // the training button with shift down 1528 function getTrainingBatchStatus( entity, trainEntType)1589 function getTrainingBatchStatus(playerState, entity, trainEntType, selection) 1529 1590 { 1591 var apporpriateBuildings = [entity]; 1592 if (selection && selection.indexOf(entity) != -1) 1593 appropriateBuildings = getBuidlingsWhichCanTrainEntity(selection, trainEntType); 1594 var nextBatchTrainingCount = 0; 1530 1595 if (inputState == INPUT_BATCHTRAINING && batchTrainingEntities.indexOf(entity) != -1 && batchTrainingType == trainEntType) 1531 return [batchTrainingCount, batchIncrementSize]; 1596 { 1597 nextBatchTrainingCount = batchTrainingCount; 1598 var canBeTrainedCount = batchTrainingEntityAllowedCount; 1599 } 1532 1600 else 1533 return [0, batchIncrementSize]; 1601 { 1602 var [trainEntLimit, trainEntCount, canBeTrainedCount] = getEntityLimitAndCount(playerState, trainEntType); 1603 var batchSize = Math.min(canBeTrainedCount, batchIncrementSize); 1604 } 1605 // We need to calculate count after the next increment if it's possible 1606 if (canBeTrainedCount == undefined || canBeTrainedCount > nextBatchTrainingCount * appropriateBuildings.length) 1607 nextBatchTrainingCount += batchIncrementSize; 1608 // If training limits don't allow us to train batchTrainingCount in each appropriate building 1609 // train as many full batches as we can and remainer in one more building. 1610 var buildingsCountToTrainFullBatch = appropriateBuildings.length; 1611 var remainderToTrain = 0; 1612 if (canBeTrainedCount !== undefined && canBeTrainedCount < nextBatchTrainingCount * appropriateBuildings.length) 1613 { 1614 buildingsCountToTrainFullBatch = Math.floor(canBeTrainedCount / nextBatchTrainingCount); 1615 remainderToTrain = canBeTrainedCount % nextBatchTrainingCount; 1616 } 1617 return [buildingsCountToTrainFullBatch, nextBatchTrainingCount, remainderToTrain]; 1534 1618 } 1535 1619 1536 1620 // Called by GUI when user clicks production queue item -
binaries/data/mods/public/gui/session/unit_commands.js
139 139 } 140 140 141 141 /** 142 * Format batch training string for tooltip 143 * Examples: 144 * buildingsCountToTrainFullBatch = 1, fullBatchSize = 5, remainderBatch = 0: 145 * "Shift-click to train 5" 146 * buildingsCountToTrainFullBatch = 2, fullBatchSize = 5, remainderBatch = 0: 147 * "Shift-click to train 10 (2*5)" 148 * buildingsCountToTrainFullBatch = 1, fullBatchSize = 15, remainderBatch = 12: 149 * "Shift-click to train 27 (15 + 12)" 150 */ 151 function formatBatchTrainingString(buildingsCountToTrainFullBatch, fullBatchSize, remainderBatch) 152 { 153 var totalBatchTrainingCount = buildingsCountToTrainFullBatch * fullBatchSize + remainderBatch; 154 // Don't show the batch training tooltip if either units of this type can't be trained at all 155 // or only one unit can be trained 156 if (totalBatchTrainingCount < 2) 157 return ""; 158 var batchTrainingString = ""; 159 var fullBatchesString = ""; 160 if (buildingsCountToTrainFullBatch > 0) 161 { 162 if (buildingsCountToTrainFullBatch > 1) 163 fullBatchesString += buildingsCountToTrainFullBatch + "*"; 164 fullBatchesString += fullBatchSize; 165 } 166 var remainderBatchString = remainderBatch > 0 ? remainderBatch : ""; 167 var batchDetailsString = buildingsCountToTrainFullBatch > 1 || (buildingsCountToTrainFullBatch == 1 && remainderBatch > 0) ? 168 " (" + [fullBatchesString, remainderBatchString].filter(function(string) { return string != "" }).join(" + ") + ")" : 169 ""; 170 return "\n\n[font=\"serif-bold-13\"]Shift-click[/font][font=\"serif-13\"] to train " 171 + totalBatchTrainingCount + batchDetailsString + ".[/font]"; 172 } 173 174 /** 142 175 * Helper function for updateUnitCommands; sets up "unit panels" (i.e. panels with rows of icons) for the currently selected 143 176 * unit. 144 177 * … … 150 183 * @param items Panel-specific data to construct the icons with. 151 184 * @param callback Callback function to argument to execute when an item's icon gets clicked. Takes a single 'item' argument. 152 185 */ 153 function setupUnitPanel(guiName, usedPanels, unitEntState, items, callback)186 function setupUnitPanel(guiName, usedPanels, unitEntState, playerState, items, callback) 154 187 { 155 188 usedPanels[guiName] = 1; 156 189 … … 374 407 if (template.tooltip) 375 408 tooltip += "\n[font=\"serif-13\"]" + template.tooltip + "[/font]"; 376 409 377 var [batchSize, batchIncrement] = getTrainingBatchStatus(unitEntState.id, entType); 378 var trainNum = batchSize ? batchSize+batchIncrement : batchIncrement; 410 var [buildingsCountToTrainFullBatch, fullBatchSize, remainderBatch] = getTrainingBatchStatus(playerState, unitEntState.id, entType, selection); 379 411 380 412 tooltip += "\n" + getEntityCostTooltip(template); 381 413 … … 388 420 if (template.speed) 389 421 tooltip += "\n" + getEntitySpeed(template); 390 422 391 tooltip += "\n\n[font=\"serif-bold-13\"]Shift-click[/font][font=\"serif-13\"] to train " + trainNum + ".[/font]"; 392 423 tooltip += formatBatchTrainingString(buildingsCountToTrainFullBatch, fullBatchSize, remainderBatch); 393 424 break; 394 425 395 426 case RESEARCH: … … 627 658 pair.hidden = true; 628 659 button1.hidden = true; 629 660 affordableMask1.hidden = true; 630 661 } 631 662 } 632 663 else if (guiName == CONSTRUCTION || guiName == TRAINING) 633 664 { 665 if (guiName == TRAINING) 666 { 667 var trainingCategory = null; 668 if (template.trainingRestrictions) 669 trainingCategory = template.trainingRestrictions.category; 670 var grayscale = ""; 671 if (trainingCategory && playerState.entityLimits[trainingCategory] && playerState.entityCounts[trainingCategory] >= playerState.entityLimits[trainingCategory]) 672 grayscale = "grayscale:"; 673 icon.sprite = "stretched:" + grayscale + "session/portraits/" + template.icon; 674 } 675 634 676 affordableMask.hidden = true; 635 677 var totalCosts = {}; 636 678 var trainNum = 1; 637 679 if (Engine.HotkeyIsPressed("session.batchtrain") && guiName == TRAINING) 638 680 { 639 var [b atchSize, batchIncrement] = getTrainingBatchStatus(unitEntState.id, entType);640 trainNum = b atchSize + batchIncrement;681 var [buildingsCountToTrainFullBatch, fullBatchSize, remainderBatch] = getTrainingBatchStatus(playerState, unitEntState.id, entType, selection); 682 trainNum = buildingsCountToTrainFullBatch * fullBatchSize + remainderBatch; 641 683 } 642 684 643 685 // Walls have no cost defined. … … 767 809 } 768 810 769 811 // Sets up "unit barter panel" - special case for setupUnitPanel 770 function setupUnitBarterPanel(unitEntState )812 function setupUnitBarterPanel(unitEntState, playerState) 771 813 { 772 814 // Amount of player's resource to exchange 773 815 var amountToSell = BARTER_RESOURCE_AMOUNT_TO_SELL; … … 862 904 var player = Engine.GetPlayerID(); 863 905 if (entState.player == player || g_DevSettings.controlAll) 864 906 { 907 // Get player state to check some constraints 908 // e.g. presence of a hero or build limits 909 var simState = Engine.GuiInterfaceCall("GetSimulationState"); 910 var playerState = simState.players[player]; 911 865 912 if (selection.length > 1) 866 setupUnitPanel(SELECTION, usedPanels, entState, g_Selection.groups.getTemplateNames(),913 setupUnitPanel(SELECTION, usedPanels, entState, playerState, g_Selection.groups.getTemplateNames(), 867 914 function (entType) { changePrimarySelectionGroup(entType); } ); 868 915 869 916 var commands = getEntityCommandsList(entState); 870 917 if (commands.length) 871 setupUnitPanel(COMMAND, usedPanels, entState, commands,918 setupUnitPanel(COMMAND, usedPanels, entState, playerState, commands, 872 919 function (item) { performCommand(entState.id, item.name); } ); 873 920 874 921 if (entState.garrisonHolder) … … 881 928 groups.add(state.garrisonHolder.entities) 882 929 } 883 930 884 setupUnitPanel(GARRISON, usedPanels, entState, groups.getTemplateNames(),931 setupUnitPanel(GARRISON, usedPanels, entState, playerState, groups.getTemplateNames(), 885 932 function (item) { unloadTemplate(item); } ); 886 933 } 887 934 888 935 var formations = Engine.GuiInterfaceCall("GetAvailableFormations"); 889 936 if (hasClass(entState, "Unit") && !hasClass(entState, "Animal") && !entState.garrisonHolder && formations.length) 890 937 { 891 setupUnitPanel(FORMATION, usedPanels, entState, formations,938 setupUnitPanel(FORMATION, usedPanels, entState, playerState, formations, 892 939 function (item) { performFormation(entState.id, item); } ); 893 940 } 894 941 … … 897 944 var stances = ["violent", "aggressive", "passive", "defensive", "standground"]; 898 945 if (hasClass(entState, "Unit") && !hasClass(entState, "Animal") && stances.length) 899 946 { 900 setupUnitPanel(STANCE, usedPanels, entState, stances,947 setupUnitPanel(STANCE, usedPanels, entState, playerState, stances, 901 948 function (item) { performStance(entState.id, item); } ); 902 949 } 903 950 … … 905 952 if (entState.barterMarket) 906 953 { 907 954 usedPanels["Barter"] = 1; 908 setupUnitBarterPanel(entState );955 setupUnitBarterPanel(entState, playerState); 909 956 } 910 957 911 958 var buildableEnts = []; … … 929 976 930 977 // The first selected entity's type has priority. 931 978 if (entState.buildEntities) 932 setupUnitPanel(CONSTRUCTION, usedPanels, entState, buildableEnts, startBuildingPlacement);979 setupUnitPanel(CONSTRUCTION, usedPanels, entState, playerState, buildableEnts, startBuildingPlacement); 933 980 else if (entState.production && entState.production.entities) 934 setupUnitPanel(TRAINING, usedPanels, entState, trainableEnts,935 function (trainEntType) { addTrainingToQueue(selection, trainEntType ); } );981 setupUnitPanel(TRAINING, usedPanels, entState, playerState, trainableEnts, 982 function (trainEntType) { addTrainingToQueue(selection, trainEntType, playerState); } ); 936 983 else if (entState.trader) 937 984 setupUnitTradingPanel(usedPanels, entState, selection); 938 985 else if (!entState.foundation && entState.gate || hasClass(entState, "LongWall")) … … 994 1041 setupUnitPanel(CONSTRUCTION, usedPanels, entState, buildableEnts, startBuildingPlacement); 995 1042 else if (trainableEnts.length) 996 1043 setupUnitPanel(TRAINING, usedPanels, entState, trainableEnts, 997 function (trainEntType) { addTrainingToQueue(selection, trainEntType ); } );1044 function (trainEntType) { addTrainingToQueue(selection, trainEntType, playerState); } ); 998 1045 } 999 1046 1000 1047 // Show technologies if the active panel has at most one row of icons. … … 1007 1054 } 1008 1055 1009 1056 if (entState.production && entState.production.queue.length) 1010 setupUnitPanel(QUEUE, usedPanels, entState, entState.production.queue,1057 setupUnitPanel(QUEUE, usedPanels, entState, playerState, entState.production.queue, 1011 1058 function (item) { removeFromProductionQueue(entState.id, item.id); } ); 1012 1059 1013 1060 supplementalDetailsPanel.hidden = false; -
binaries/data/mods/public/simulation/ai/jubot/gamestate.js
416 416 * Returns player build limits 417 417 * an object where each key is a category corresponding to a build limit for the player. 418 418 */ 419 get BuildLimits: function()419 getEntityLimits: function() 420 420 { 421 return this.playerData. buildLimits;421 return this.playerData.entityLimits; 422 422 }, 423 423 424 424 /** 425 425 * Returns player build counts 426 426 * an object where each key is a category corresponding to the current building count for the player. 427 427 */ 428 get BuildCounts: function()428 getEntityCounts: function() 429 429 { 430 return this.playerData. buildCounts;430 return this.playerData.entityCounts; 431 431 }, 432 432 433 433 /** 434 434 * Checks if the player's build limit has been reached for the given category. 435 435 * The category comes from the entity tenplate, specifically the BuildRestrictions component. 436 436 */ 437 is BuildLimitReached: function(category)437 isEntityLimitReached: function(category) 438 438 { 439 if (this.playerData. buildLimits[category] === undefined || this.playerData.buildCounts[category] === undefined)439 if (this.playerData.entityLimits[category] === undefined || this.playerData.entityCounts[category] === undefined) 440 440 return false; 441 441 442 442 // There's a special case of build limits per civ centre, so check that first 443 if (this.playerData. buildLimits[category].LimitPerCivCentre !== undefined)444 return (this.playerData. buildCounts[category] >= this.playerData.buildCounts["CivilCentre"]*this.playerData.buildLimits[category].LimitPerCivCentre);443 if (this.playerData.entityLimits[category].LimitPerCivCentre !== undefined) 444 return (this.playerData.entityCounts[category] >= this.playerData.entityCounts["CivilCentre"]*this.playerData.entityLimits[category].LimitPerCivCentre); 445 445 else 446 return (this.playerData. buildCounts[category] >= this.playerData.buildLimits[category]);446 return (this.playerData.entityCounts[category] >= this.playerData.entityLimits[category]); 447 447 }, 448 448 }); -
binaries/data/mods/public/simulation/ai/qbot/gamestate.js
303 303 return this.updatingCollection("resource-" + resource, Filters.byResource(resource), this.getEntities()); 304 304 }; 305 305 306 GameState.prototype.get BuildLimits = function() {307 return this.playerData. buildLimits;306 GameState.prototype.getEntityLimits = function() { 307 return this.playerData.entityLimits; 308 308 }; 309 309 310 GameState.prototype.get BuildCounts = function() {311 return this.playerData. buildCounts;310 GameState.prototype.getEntityCounts = function() { 311 return this.playerData.entityCounts; 312 312 }; 313 313 314 314 // Checks whether the maximum number of buildings have been cnstructed for a certain catergory 315 GameState.prototype.is BuildLimitReached = function(category) {316 if(this.playerData. buildLimits[category] === undefined || this.playerData.buildCounts[category] === undefined)315 GameState.prototype.isEntityLimitReached = function(category) { 316 if(this.playerData.entityLimits[category] === undefined || this.playerData.entityCounts[category] === undefined) 317 317 return false; 318 if(this.playerData. buildLimits[category].LimitsPerCivCentre != undefined)319 return (this.playerData. buildCounts[category] >= this.playerData.buildCounts["CivilCentre"]*this.playerData.buildLimits[category].LimitPerCivCentre);318 if(this.playerData.entityLimits[category].LimitsPerCivCentre != undefined) 319 return (this.playerData.entityCounts[category] >= this.playerData.entityCounts["CivilCentre"]*this.playerData.entityLimits[category].LimitPerCivCentre); 320 320 else 321 return (this.playerData. buildCounts[category] >= this.playerData.buildLimits[category]);321 return (this.playerData.entityCounts[category] >= this.playerData.entityLimits[category]); 322 322 }; -
binaries/data/mods/public/simulation/ai/qbot/military.js
324 324 // Adds towers to the defenceBuilding queue 325 325 MilitaryAttackManager.prototype.buildDefences = function(gameState, queues){ 326 326 if (gameState.countEntitiesAndQueuedByType(gameState.applyCiv('structures/{civ}_defense_tower')) 327 + queues.defenceBuilding.totalLength() < gameState.get BuildLimits()["DefenseTower"]) {327 + queues.defenceBuilding.totalLength() < gameState.getEntityLimits()["DefenseTower"]) { 328 328 329 329 330 330 gameState.getOwnEntities().forEach(function(dropsiteEnt) { … … 343 343 numFortresses += gameState.countEntitiesAndQueuedByType(gameState.applyCiv(this.bFort[i])); 344 344 } 345 345 346 if (numFortresses + queues.defenceBuilding.totalLength() < gameState.get BuildLimits()["Fortress"]) {346 if (numFortresses + queues.defenceBuilding.totalLength() < gameState.getEntityLimits()["Fortress"]) { 347 347 if (gameState.countEntitiesByType(gameState.applyCiv("units/{civ}_support_female_citizen")) > gameState.ai.modules["economy"].targetNumWorkers * 0.5){ 348 348 if (gameState.getTimeElapsed() > 350 * 1000 * numFortresses){ 349 349 if (gameState.ai.pathsToMe && gameState.ai.pathsToMe.length > 0){ -
binaries/data/mods/public/simulation/ai/testbot/gamestate.js
269 269 * Returns player build limits 270 270 * an object where each key is a category corresponding to a build limit for the player. 271 271 */ 272 get BuildLimits: function()272 getEntityLimits: function() 273 273 { 274 return this.playerData. buildLimits;274 return this.playerData.entityLimits; 275 275 }, 276 276 277 277 /** 278 * Returns player buildcounts279 * an object where each key is a category corresponding to the current buildingcount for the player.278 * Returns player entity counts 279 * an object where each key is a category corresponding to the current entity count for the player. 280 280 */ 281 get BuildCounts: function()281 getEntityCounts: function() 282 282 { 283 return this.playerData. buildCounts;283 return this.playerData.entityCounts; 284 284 }, 285 285 286 286 /** 287 * Checks if the player's buildlimit has been reached for the given category.287 * Checks if the player's entity limit has been reached for the given category. 288 288 * The category comes from the entity tenplate, specifically the BuildRestrictions component. 289 289 */ 290 is BuildLimitReached: function(category)290 isEntityLimitReached: function(category) 291 291 { 292 if (this.playerData. buildLimits[category] === undefined || this.playerData.buildCounts[category] === undefined)292 if (this.playerData.entityLimits[category] === undefined || this.playerData.entityCounts[category] === undefined) 293 293 return false; 294 294 295 295 // There's a special case of build limits per civ centre, so check that first 296 if (this.playerData. buildLimits[category].LimitPerCivCentre !== undefined)297 return (this.playerData. buildCounts[category] >= this.playerData.buildCounts["CivilCentre"]*this.playerData.buildLimits[category].LimitPerCivCentre);296 if (this.playerData.entityLimits[category].LimitPerCivCentre !== undefined) 297 return (this.playerData.entityCounts[category] >= this.playerData.entityCounts["CivilCentre"]*this.playerData.entityLimits[category].LimitPerCivCentre); 298 298 else 299 return (this.playerData. buildCounts[category] >= this.playerData.buildLimits[category]);299 return (this.playerData.entityCounts[category] >= this.playerData.entityLimits[category]); 300 300 }, 301 301 }); -
binaries/data/mods/public/simulation/components/BuildLimits.js
1 function BuildLimits() {}2 3 BuildLimits.prototype.Schema =4 "<a:help>Specifies per category limits on number of buildings that can be constructed for each player.</a:help>" +5 "<a:example>" +6 "<Limits>" +7 "<CivilCentre/>" +8 "<DefenseTower>25</DefenseTower>" +9 "<Fortress>10</Fortress>" +10 "<Special>" +11 "<LimitPerCivCentre>1</LimitPerCivCentre>" +12 "</Special>" +13 "</Limits>" +14 "</a:example>" +15 "<element name='LimitMultiplier'>" +16 "<ref name='positiveDecimal'/>" +17 "</element>" +18 "<element name='Limits'>" +19 "<zeroOrMore>" +20 "<element a:help='Specifies a category of building on which to apply this limit. See BuildRestrictions for list of categories.'>" +21 "<anyName />" +22 "<choice>" +23 "<text />" +24 "<element name='LimitPerCivCentre' a:help='Specifies that this limit is per number of civil centres.'>" +25 "<data type='nonNegativeInteger'/>" +26 "</element>" +27 "</choice>" +28 "</element>" +29 "</zeroOrMore>" +30 "</element>";31 32 /*33 * TODO: Use an inheriting player_{civ}.xml template for civ-specific limits34 */35 36 BuildLimits.prototype.Init = function()37 {38 this.limit = {};39 this.count = {};40 for (var category in this.template.Limits)41 {42 this.limit[category] = this.template.Limits[category];43 this.count[category] = 0;44 }45 };46 47 BuildLimits.prototype.IncrementCount = function(category)48 {49 if (this.count[category] !== undefined)50 {51 this.count[category]++;52 }53 };54 55 BuildLimits.prototype.DecrementCount = function(category)56 {57 if (this.count[category] !== undefined)58 {59 this.count[category]--;60 }61 };62 63 BuildLimits.prototype.GetLimits = function()64 {65 return this.limit;66 };67 68 BuildLimits.prototype.GetCounts = function()69 {70 return this.count;71 };72 73 BuildLimits.prototype.AllowedToBuild = function(category)74 {75 // TODO: The UI should reflect this before the user tries to place the building,76 // since the limits are independent of placement location77 78 // Allow unspecified categories and those with no limit79 if (this.count[category] === undefined || this.limit[category] === undefined)80 {81 return true;82 }83 84 // Rather than complicating the schema unecessarily, just handle special cases here85 if (this.limit[category].LimitPerCivCentre !== undefined)86 {87 if (this.count[category] >= this.count["CivilCentre"] * this.limit[category].LimitPerCivCentre)88 {89 var cmpPlayer = Engine.QueryInterface(this.entity, IID_Player);90 var notification = {"player": cmpPlayer.GetPlayerID(), "message": category+" build limit of "+this.limit[category].LimitPerCivCentre+" per civil centre reached"};91 var cmpGUIInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface);92 cmpGUIInterface.PushNotification(notification);93 94 return false;95 }96 }97 else if (this.count[category] >= this.limit[category])98 {99 var cmpPlayer = Engine.QueryInterface(this.entity, IID_Player);100 var notification = {"player": cmpPlayer.GetPlayerID(), "message": category+" build limit of "+this.limit[category]+ " reached"};101 var cmpGUIInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface);102 cmpGUIInterface.PushNotification(notification);103 104 return false;105 }106 107 return true;108 };109 110 BuildLimits.prototype.OnGlobalOwnershipChanged = function(msg)111 {112 // This automatically updates build counts113 var cmpBuildRestrictions = Engine.QueryInterface(msg.entity, IID_BuildRestrictions);114 if (cmpBuildRestrictions)115 {116 var playerID = (Engine.QueryInterface(this.entity, IID_Player)).GetPlayerID();117 if (msg.from == playerID)118 {119 this.DecrementCount(cmpBuildRestrictions.GetCategory());120 }121 if (msg.to == playerID)122 {123 this.IncrementCount(cmpBuildRestrictions.GetCategory());124 }125 }126 };127 128 Engine.RegisterComponentType(IID_BuildLimits, "BuildLimits", BuildLimits); -
binaries/data/mods/public/simulation/components/EntityLimits.js
1 function EntityLimits() {} 2 3 EntityLimits.prototype.Schema = 4 "<a:help>Specifies per category limits on number of entities (buildings or units) that can be created for each player.</a:help>" + 5 "<a:example>" + 6 "<Limits>" + 7 "<CivilCentre/>" + 8 "<DefenseTower>25</DefenseTower>" + 9 "<Fortress>10</Fortress>" + 10 "<Hero>1</Hero>" + 11 "<Special>" + 12 "<LimitPerCivCentre>1</LimitPerCivCentre>" + 13 "</Special>" + 14 "</Limits>" + 15 "</a:example>" + 16 "<element name='LimitMultiplier'>" + 17 "<ref name='positiveDecimal'/>" + 18 "</element>" + 19 "<element name='Limits'>" + 20 "<zeroOrMore>" + 21 "<element a:help='Specifies a category of building/unit on which to apply this limit. See BuildRestrictions/TrainingRestrictions for list of categories.'>" + 22 "<anyName />" + 23 "<choice>" + 24 "<text />" + 25 "<element name='LimitPerCivCentre' a:help='Specifies that this limit is per number of civil centres.'>" + 26 "<data type='nonNegativeInteger'/>" + 27 "</element>" + 28 "</choice>" + 29 "</element>" + 30 "</zeroOrMore>" + 31 "</element>"; 32 33 /* 34 * TODO: Use an inheriting player_{civ}.xml template for civ-specific limits 35 */ 36 37 const TRAINING = "training"; 38 const BUILD = "build"; 39 40 EntityLimits.prototype.Init = function() 41 { 42 this.limit = {}; 43 this.count = {}; 44 for (var category in this.template.Limits) 45 { 46 this.limit[category] = this.template.Limits[category]; 47 this.count[category] = 0; 48 } 49 }; 50 51 EntityLimits.prototype.IncreaseCount = function(category, value) 52 { 53 if (this.count[category] !== undefined) 54 { 55 this.count[category] += value; 56 } 57 }; 58 59 EntityLimits.prototype.DecreaseCount = function(category, value) 60 { 61 if (this.count[category] !== undefined) 62 { 63 this.count[category] -= value; 64 } 65 }; 66 67 EntityLimits.prototype.IncrementCount = function(category) 68 { 69 this.IncreaseCount(category, 1); 70 }; 71 72 EntityLimits.prototype.DecrementCount = function(category) 73 { 74 this.DecreaseCount(category, 1); 75 }; 76 77 EntityLimits.prototype.GetLimits = function() 78 { 79 return this.limit; 80 }; 81 82 EntityLimits.prototype.GetCounts = function() 83 { 84 return this.count; 85 }; 86 87 EntityLimits.prototype.AllowedToCreate = function(limitType, category, count) 88 { 89 // TODO: The UI should reflect this before the user tries to place the building, 90 // since the limits are independent of placement location 91 92 // Allow unspecified categories and those with no limit 93 if (this.count[category] === undefined || this.limit[category] === undefined) 94 { 95 return true; 96 } 97 98 // Rather than complicating the schema unecessarily, just handle special cases here 99 if (this.limit[category].LimitPerCivCentre !== undefined) 100 { 101 if (this.count[category] >= this.count["CivilCentre"] * this.limit[category].LimitPerCivCentre) 102 { 103 var cmpPlayer = Engine.QueryInterface(this.entity, IID_Player); 104 var notification = {"player": cmpPlayer.GetPlayerID(), "message": category+" "+limitType+" limit of "+this.limit[category].LimitPerCivCentre+" per civil centre reached"}; 105 var cmpGUIInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface); 106 cmpGUIInterface.PushNotification(notification); 107 108 return false; 109 } 110 } 111 else if (this.count[category] + count > this.limit[category]) 112 { 113 var cmpPlayer = Engine.QueryInterface(this.entity, IID_Player); 114 var notification = {"player": cmpPlayer.GetPlayerID(), "message": category+" "+limitType+" limit of "+this.limit[category]+ " reached"}; 115 var cmpGUIInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface); 116 cmpGUIInterface.PushNotification(notification); 117 118 return false; 119 } 120 121 return true; 122 } 123 124 EntityLimits.prototype.AllowedToBuild = function(category) 125 { 126 // TODO: The UI should reflect this before the user tries to place the building, 127 // since the limits are independent of placement location 128 129 return this.AllowedToCreate(BUILD, category, 1); 130 }; 131 132 EntityLimits.prototype.AllowedToTrain = function(category, count) 133 { 134 return this.AllowedToCreate(TRAINING, category, count); 135 }; 136 137 EntityLimits.prototype.OnGlobalOwnershipChanged = function(msg) 138 { 139 // This automatically updates entity counts 140 var category = null; 141 var cmpBuildRestrictions = Engine.QueryInterface(msg.entity, IID_BuildRestrictions); 142 if (cmpBuildRestrictions) 143 category = cmpBuildRestrictions.GetCategory(); 144 var cmpTrainingRestrictions = Engine.QueryInterface(msg.entity, IID_TrainingRestrictions); 145 if (cmpTrainingRestrictions) 146 category = cmpTrainingRestrictions.GetCategory(); 147 if (category) 148 { 149 var playerID = (Engine.QueryInterface(this.entity, IID_Player)).GetPlayerID(); 150 if (msg.from == playerID) 151 { 152 this.DecrementCount(category); 153 } 154 if (msg.to == playerID) 155 { 156 this.IncrementCount(category); 157 } 158 } 159 }; 160 161 Engine.RegisterComponentType(IID_EntityLimits, "EntityLimits", EntityLimits); -
binaries/data/mods/public/simulation/components/GuiInterface.js
49 49 for (var i = 0; i < n; ++i) 50 50 { 51 51 var playerEnt = cmpPlayerMan.GetPlayerByID(i); 52 var cmpPlayer BuildLimits = Engine.QueryInterface(playerEnt, IID_BuildLimits);52 var cmpPlayerEntityLimits = Engine.QueryInterface(playerEnt, IID_EntityLimits); 53 53 var cmpPlayer = Engine.QueryInterface(playerEnt, IID_Player); 54 54 55 55 // Work out what phase we are in … … 88 88 "isAlly": allies, 89 89 "isNeutral": neutrals, 90 90 "isEnemy": enemies, 91 " buildLimits": cmpPlayerBuildLimits.GetLimits(),92 " buildCounts": cmpPlayerBuildLimits.GetCounts(),91 "entityLimits": cmpPlayerEntityLimits.GetLimits(), 92 "entityCounts": cmpPlayerEntityLimits.GetCounts(), 93 93 "techModifications": cmpTechnologyManager.GetTechModifications() 94 94 }; 95 95 ret.players.push(playerData); … … 384 384 if (template.BuildRestrictions.Distance.MaxDistance) ret.buildRestrictions.distance.max = +template.BuildRestrictions.Distance.MaxDistance; 385 385 } 386 386 } 387 387 388 if (template.TrainingRestrictions) 389 { 390 ret.trainingRestrictions = { 391 "category": template.TrainingRestrictions.Category, 392 }; 393 } 394 388 395 if (template.Cost) 389 396 { 390 397 ret.cost = {}; … … 453 460 ret.icon = template.Identity.Icon; 454 461 ret.tooltip = template.Identity.Tooltip; 455 462 ret.requiredTechnology = template.Identity.RequiredTechnology; 463 ret.identityClassesString = GetTemplateIdentityClassesString(template); 456 464 } 457 465 458 466 if (template.UnitMotion) -
binaries/data/mods/public/simulation/components/Player.js
417 417 Player.prototype.OnGlobalOwnershipChanged = function(msg) 418 418 { 419 419 var isConquestCritical = false; 420 421 420 // Load class list only if we're going to need it 422 421 if (msg.from == this.playerID || msg.to == this.playerID) 423 422 { 424 423 var cmpIdentity = Engine.QueryInterface(msg.entity, IID_Identity); 425 424 if (cmpIdentity) 426 425 { 427 var classes = cmpIdentity.GetClassesList(); 428 isConquestCritical = classes.indexOf("ConquestCritical") != -1; 426 isConquestCritical = cmpIdentity.HasClass("ConquestCritical"); 429 427 } 430 428 } 431 432 429 if (msg.from == this.playerID) 433 430 { 434 431 if (isConquestCritical) 435 432 this.conquestCriticalEntitiesCount--; 436 437 433 var cost = Engine.QueryInterface(msg.entity, IID_Cost); 438 434 if (cost) 439 435 { … … 441 437 this.popBonuses -= cost.GetPopBonus(); 442 438 } 443 439 } 444 445 440 if (msg.to == this.playerID) 446 441 { 447 442 if (isConquestCritical) 448 443 this.conquestCriticalEntitiesCount++; 449 450 444 var cost = Engine.QueryInterface(msg.entity, IID_Cost); 451 445 if (cost) 452 446 { -
binaries/data/mods/public/simulation/components/ProductionQueue.js
212 212 if (!cmpPlayer.TrySubtractResources(totalCosts)) 213 213 return; 214 214 215 // Update entity count in the EntityLimits component 216 if (template.TrainingRestrictions) 217 { 218 var unitCategory = template.TrainingRestrictions.Category; 219 var cmpPlayerEntityLimits = QueryOwnerInterface(this.entity, IID_EntityLimits); 220 cmpPlayerEntityLimits.IncreaseCount(unitCategory, count); 221 } 222 215 223 this.queue.push({ 216 224 "id": this.nextID++, 217 225 "player": cmpPlayer.GetPlayerID(), … … 307 315 308 316 var cmpPlayer = QueryPlayerIDInterface(item.player, IID_Player); 309 317 318 // Update entity count in the EntityLimits component 319 if (item.unitTemplate) 320 { 321 var cmpTempMan = Engine.QueryInterface(SYSTEM_ENTITY, IID_TemplateManager); 322 var template = cmpTempMan.GetTemplate(item.unitTemplate); 323 if (template.TrainingRestrictions) 324 { 325 var unitCategory = template.TrainingRestrictions.Category; 326 var cmpPlayerEntityLimits = QueryOwnerInterface(this.entity, IID_EntityLimits); 327 cmpPlayerEntityLimits.DecreaseCount(unitCategory, item.count); 328 } 329 } 330 310 331 // Refund the resource cost for this batch 311 332 var totalCosts = {}; 312 333 var cmpStatisticsTracker = QueryOwnerInterface(this.entity, IID_StatisticsTracker); … … 422 443 // so only create them once and use as needed 423 444 for (var i = 0; i < count; ++i) 424 445 { 425 this.entityCache.push(Engine.AddEntity(templateName)); 446 var ent = Engine.AddEntity(templateName); 447 this.entityCache.push(ent); 448 449 // Decrement entity count in the EntityLimits component 450 // since it will be increased by EntityLimits.OnGlobalOwnershipChanged function, 451 // i.e. we replace a 'trained' entity to an 'alive' one 452 var cmpTrainingRestrictions = Engine.QueryInterface(ent, IID_TrainingRestrictions); 453 if (cmpTrainingRestrictions) 454 { 455 var unitCategory = cmpTrainingRestrictions.GetCategory(); 456 var cmpPlayerEntityLimits = QueryOwnerInterface(this.entity, IID_EntityLimits); 457 cmpPlayerEntityLimits.DecrementCount(unitCategory); 458 } 426 459 } 427 460 } 428 461 -
binaries/data/mods/public/simulation/components/TrainingRestrictions.js
1 function TrainingRestrictions() {} 2 3 TrainingRestrictions.prototype.Schema = 4 "<a:help>Specifies unit training restrictions, currently only unit category.</a:help>" + 5 "<a:example>" + 6 "<TrainingRestrictions>" + 7 "<Category>Hero</Category>" + 8 "</TrainingRestrictions>" + 9 "</a:example>" + 10 "<element name='Category' a:help='Specifies the category of this unit, for satisfying special constraints.'>" + 11 "<choice>" + 12 "<value>Hero</value>" + 13 "<value>FemaleCitizen</value>" + 14 "</choice>" + 15 "</element>"; 16 17 TrainingRestrictions.prototype.GetCategory = function() 18 { 19 return this.template.Category; 20 }; 21 22 Engine.RegisterComponentType(IID_TrainingRestrictions, "TrainingRestrictions", TrainingRestrictions); -
binaries/data/mods/public/simulation/components/interfaces/BuildLimits.js
1 Engine.RegisterInterface("BuildLimits");2 No newline at end of file -
binaries/data/mods/public/simulation/components/interfaces/EntityLimits.js
1 Engine.RegisterInterface("EntityLimits"); -
binaries/data/mods/public/simulation/components/interfaces/TrainingRestrictions.js
1 Engine.RegisterInterface("TrainingRestrictions"); 2 -
binaries/data/mods/public/simulation/components/tests/test_GuiInterface.js
1 1 Engine.LoadComponentScript("interfaces/Attack.js"); 2 2 Engine.LoadComponentScript("interfaces/Barter.js"); 3 3 Engine.LoadComponentScript("interfaces/Builder.js"); 4 Engine.LoadComponentScript("interfaces/BuildLimits.js");5 4 Engine.LoadComponentScript("interfaces/DamageReceiver.js"); 5 Engine.LoadComponentScript("interfaces/EntityLimits.js"); 6 6 Engine.LoadComponentScript("interfaces/Foundation.js"); 7 7 Engine.LoadComponentScript("interfaces/GarrisonHolder.js"); 8 8 Engine.LoadComponentScript("interfaces/Gate.js"); … … 69 69 IsEnemy: function() { return true; }, 70 70 }); 71 71 72 AddMock(100, IID_ BuildLimits, {72 AddMock(100, IID_EntityLimits, { 73 73 GetLimits: function() { return {"Foo": 10}; }, 74 74 GetCounts: function() { return {"Foo": 5}; }, 75 75 }); … … 122 122 IsEnemy: function() { return false; }, 123 123 }); 124 124 125 AddMock(101, IID_ BuildLimits, {125 AddMock(101, IID_EntityLimits, { 126 126 GetLimits: function() { return {"Bar": 20}; }, 127 127 GetCounts: function() { return {"Bar": 0}; }, 128 128 }); … … 177 177 isAlly: [false, false, false], 178 178 isNeutral: [false, false, false], 179 179 isEnemy: [true, true, true], 180 buildLimits: {"Foo": 10},181 buildCounts: {"Foo": 5},180 entityLimits: {"Foo": 10}, 181 entityCounts: {"Foo": 5}, 182 182 techModifications: {}, 183 183 }, 184 184 { … … 197 197 isAlly: [true, true, true], 198 198 isNeutral: [false, false, false], 199 199 isEnemy: [false, false, false], 200 buildLimits: {"Bar": 20},201 buildCounts: {"Bar": 0},200 entityLimits: {"Bar": 20}, 201 entityCounts: {"Bar": 0}, 202 202 techModifications: {}, 203 203 } 204 204 ], … … 224 224 isAlly: [false, false, false], 225 225 isNeutral: [false, false, false], 226 226 isEnemy: [true, true, true], 227 buildLimits: {"Foo": 10},228 buildCounts: {"Foo": 5},227 entityLimits: {"Foo": 10}, 228 entityCounts: {"Foo": 5}, 229 229 techModifications: {}, 230 230 statistics: { 231 231 unitsTrained: 10, … … 260 260 isAlly: [true, true, true], 261 261 isNeutral: [false, false, false], 262 262 isEnemy: [false, false, false], 263 buildLimits: {"Bar": 20},264 buildCounts: {"Bar": 0},263 entityLimits: {"Bar": 20}, 264 entityCounts: {"Bar": 0}, 265 265 techModifications: {}, 266 266 statistics: { 267 267 unitsTrained: 10, -
binaries/data/mods/public/simulation/data/technologies/no_heroes.json
1 {2 "genericName": "Future Alpha",3 "description": "Temporarily Disable Heroes",4 "cost": {"food": 0, "wood": 100, "stone": 0, "metal": 0},5 "requirements": {"tech": "phase_city"},6 "requirementsTooltip": "Unlocked in City Phase.",7 "icon": "arrow.png",8 "researchTime": 20,9 "tooltip": "Need build limits before renabling this."10 } -
binaries/data/mods/public/simulation/helpers/Commands.js
169 169 170 170 case "train": 171 171 var entities = FilterEntityList(cmd.entities, player, controlAllUnits); 172 173 // Check entity limits 174 var cmpTempMan = Engine.QueryInterface(SYSTEM_ENTITY, IID_TemplateManager); 175 var template = cmpTempMan.GetTemplate(cmd.template); 176 var unitCategory = null; 177 if (template.TrainingRestrictions) 178 unitCategory = template.TrainingRestrictions.Category; 179 172 180 // Verify that the building(s) can be controlled by the player 173 181 if (entities.length > 0) 174 182 { 175 183 for each (var ent in entities) 176 184 { 185 if (unitCategory) 186 { 187 var cmpPlayerEntityLimits = QueryOwnerInterface(ent, IID_EntityLimits); 188 if (!cmpPlayerEntityLimits.AllowedToTrain(unitCategory, cmd.count)) 189 { 190 if (g_DebugCommands) 191 { 192 warn(unitCategory + " train limit is reached: " + uneval(cmd)); 193 } 194 continue; 195 } 196 } 197 177 198 var cmpTechnologyManager = QueryOwnerInterface(ent, IID_TechnologyManager); 178 199 // TODO: Enable this check once the AI gets technology support 179 200 if (cmpTechnologyManager.CanProduce(cmd.template) || true) … … 568 589 return false; 569 590 } 570 591 571 // Check buildlimits572 var cmp BuildLimits = QueryPlayerIDInterface(player, IID_BuildLimits);573 if (!cmp BuildLimits || !cmpBuildLimits.AllowedToBuild(cmpBuildRestrictions.GetCategory()))592 // Check entity limits 593 var cmpEntityLimits = QueryPlayerIDInterface(player, IID_EntityLimits); 594 if (!cmpEntityLimits || !cmpEntityLimits.AllowedToBuild(cmpBuildRestrictions.GetCategory())) 574 595 { 575 596 if (g_DebugCommands) 576 597 { -
binaries/data/mods/public/simulation/helpers/Templates.js
1 /** 2 * Return template.Identity.Classes._string if exists 3 */ 4 function GetTemplateIdentityClassesString(template) 5 { 6 var identityClassesString = undefined; 7 if (template.Identity && template.Identity.Classes && "_string" in template.Identity.Classes) 8 identityClassesString = template.Identity.Classes._string; 9 return identityClassesString; 10 } 11 12 /** 13 * Check whether template.Identity.Classes contains specified class 14 */ 15 function TemplateHasIdentityClass(template, className) 16 { 17 var identityClassesString = GetTemplateIdentityClassesString(template); 18 var hasClass = identityClassesString && identityClassesString.indexOf(className) != -1; 19 return hasClass; 20 } 21 22 Engine.RegisterGlobal("GetTemplateIdentityClassesString", GetTemplateIdentityClassesString); 23 Engine.RegisterGlobal("TemplateHasIdentityClass", TemplateHasIdentityClass); 24 -
binaries/data/mods/public/simulation/templates/special/player.xml
1 1 <?xml version="1.0" encoding="utf-8"?> 2 2 <Entity> 3 < BuildLimits>3 <EntityLimits> 4 4 <LimitMultiplier>1.0</LimitMultiplier> 5 5 <Limits> 6 6 <CivilCentre/> 7 7 <DefenseTower>25</DefenseTower> 8 8 <Fortress>10</Fortress> 9 <FemaleCitizen>32</FemaleCitizen> 10 <Hero>1</Hero> 9 11 </Limits> 10 </ BuildLimits>12 </EntityLimits> 11 13 <Player/> 12 14 <StatisticsTracker/> 13 15 <TechnologyManager/> -
binaries/data/mods/public/simulation/templates/template_unit_hero.xml
36 36 <Identity> 37 37 <GenericName>Hero</GenericName> 38 38 <Classes datatype="tokens">Hero Organic</Classes> 39 <RequiredTechnology>no_heroes</RequiredTechnology>40 39 </Identity> 41 40 <Loot> 42 41 <xp>400</xp> … … 63 62 <death>actor/human/death/death.xml</death> 64 63 </SoundGroups> 65 64 </Sound> 65 <TrainingRestrictions> 66 <Category>Hero</Category> 67 </TrainingRestrictions> 66 68 <UnitMotion> 67 69 <WalkSpeed>9.0</WalkSpeed> 68 70 <Run> -
binaries/data/mods/public/simulation/templates/template_unit_hero_cavalry.xml
40 40 <Identity> 41 41 <GenericName>Hero Cavalry</GenericName> 42 42 <Classes datatype="tokens">Hero Cavalry</Classes> 43 <RequiredTechnology>no_heroes</RequiredTechnology>44 43 </Identity> 45 44 <Loot> 46 45 <xp>500</xp> … … 70 69 <Stamina> 71 70 <Max>2500</Max> 72 71 </Stamina> 72 <TrainingRestrictions> 73 <Category>Hero</Category> 74 </TrainingRestrictions> 73 75 <UnitMotion> 74 76 <WalkSpeed>11.0</WalkSpeed> 75 77 <Run> -
binaries/data/mods/public/simulation/templates/template_unit_hero_cavalry_archer.xml
49 49 <GenericName>Hero Cavalry Archer</GenericName> 50 50 <Tooltip>Hero Aura: n/a. 51 51 Ranged attack 2x vs. spearmen. Ranged attack 1.5x vs. Swordsmen.</Tooltip> 52 <RequiredTechnology>no_heroes</RequiredTechnology>53 52 </Identity> 54 53 <Loot> 55 54 <xp>450</xp> … … 70 69 </Texture> 71 70 </Overlay> 72 71 </Selectable> 72 <TrainingRestrictions> 73 <Category>Hero</Category> 74 </TrainingRestrictions> 73 75 <UnitMotion> 74 76 <WalkSpeed>11.0</WalkSpeed> 75 77 <Run> -
binaries/data/mods/public/simulation/templates/template_unit_hero_cavalry_javelinist.xml
39 39 <Identity> 40 40 <Classes datatype="tokens">Hero</Classes> 41 41 <GenericName>Hero Cavalry Skirmisher</GenericName> 42 <RequiredTechnology>no_heroes</RequiredTechnology>43 42 </Identity> 44 43 <Loot> 45 44 <xp>450</xp> … … 60 59 </Texture> 61 60 </Overlay> 62 61 </Selectable> 62 <TrainingRestrictions> 63 <Category>Hero</Category> 64 </TrainingRestrictions> 63 65 <UnitMotion> 64 66 <WalkSpeed>11.5</WalkSpeed> 65 67 <Run> -
binaries/data/mods/public/simulation/templates/template_unit_hero_infantry.xml
38 38 <Identity> 39 39 <Classes datatype="tokens">Hero Infantry</Classes> 40 40 <GenericName>Hero</GenericName> 41 <RequiredTechnology>no_heroes</RequiredTechnology>42 41 </Identity> 43 42 <Loot> 44 43 <xp>400</xp> … … 68 67 <Stamina> 69 68 <Max>1500</Max> 70 69 </Stamina> 70 <TrainingRestrictions> 71 <Category>Hero</Category> 72 </TrainingRestrictions> 71 73 <UnitMotion> 72 74 <WalkSpeed>8.5</WalkSpeed> 73 75 <Run> -
binaries/data/mods/public/simulation/templates/template_unit_hero_infantry_archer.xml
41 41 <Classes datatype="tokens">Hero</Classes> 42 42 <Tooltip>Hero Archer. 43 43 Counters Swordsmen and Cavalry Spearmen. Countered by Skirmishers and other Cavalry types.</Tooltip> 44 <RequiredTechnology>no_heroes</RequiredTechnology>45 44 </Identity> 46 45 <Loot> 47 46 <xp>350</xp> … … 62 61 </Texture> 63 62 </Overlay> 64 63 </Selectable> 64 <TrainingRestrictions> 65 <Category>Hero</Category> 66 </TrainingRestrictions> 65 67 </Entity> -
binaries/data/mods/public/simulation/templates/template_unit_hero_infantry_javelinist.xml
45 45 <Identity> 46 46 <Classes datatype="tokens">Hero</Classes> 47 47 <GenericName>Hero Skirmisher</GenericName> 48 <RequiredTechnology>no_heroes</RequiredTechnology>49 48 </Identity> 50 49 <Loot> 51 50 <xp>350</xp> … … 66 65 </Texture> 67 66 </Overlay> 68 67 </Selectable> 68 <TrainingRestrictions> 69 <Category>Hero</Category> 70 </TrainingRestrictions> 69 71 </Entity> -
binaries/data/mods/public/simulation/templates/template_unit_hero_ranged.xml
51 51 </Texture> 52 52 </Overlay> 53 53 </Selectable> 54 <TrainingRestrictions> 55 <Category>Hero</Category> 56 </TrainingRestrictions> 54 57 <UnitMotion> 55 58 <WalkSpeed>8.5</WalkSpeed> 56 59 <Run> -
binaries/data/mods/public/simulation/templates/template_unit_support_female_citizen.xml
99 99 <Stamina> 100 100 <Max>500</Max> 101 101 </Stamina> 102 <TrainingRestrictions> 103 <Category>FemaleCitizen</Category> 104 </TrainingRestrictions> 102 105 <UnitMotion> 103 106 <WalkSpeed>8.0</WalkSpeed> 104 107 <Run>