Ticket #1432: one_hero_2012_10_06.diff
File one_hero_2012_10_06.diff, 59.0 KB (added by , 12 years ago) |
---|
-
binaries/data/mods/public/gui/session/input.js
1470 1470 1471 1471 function flushTrainingBatch() 1472 1472 { 1473 Engine.PostNetworkCommand({"type": "train", "entities": batchTrainingEntities, "template": batchTrainingType, "count": batchTrainingCount}); 1473 var appropriateBuildings = getBuidlingsWhichCanTrainEntity(batchTrainingEntities, batchTrainingType); 1474 // If training limits don't allow us to train batchTrainingCount in each appropriate building 1475 if (batchTrainingEntityAllowedCount !== undefined && batchTrainingEntityAllowedCount < batchTrainingCount * appropriateBuildings.length) 1476 { 1477 // Train as many full batches as we can 1478 var buildingsCountToTrainFullBatch = Math.floor(batchTrainingEntityAllowedCount / batchTrainingCount); 1479 var buildingsToTrainFullBatch = appropriateBuildings.slice(0, buildingsCountToTrainFullBatch); 1480 Engine.PostNetworkCommand({"type": "train", "entities": buildingsToTrainFullBatch, "template": batchTrainingType, "count": batchTrainingCount}); 1481 1482 // Train remainer in one more building 1483 var remainderToTrain = batchTrainingEntityAllowedCount % batchTrainingCount; 1484 Engine.PostNetworkCommand({"type": "train", "entities": [ appropriateBuildings[buildingsCountToTrainFullBatch] ], "template": batchTrainingType, "count": remainderToTrain}); 1485 } 1486 else 1487 { 1488 Engine.PostNetworkCommand({"type": "train", "entities": appropriateBuildings, "template": batchTrainingType, "count": batchTrainingCount}); 1489 } 1474 1490 } 1475 1491 1492 function getBuidlingsWhichCanTrainEntity(entitiesToCheck, trainEntType) 1493 { 1494 return entitiesToCheck.filter(function(entity) { 1495 var state = GetEntityState(entity); 1496 var canTrain = state && state.production && state.production.entities.length && state.production.entities.indexOf(trainEntType) != -1; 1497 return canTrain; 1498 }); 1499 } 1500 1501 function getEntityLimitAndCount(playerState, entType) 1502 { 1503 var template = GetTemplateData(entType); 1504 var trainingCategory = null; 1505 if (template.trainingRestrictions) 1506 trainingCategory = template.trainingRestrictions.category; 1507 var trainEntLimit = undefined; 1508 var trainEntCount = undefined; 1509 var canBeTrainedCount = undefined; 1510 if (trainingCategory && playerState.entityLimits[trainingCategory]) 1511 { 1512 trainEntLimit = playerState.entityLimits[trainingCategory]; 1513 trainEntCount = playerState.entityCounts[trainingCategory]; 1514 canBeTrainedCount = trainEntLimit - trainEntCount; 1515 } 1516 return [trainEntLimit, trainEntCount, canBeTrainedCount]; 1517 } 1518 1476 1519 // Called by GUI when user clicks training button 1477 function addTrainingToQueue(selection, trainEntType )1520 function addTrainingToQueue(selection, trainEntType, playerState) 1478 1521 { 1479 if (Engine.HotkeyIsPressed("session.batchtrain")) 1522 // Create list of buildings which can train trainEntType 1523 var appropriateBuildings = getBuidlingsWhichCanTrainEntity(selection, trainEntType); 1524 1525 // Check trainEntType entity limit and count 1526 var [trainEntLimit, trainEntCount, canBeTrainedCount] = getEntityLimitAndCount(playerState, trainEntType) 1527 1528 // Batch training possible if we can train at least 2 units 1529 var batchTrainingPossible = canBeTrainedCount !== undefined && canBeTrainedCount > 1; 1530 1531 if (Engine.HotkeyIsPressed("session.batchtrain") && batchTrainingPossible) 1480 1532 { 1481 1533 if (inputState == INPUT_BATCHTRAINING) 1482 1534 { … … 1493 1545 } 1494 1546 } 1495 1547 // If we're already creating a batch of this unit (in the same building(s)), then just extend it 1548 // (if training limits allow) 1496 1549 if (sameEnts && batchTrainingType == trainEntType) 1497 1550 { 1498 batchTrainingCount += batchIncrementSize; 1551 if (canBeTrainedCount !== undefined && canBeTrainedCount > batchTrainingCount * appropriateBuildings.length) 1552 batchTrainingCount += batchIncrementSize; 1553 batchTrainingEntityAllowedCount = canBeTrainedCount; 1499 1554 return; 1500 1555 } 1501 1556 // Otherwise start a new one … … 1508 1563 inputState = INPUT_BATCHTRAINING; 1509 1564 batchTrainingEntities = selection; 1510 1565 batchTrainingType = trainEntType; 1566 batchTrainingEntityAllowedCount = canBeTrainedCount; 1511 1567 batchTrainingCount = batchIncrementSize; 1512 1568 } 1513 1569 else 1514 1570 { 1515 // Non-batched - just create a single entity 1516 Engine.PostNetworkCommand({"type": "train", "template": trainEntType, "count": 1, "entities": selection}); 1571 // Non-batched - just create a single entity in each building 1572 // (but no more than entity limit allows) 1573 var buildingsForTraining = appropriateBuildings; 1574 if (trainEntLimit) 1575 buildingsForTraining = buildingsForTraining.slice(0, canBeTrainedCount); 1576 Engine.PostNetworkCommand({"type": "train", "template": trainEntType, "count": 1, "entities": buildingsForTraining}); 1517 1577 } 1518 1578 } 1519 1579 … … 1525 1585 1526 1586 // Returns the number of units that will be present in a batch if the user clicks 1527 1587 // the training button with shift down 1528 function getTrainingBatchStatus( entity, trainEntType)1588 function getTrainingBatchStatus(playerState, entity, trainEntType, selection) 1529 1589 { 1590 var apporpriateBuildings = [entity]; 1591 if (selection && selection.indexOf(entity) != -1) 1592 appropriateBuildings = getBuidlingsWhichCanTrainEntity(selection, trainEntType); 1593 var nextBatchTrainingCount = 0; 1530 1594 if (inputState == INPUT_BATCHTRAINING && batchTrainingEntities.indexOf(entity) != -1 && batchTrainingType == trainEntType) 1531 return [batchTrainingCount, batchIncrementSize]; 1595 { 1596 nextBatchTrainingCount = batchTrainingCount; 1597 var canBeTrainedCount = batchTrainingEntityAllowedCount; 1598 } 1532 1599 else 1533 return [0, batchIncrementSize]; 1600 { 1601 var [trainEntLimit, trainEntCount, canBeTrainedCount] = getEntityLimitAndCount(playerState, trainEntType); 1602 var batchSize = Math.min(canBeTrainedCount, batchIncrementSize); 1603 } 1604 // We need to calculate count after the next increment if it's possible 1605 if (canBeTrainedCount == undefined || canBeTrainedCount > nextBatchTrainingCount * appropriateBuildings.length) 1606 nextBatchTrainingCount += batchIncrementSize; 1607 // If training limits don't allow us to train batchTrainingCount in each appropriate building 1608 // train as many full batches as we can and remainer in one more building. 1609 var buildingsCountToTrainFullBatch = appropriateBuildings.length; 1610 var remainderToTrain = 0; 1611 if (canBeTrainedCount !== undefined && canBeTrainedCount < nextBatchTrainingCount * appropriateBuildings.length) 1612 { 1613 buildingsCountToTrainFullBatch = Math.floor(canBeTrainedCount / nextBatchTrainingCount); 1614 remainderToTrain = canBeTrainedCount % nextBatchTrainingCount; 1615 } 1616 return [buildingsCountToTrainFullBatch, nextBatchTrainingCount, remainderToTrain]; 1534 1617 } 1535 1618 1536 1619 // 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 … … 347 380 case GATE: 348 381 var tooltip = item.tooltip; 349 382 if (item.template) 350 { 383 { 351 384 var template = GetTemplateData(item.template); 352 tooltip += "\n" + getEntityCostTooltip(template); 353 354 var affordableMask = getGUIObjectByName("unitGateUnaffordable["+i+"]"); 385 tooltip += "\n" + getEntityCostTooltip(template); 386 387 var affordableMask = getGUIObjectByName("unitGateUnaffordable["+i+"]"); 355 388 affordableMask.hidden = true; 356 357 var neededResources = Engine.GuiInterfaceCall("GetNeededResources", template.cost); 358 if (neededResources) 359 { 360 affordableMask.hidden = false; 361 tooltip += getNeededResourcesTooltip(neededResources); 362 } 363 } 389 390 var neededResources = Engine.GuiInterfaceCall("GetNeededResources", template.cost); 391 if (neededResources) 392 { 393 affordableMask.hidden = false; 394 tooltip += getNeededResourcesTooltip(neededResources); 395 } 396 } 364 397 break; 365 398 366 399 case STANCE: … … 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: … … 444 475 // Button 445 476 var button = getGUIObjectByName("unit"+guiName+"Button["+i+"]"); 446 477 var button1 = getGUIObjectByName("unit"+guiName+"Button["+(i+rowLength)+"]"); 447 var affordableMask = getGUIObjectByName("unit"+guiName+"Unaffordable["+i+"]"); 448 var affordableMask1 = getGUIObjectByName("unit"+guiName+"Unaffordable["+(i+rowLength)+"]"); 478 var affordableMask = getGUIObjectByName("unit"+guiName+"Unaffordable["+i+"]"); 479 var affordableMask1 = getGUIObjectByName("unit"+guiName+"Unaffordable["+(i+rowLength)+"]"); 449 480 var icon = getGUIObjectByName("unit"+guiName+"Icon["+i+"]"); 450 481 var selection = getGUIObjectByName("unit"+guiName+"Selection["+i+"]"); 451 482 var pair = getGUIObjectByName("unit"+guiName+"Pair["+i+"]"); … … 540 571 { 541 572 icon.sprite = "stretched:session/icons/" + item.icon; 542 573 } 574 else if (guiName == TRAINING) 575 { 576 if (template.icon) 577 { 578 var trainingCategory = null; 579 if (template.trainingRestrictions) 580 trainingCategory = template.trainingRestrictions.category; 581 var grayscale = ""; 582 if (trainingCategory && playerState.entityLimits[trainingCategory] && playerState.entityCounts[trainingCategory] >= playerState.entityLimits[trainingCategory]) 583 grayscale = "grayscale:"; 584 icon.sprite = "stretched:" + grayscale + "session/portraits/" + template.icon; 585 } 586 } 543 587 else if (guiName == GATE) 544 588 { 545 589 var gateIcon; … … 583 627 584 628 if (guiName == RESEARCH) 585 629 { 586 // Check resource requirements for first button 587 affordableMask.hidden = true; 588 var neededResources = Engine.GuiInterfaceCall("GetNeededResources", template.cost); 589 if (neededResources) 590 { 591 if (button.enabled !== false) 592 { 593 button.enabled = false; 594 affordableMask.hidden = false; 595 } 596 button.tooltip += getNeededResourcesTooltip(neededResources); 597 } 598 630 // Check resource requirements for first button 631 affordableMask.hidden = true; 632 var neededResources = Engine.GuiInterfaceCall("GetNeededResources", template.cost); 633 if (neededResources) 634 { 635 if (button.enabled !== false) 636 { 637 button.enabled = false; 638 affordableMask.hidden = false; 639 } 640 button.tooltip += getNeededResourcesTooltip(neededResources); 641 } 642 599 643 if (item.pair) 600 644 { 601 645 grayscale = ""; 602 646 button1.enabled = true; 603 604 if (!Engine.GuiInterfaceCall("CheckTechnologyRequirements", entType1)) 647 648 if (!Engine.GuiInterfaceCall("CheckTechnologyRequirements", entType1)) 605 649 { 606 650 button1.enabled = false; 607 651 button1.tooltip += "\n" + GetTechnologyData(entType1).requirementsTooltip; 608 652 grayscale = "grayscale:"; 609 653 } 610 654 icon1.sprite = "stretched:" + grayscale + "session/portraits/" +template1.icon; 611 612 // Check resource requirements for second button 613 affordableMask1.hidden = true; 614 neededResources = Engine.GuiInterfaceCall("GetNeededResources", template.cost); 615 if (neededResources) 616 { 617 if (button1.enabled !== false) 618 { 619 button1.enabled = false; 620 affordableMask1.hidden = false; 621 } 622 button1.tooltip += getNeededResourcesTooltip(neededResources); 623 } 655 656 // Check resource requirements for second button 657 affordableMask1.hidden = true; 658 neededResources = Engine.GuiInterfaceCall("GetNeededResources", template.cost); 659 if (neededResources) 660 { 661 if (button1.enabled !== false) 662 { 663 button1.enabled = false; 664 affordableMask1.hidden = false; 665 } 666 button1.tooltip += getNeededResourcesTooltip(neededResources); 667 } 624 668 } 625 669 else 626 670 { 627 671 pair.hidden = true; 628 672 button1.hidden = true; 629 affordableMask1.hidden = true; 630 } 631 } 632 else if (guiName == CONSTRUCTION || guiName == TRAINING) 633 { 634 affordableMask.hidden = true; 635 var totalCosts = {}; 636 var trainNum = 1; 637 if (Engine.HotkeyIsPressed("session.batchtrain") && guiName == TRAINING) 638 { 639 var [b atchSize, batchIncrement] = getTrainingBatchStatus(unitEntState.id, entType);640 trainNum = b atchSize + batchIncrement;673 affordableMask1.hidden = true; 674 } 675 } 676 else if (guiName == CONSTRUCTION || guiName == TRAINING) 677 { 678 affordableMask.hidden = true; 679 var totalCosts = {}; 680 var trainNum = 1; 681 if (Engine.HotkeyIsPressed("session.batchtrain") && guiName == TRAINING) 682 { 683 var [buildingsCountToTrainFullBatch, fullBatchSize, remainderBatch] = getTrainingBatchStatus(playerState, unitEntState.id, entType, selection); 684 trainNum = buildingsCountToTrainFullBatch * fullBatchSize + remainderBatch; 641 685 } 642 643 // Walls have no cost defined. 686 687 // Walls have no cost defined. 644 688 if (template.cost !== undefined) 645 689 for (var r in template.cost) 646 690 totalCosts[r] = Math.floor(template.cost[r] * trainNum); 647 648 var neededResources = Engine.GuiInterfaceCall("GetNeededResources", totalCosts); 649 if (neededResources) 691 692 var neededResources = Engine.GuiInterfaceCall("GetNeededResources", totalCosts); 693 if (neededResources) 650 694 { 651 var totalCost = 0; 652 if (button.enabled !== false) 695 var totalCost = 0; 696 if (button.enabled !== false) 653 697 { 654 698 for each (var resource in neededResources) 655 699 totalCost += resource; 656 657 button.enabled = false; 658 affordableMask.hidden = false; 659 var alpha = 75 + totalCost/6; 660 alpha = alpha > 150 ? 150 : alpha; 661 affordableMask.sprite = "colour: 255 0 0 " + (alpha); 662 } 663 button.tooltip += getNeededResourcesTooltip(neededResources); 664 } 700 701 button.enabled = false; 702 affordableMask.hidden = false; 703 var alpha = 75 + totalCost/6; 704 alpha = alpha > 150 ? 150 : alpha; 705 affordableMask.sprite = "colour: 255 0 0 " + (alpha); 706 } 707 button.tooltip += getNeededResourcesTooltip(neededResources); 708 } 665 709 } 666 710 } 667 711 else … … 767 811 } 768 812 769 813 // Sets up "unit barter panel" - special case for setupUnitPanel 770 function setupUnitBarterPanel(unitEntState )814 function setupUnitBarterPanel(unitEntState, playerState) 771 815 { 772 816 // Amount of player's resource to exchange 773 817 var amountToSell = BARTER_RESOURCE_AMOUNT_TO_SELL; … … 862 906 var player = Engine.GetPlayerID(); 863 907 if (entState.player == player || g_DevSettings.controlAll) 864 908 { 909 // Get player state to check some constraints 910 // e.g. presence of a hero or build limits 911 var simState = Engine.GuiInterfaceCall("GetSimulationState"); 912 var playerState = simState.players[player]; 913 865 914 if (selection.length > 1) 866 setupUnitPanel(SELECTION, usedPanels, entState, g_Selection.groups.getTemplateNames(),915 setupUnitPanel(SELECTION, usedPanels, entState, playerState, g_Selection.groups.getTemplateNames(), 867 916 function (entType) { changePrimarySelectionGroup(entType); } ); 868 917 869 918 var commands = getEntityCommandsList(entState); 870 919 if (commands.length) 871 setupUnitPanel(COMMAND, usedPanels, entState, commands,920 setupUnitPanel(COMMAND, usedPanels, entState, playerState, commands, 872 921 function (item) { performCommand(entState.id, item.name); } ); 873 922 874 923 if (entState.garrisonHolder) … … 881 930 groups.add(state.garrisonHolder.entities) 882 931 } 883 932 884 setupUnitPanel(GARRISON, usedPanels, entState, groups.getTemplateNames(),933 setupUnitPanel(GARRISON, usedPanels, entState, playerState, groups.getTemplateNames(), 885 934 function (item) { unloadTemplate(item); } ); 886 935 } 887 936 888 937 var formations = Engine.GuiInterfaceCall("GetAvailableFormations"); 889 938 if (hasClass(entState, "Unit") && !hasClass(entState, "Animal") && !entState.garrisonHolder && formations.length) 890 939 { 891 setupUnitPanel(FORMATION, usedPanels, entState, formations,940 setupUnitPanel(FORMATION, usedPanels, entState, playerState, formations, 892 941 function (item) { performFormation(entState.id, item); } ); 893 942 } 894 943 … … 897 946 var stances = ["violent", "aggressive", "passive", "defensive", "standground"]; 898 947 if (hasClass(entState, "Unit") && !hasClass(entState, "Animal") && stances.length) 899 948 { 900 setupUnitPanel(STANCE, usedPanels, entState, stances,949 setupUnitPanel(STANCE, usedPanels, entState, playerState, stances, 901 950 function (item) { performStance(entState.id, item); } ); 902 951 } 903 952 … … 905 954 if (entState.barterMarket) 906 955 { 907 956 usedPanels["Barter"] = 1; 908 setupUnitBarterPanel(entState );957 setupUnitBarterPanel(entState, playerState); 909 958 } 910 959 911 960 var buildableEnts = []; … … 929 978 930 979 // The first selected entity's type has priority. 931 980 if (entState.buildEntities) 932 setupUnitPanel(CONSTRUCTION, usedPanels, entState, buildableEnts, startBuildingPlacement);981 setupUnitPanel(CONSTRUCTION, usedPanels, entState, playerState, buildableEnts, startBuildingPlacement); 933 982 else if (entState.production && entState.production.entities) 934 setupUnitPanel(TRAINING, usedPanels, entState, trainableEnts,935 function (trainEntType) { addTrainingToQueue(selection, trainEntType ); } );983 setupUnitPanel(TRAINING, usedPanels, entState, playerState, trainableEnts, 984 function (trainEntType) { addTrainingToQueue(selection, trainEntType, playerState); } ); 936 985 else if (entState.trader) 937 986 setupUnitTradingPanel(usedPanels, entState, selection); 938 987 else if (!entState.foundation && entState.gate || hasClass(entState, "LongWall")) … … 994 1043 setupUnitPanel(CONSTRUCTION, usedPanels, entState, buildableEnts, startBuildingPlacement); 995 1044 else if (trainableEnts.length) 996 1045 setupUnitPanel(TRAINING, usedPanels, entState, trainableEnts, 997 function (trainEntType) { addTrainingToQueue(selection, trainEntType ); } );1046 function (trainEntType) { addTrainingToQueue(selection, trainEntType, playerState); } ); 998 1047 } 999 1048 1000 1049 // Show technologies if the active panel has at most one row of icons. … … 1007 1056 } 1008 1057 1009 1058 if (entState.production && entState.production.queue.length) 1010 setupUnitPanel(QUEUE, usedPanels, entState, entState.production.queue,1059 setupUnitPanel(QUEUE, usedPanels, entState, playerState, entState.production.queue, 1011 1060 function (item) { removeFromProductionQueue(entState.id, item.id); } ); 1012 1061 1013 1062 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 on which to apply this limit. See BuildRestrictions 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 EntityLimits.prototype.Init = function() 38 { 39 this.limit = {}; 40 this.count = {}; 41 for (var category in this.template.Limits) 42 { 43 this.limit[category] = this.template.Limits[category]; 44 this.count[category] = 0; 45 } 46 }; 47 48 EntityLimits.prototype.IncreaseCount = function(category, value) 49 { 50 if (this.count[category] !== undefined) 51 { 52 this.count[category] += value; 53 } 54 }; 55 56 EntityLimits.prototype.DecreaseCount = function(category, value) 57 { 58 if (this.count[category] !== undefined) 59 { 60 this.count[category] -= value; 61 } 62 }; 63 64 EntityLimits.prototype.IncrementCount = function(category) 65 { 66 this.IncreaseCount(category, 1); 67 }; 68 69 EntityLimits.prototype.DecrementCount = function(category) 70 { 71 this.DecreaseCount(category, 1); 72 }; 73 74 EntityLimits.prototype.GetLimits = function() 75 { 76 return this.limit; 77 }; 78 79 EntityLimits.prototype.GetCounts = function() 80 { 81 return this.count; 82 }; 83 84 EntityLimits.prototype.AllowedToBuild = function(category) 85 { 86 // TODO: The UI should reflect this before the user tries to place the building, 87 // since the limits are independent of placement location 88 89 // Allow unspecified categories and those with no limit 90 if (this.count[category] === undefined || this.limit[category] === undefined) 91 { 92 return true; 93 } 94 95 // Rather than complicating the schema unecessarily, just handle special cases here 96 if (this.limit[category].LimitPerCivCentre !== undefined) 97 { 98 if (this.count[category] >= this.count["CivilCentre"] * this.limit[category].LimitPerCivCentre) 99 { 100 var cmpPlayer = Engine.QueryInterface(this.entity, IID_Player); 101 var notification = {"player": cmpPlayer.GetPlayerID(), "message": category+" build limit of "+this.limit[category].LimitPerCivCentre+" per civil centre reached"}; 102 var cmpGUIInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface); 103 cmpGUIInterface.PushNotification(notification); 104 105 return false; 106 } 107 } 108 else if (this.count[category] >= this.limit[category]) 109 { 110 var cmpPlayer = Engine.QueryInterface(this.entity, IID_Player); 111 var notification = {"player": cmpPlayer.GetPlayerID(), "message": category+" train limit of "+this.limit[category]+ " reached"}; 112 var cmpGUIInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface); 113 cmpGUIInterface.PushNotification(notification); 114 115 return false; 116 } 117 118 return true; 119 }; 120 121 EntityLimits.prototype.AllowedToTrain = function(category, count) 122 { 123 // Allow unspecified categories and those with no limit 124 if (this.count[category] === undefined || this.limit[category] === undefined) 125 { 126 return true; 127 } 128 if (this.count[category] + count > this.limit[category]) 129 { 130 var cmpPlayer = Engine.QueryInterface(this.entity, IID_Player); 131 var notification = {"player": cmpPlayer.GetPlayerID(), "message": category+" build limit of "+this.limit[category]+ " reached"}; 132 var cmpGUIInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface); 133 cmpGUIInterface.PushNotification(notification); 134 135 return false; 136 } 137 return true; 138 }; 139 140 EntityLimits.prototype.OnGlobalOwnershipChanged = function(msg) 141 { 142 // This automatically updates entity counts 143 var category = null; 144 var cmpBuildRestrictions = Engine.QueryInterface(msg.entity, IID_BuildRestrictions); 145 if (cmpBuildRestrictions) 146 category = cmpBuildRestrictions.GetCategory(); 147 var cmpTrainingRestrictions = Engine.QueryInterface(msg.entity, IID_TrainingRestrictions); 148 if (cmpTrainingRestrictions) 149 category = cmpTrainingRestrictions.GetCategory(); 150 if (category) 151 { 152 var playerID = (Engine.QueryInterface(this.entity, IID_Player)).GetPlayerID(); 153 if (msg.from == playerID) 154 { 155 this.DecrementCount(category); 156 } 157 if (msg.to == playerID) 158 { 159 this.IncrementCount(category); 160 } 161 } 162 }; 163 164 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 … … 84 84 "phase": phase, 85 85 "isAlly": allies, 86 86 "isEnemy": enemies, 87 " buildLimits": cmpPlayerBuildLimits.GetLimits(),88 " buildCounts": cmpPlayerBuildLimits.GetCounts(),87 "entityLimits": cmpPlayerEntityLimits.GetLimits(), 88 "entityCounts": cmpPlayerEntityLimits.GetCounts(), 89 89 "techModifications": cmpTechnologyManager.GetTechModifications() 90 90 }; 91 91 ret.players.push(playerData); … … 380 380 if (template.BuildRestrictions.Distance.MaxDistance) ret.buildRestrictions.distance.max = +template.BuildRestrictions.Distance.MaxDistance; 381 381 } 382 382 } 383 383 384 if (template.TrainingRestrictions) 385 { 386 ret.trainingRestrictions = { 387 "category": template.TrainingRestrictions.Category, 388 }; 389 } 390 384 391 if (template.Cost) 385 392 { 386 393 ret.cost = {}; … … 449 456 ret.icon = template.Identity.Icon; 450 457 ret.tooltip = template.Identity.Tooltip; 451 458 ret.requiredTechnology = template.Identity.RequiredTechnology; 459 ret.identityClassesString = GetTemplateIdentityClassesString(template); 452 460 } 453 461 454 462 if (template.UnitMotion) -
binaries/data/mods/public/simulation/components/Player.js
358 358 Player.prototype.OnGlobalOwnershipChanged = function(msg) 359 359 { 360 360 var isConquestCritical = false; 361 362 361 // Load class list only if we're going to need it 363 362 if (msg.from == this.playerID || msg.to == this.playerID) 364 363 { 365 364 var cmpIdentity = Engine.QueryInterface(msg.entity, IID_Identity); 366 365 if (cmpIdentity) 367 366 { 368 var classes = cmpIdentity.GetClassesList(); 369 isConquestCritical = classes.indexOf("ConquestCritical") != -1; 367 isConquestCritical = cmpIdentity.HasClass("ConquestCritical"); 370 368 } 371 369 } 372 373 370 if (msg.from == this.playerID) 374 371 { 375 372 if (isConquestCritical) 376 this.conquestCriticalEntitiesCount--; 377 373 this.conquestCriticalEntitiesCount--; 378 374 var cost = Engine.QueryInterface(msg.entity, IID_Cost); 379 375 if (cost) 380 376 { … … 382 378 this.popBonuses -= cost.GetPopBonus(); 383 379 } 384 380 } 385 386 381 if (msg.to == this.playerID) 387 382 { 388 383 if (isConquestCritical) 389 384 this.conquestCriticalEntitiesCount++; 390 391 385 var cost = Engine.QueryInterface(msg.entity, IID_Cost); 392 386 if (cost) 393 387 { -
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"); … … 67 67 IsEnemy: function() { return true; }, 68 68 }); 69 69 70 AddMock(100, IID_ BuildLimits, {70 AddMock(100, IID_EntityLimits, { 71 71 GetLimits: function() { return {"Foo": 10}; }, 72 72 GetCounts: function() { return {"Foo": 5}; }, 73 73 }); … … 118 118 IsEnemy: function() { return false; }, 119 119 }); 120 120 121 AddMock(101, IID_ BuildLimits, {121 AddMock(101, IID_EntityLimits, { 122 122 GetLimits: function() { return {"Bar": 20}; }, 123 123 GetCounts: function() { return {"Bar": 0}; }, 124 124 }); … … 171 171 phase: "", 172 172 isAlly: [false, false, false], 173 173 isEnemy: [true, true, true], 174 buildLimits: {"Foo": 10},175 buildCounts: {"Foo": 5},174 entityLimits: {"Foo": 10}, 175 entityCounts: {"Foo": 5}, 176 176 techModifications: {}, 177 177 }, 178 178 { … … 189 189 phase: "village", 190 190 isAlly: [true, true, true], 191 191 isEnemy: [false, false, false], 192 buildLimits: {"Bar": 20},193 buildCounts: {"Bar": 0},192 entityLimits: {"Bar": 20}, 193 entityCounts: {"Bar": 0}, 194 194 techModifications: {}, 195 195 } 196 196 ], … … 214 214 phase: "", 215 215 isAlly: [false, false, false], 216 216 isEnemy: [true, true, true], 217 buildLimits: {"Foo": 10},218 buildCounts: {"Foo": 5},217 entityLimits: {"Foo": 10}, 218 entityCounts: {"Foo": 5}, 219 219 techModifications: {}, 220 220 statistics: { 221 221 unitsTrained: 10, … … 248 248 phase: "village", 249 249 isAlly: [true, true, true], 250 250 isEnemy: [false, false, false], 251 buildLimits: {"Bar": 20},252 buildCounts: {"Bar": 0},251 entityLimits: {"Bar": 20}, 252 entityCounts: {"Bar": 0}, 253 253 techModifications: {}, 254 254 statistics: { 255 255 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
146 146 147 147 case "train": 148 148 var entities = FilterEntityList(cmd.entities, player, controlAllUnits); 149 150 // Check entity limits 151 var cmpTempMan = Engine.QueryInterface(SYSTEM_ENTITY, IID_TemplateManager); 152 var template = cmpTempMan.GetTemplate(cmd.template); 153 var unitCategory = null; 154 if (template.TrainingRestrictions) 155 unitCategory = template.TrainingRestrictions.Category; 156 149 157 // Verify that the building(s) can be controlled by the player 150 158 if (entities.length > 0) 151 159 { 152 160 for each (var ent in entities) 153 161 { 162 if (unitCategory) 163 { 164 var cmpPlayerEntityLimits = QueryOwnerInterface(ent, IID_EntityLimits); 165 if (!cmpPlayerEntityLimits.AllowedToTrain(unitCategory, cmd.count)) 166 { 167 if (g_DebugCommands) 168 { 169 warn(unitCategory + " train limit is reached: " + uneval(cmd)); 170 } 171 continue; 172 } 173 } 174 154 175 var cmpTechnologyManager = QueryOwnerInterface(ent, IID_TechnologyManager); 155 176 // TODO: Enable this check once the AI gets technology support 156 177 if (cmpTechnologyManager.CanProduce(cmd.template) || true) … … 545 566 return false; 546 567 } 547 568 548 // Check buildlimits549 var cmp BuildLimits = QueryPlayerIDInterface(player, IID_BuildLimits);550 if (!cmp BuildLimits || !cmpBuildLimits.AllowedToBuild(cmpBuildRestrictions.GetCategory()))569 // Check entity limits 570 var cmpEntityLimits = QueryPlayerIDInterface(player, IID_EntityLimits); 571 if (!cmpEntityLimits || !cmpEntityLimits.AllowedToBuild(cmpBuildRestrictions.GetCategory())) 551 572 { 552 573 if (g_DebugCommands) 553 574 { -
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>