Ticket #1432: one_hero_2012_07_22.diff
File one_hero_2012_07_22.diff, 43.5 KB (added by , 12 years ago) |
---|
-
binaries/data/mods/public/gui/session/input.js
1439 1439 } 1440 1440 1441 1441 // Called by GUI when user clicks training button 1442 function addTrainingToQueue(selection, trainEntType )1442 function addTrainingToQueue(selection, trainEntType, playerState) 1443 1443 { 1444 // Create list of buildings which can train trainEntType 1445 var appropriateBuildings = []; 1446 for each (var selectedEntity in selection) 1447 { 1448 var state = GetEntityState(selectedEntity); 1449 var canTrain = state && state.production && state.production.entities.length && state.production.entities.indexOf(trainEntType) != -1; 1450 appropriateBuildings.push(selectedEntity); 1451 } 1452 1453 // Check trainEntType entity limit and count 1454 template = GetTemplateData(trainEntType); 1455 var trainingCategory = null; 1456 if (template.trainingRestrictions) 1457 trainingCategory = template.trainingRestrictions.category; 1458 var trainEntLimit = undefined; 1459 var trainEntCount = undefined; 1460 if (trainingCategory && playerState.entityLimits[trainingCategory]) 1461 { 1462 trainEntLimit = playerState.entityLimits[trainingCategory]; 1463 trainEntCount = playerState.entityCounts[trainingCategory] 1464 } 1465 1444 1466 if (Engine.HotkeyIsPressed("session.batchtrain")) 1445 1467 { 1446 1468 if (inputState == INPUT_BATCHTRAINING) … … 1477 1499 } 1478 1500 else 1479 1501 { 1480 // Non-batched - just create a single entity 1481 Engine.PostNetworkCommand({"type": "train", "template": trainEntType, "count": 1, "entities": selection}); 1502 // Non-batched - just create a single entity in each building 1503 // (but no more than entity limit allows) 1504 var buildingsForTraining = appropriateBuildings; 1505 if (trainEntLimit) 1506 { 1507 var canBeTrainedCount = trainEntLimit - trainEntCount; 1508 buildingsForTraining = buildingsForTraining.slice(0, canBeTrainedCount); 1509 } 1510 Engine.PostNetworkCommand({"type": "train", "template": trainEntType, "count": 1, "entities": buildingsForTraining}); 1482 1511 } 1483 1512 } 1484 1513 -
binaries/data/mods/public/gui/session/unit_commands.js
150 150 * @param items Panel-specific data to construct the icons with. 151 151 * @param callback Callback function to argument to execute when an item's icon gets clicked. Takes a single 'item' argument. 152 152 */ 153 function setupUnitPanel(guiName, usedPanels, unitEntState, items, callback)153 function setupUnitPanel(guiName, usedPanels, unitEntState, playerState, items, callback) 154 154 { 155 155 usedPanels[guiName] = 1; 156 156 … … 359 359 tooltip += "\n" + getEntitySpeed(template); 360 360 361 361 tooltip += "\n\n[font=\"serif-bold-13\"]Shift-click[/font][font=\"serif-13\"] to train " + trainNum + ".[/font]"; 362 363 362 break; 364 363 365 364 case RESEARCH: … … 507 506 { 508 507 icon.sprite = "stretched:session/icons/" + item.icon; 509 508 } 509 else if (guiName == TRAINING) 510 { 511 if (template.icon) 512 { 513 var trainingCategory = null; 514 if (template.trainingRestrictions) 515 trainingCategory = template.trainingRestrictions.category; 516 var grayscale = ""; 517 if (trainingCategory && playerState.entityLimits[trainingCategory] && playerState.entityCounts[trainingCategory] >= playerState.entityLimits[trainingCategory]) 518 grayscale = "grayscale:"; 519 icon.sprite = "stretched:" + grayscale + "session/portraits/" + template.icon; 520 } 521 } 510 522 else if (guiName == GATE) 511 523 { 512 524 var gateIcon; … … 671 683 } 672 684 673 685 // Sets up "unit barter panel" - special case for setupUnitPanel 674 function setupUnitBarterPanel(unitEntState )686 function setupUnitBarterPanel(unitEntState, playerState) 675 687 { 676 688 // Amount of player's resource to exchange 677 689 var amountToSell = BARTER_RESOURCE_AMOUNT_TO_SELL; … … 750 762 var player = Engine.GetPlayerID(); 751 763 if (entState.player == player || g_DevSettings.controlAll) 752 764 { 765 // Get player state to check some constraints 766 // e.g. presence of a hero or build limits 767 var simState = Engine.GuiInterfaceCall("GetSimulationState"); 768 var playerState = simState.players[player]; 769 753 770 if (selection.length > 1) 754 setupUnitPanel(SELECTION, usedPanels, entState, g_Selection.groups.getTemplateNames(),771 setupUnitPanel(SELECTION, usedPanels, entState, playerState, g_Selection.groups.getTemplateNames(), 755 772 function (entType) { changePrimarySelectionGroup(entType); } ); 756 773 757 774 var commands = getEntityCommandsList(entState); 758 775 if (commands.length) 759 setupUnitPanel(COMMAND, usedPanels, entState, commands,776 setupUnitPanel(COMMAND, usedPanels, entState, playerState, commands, 760 777 function (item) { performCommand(entState.id, item.name); } ); 761 778 762 779 if (entState.garrisonHolder) 763 780 { 764 781 var groups = new EntityGroups(); 765 782 groups.add(entState.garrisonHolder.entities); 766 setupUnitPanel(GARRISON, usedPanels, entState, groups.getTemplateNames(),783 setupUnitPanel(GARRISON, usedPanels, entState, playerState, groups.getTemplateNames(), 767 784 function (item) { unload(entState.id, groups.getEntsByName(item)); } ); 768 785 } 769 786 770 787 var formations = Engine.GuiInterfaceCall("GetAvailableFormations"); 771 788 if (hasClass(entState, "Unit") && !hasClass(entState, "Animal") && !entState.garrisonHolder && formations.length) 772 789 { 773 setupUnitPanel(FORMATION, usedPanels, entState, formations,790 setupUnitPanel(FORMATION, usedPanels, entState, playerState, formations, 774 791 function (item) { performFormation(entState.id, item); } ); 775 792 } 776 793 … … 779 796 var stances = ["violent", "aggressive", "passive", "defensive", "standground"]; 780 797 if (hasClass(entState, "Unit") && !hasClass(entState, "Animal") && !entState.garrisonHolder && stances.length) 781 798 { 782 setupUnitPanel(STANCE, usedPanels, entState, stances,799 setupUnitPanel(STANCE, usedPanels, entState, playerState, stances, 783 800 function (item) { performStance(entState.id, item); } ); 784 801 } 785 802 … … 787 804 if (entState.barterMarket) 788 805 { 789 806 usedPanels["Barter"] = 1; 790 setupUnitBarterPanel(entState );807 setupUnitBarterPanel(entState, playerState); 791 808 } 792 809 793 810 var buildableEnts = []; … … 808 825 809 826 // The first selected entity's type has priority. 810 827 if (entState.buildEntities) 811 setupUnitPanel(CONSTRUCTION, usedPanels, entState, buildableEnts, startBuildingPlacement);828 setupUnitPanel(CONSTRUCTION, usedPanels, entState, playerState, buildableEnts, startBuildingPlacement); 812 829 else if (entState.production && entState.production.entities) 813 setupUnitPanel(TRAINING, usedPanels, entState, trainableEnts,814 function (trainEntType) { addTrainingToQueue(selection, trainEntType ); } );830 setupUnitPanel(TRAINING, usedPanels, entState, playerState, trainableEnts, 831 function (trainEntType) { addTrainingToQueue(selection, trainEntType, playerState); } ); 815 832 else if (entState.trader) 816 833 setupUnitTradingPanel(usedPanels, entState, selection); 817 834 else … … 822 839 setupUnitPanel(CONSTRUCTION, usedPanels, entState, buildableEnts, startBuildingPlacement); 823 840 else if (trainableEnts.length) 824 841 setupUnitPanel(TRAINING, usedPanels, entState, trainableEnts, 825 function (trainEntType) { addTrainingToQueue(selection, trainEntType ); } );842 function (trainEntType) { addTrainingToQueue(selection, trainEntType, playerState); } ); 826 843 } 827 844 828 845 // Show technologies if the active panel has at most one row of icons. … … 835 852 } 836 853 837 854 if (entState.production && entState.production.queue.length) 838 setupUnitPanel(QUEUE, usedPanels, entState, entState.production.queue,855 setupUnitPanel(QUEUE, usedPanels, entState, playerState, entState.production.queue, 839 856 function (item) { removeFromProductionQueue(entState.id, item.id); } ); 840 857 841 858 if(!entState.foundation && (entState.gate || hasClass(entState, "LongWall"))) -
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/helpers/Commands.js
142 142 143 143 case "train": 144 144 var entities = FilterEntityList(cmd.entities, player, controlAllUnits); 145 146 // Check entity limits 147 var cmpTempMan = Engine.QueryInterface(SYSTEM_ENTITY, IID_TemplateManager); 148 var template = cmpTempMan.GetTemplate(cmd.template); 149 var unitCategory = null; 150 if (template.TrainingRestrictions) 151 unitCategory = template.TrainingRestrictions.Category; 152 145 153 // Verify that the building(s) can be controlled by the player 146 154 if (entities.length > 0) 147 155 { 148 156 for each (var ent in entities) 149 157 { 158 if (unitCategory) 159 { 160 var cmpPlayerEntityLimits = QueryOwnerInterface(ent, IID_EntityLimits); 161 if (!cmpPlayerEntityLimits.AllowedToTrain(unitCategory, cmd.count)) 162 { 163 if (g_DebugCommands) 164 { 165 warn(unitCategory + " train limit is reached: "+uneval(cmd)); 166 } 167 continue; 168 } 169 } 170 150 171 var cmpTechMan = QueryOwnerInterface(ent, IID_TechnologyManager); 151 172 // TODO: Enable this check once the AI gets technology support 152 173 if (cmpTechMan.CanProduce(cmd.template) || true) … … 524 545 return false; 525 546 } 526 547 527 // Check buildlimits528 var cmp BuildLimits = QueryPlayerIDInterface(player, IID_BuildLimits);529 if (!cmp BuildLimits || !cmpBuildLimits.AllowedToBuild(cmpBuildRestrictions.GetCategory()))548 // Check entity limits 549 var cmpEntityLimits = QueryPlayerIDInterface(player, IID_EntityLimits); 550 if (!cmpEntityLimits || !cmpEntityLimits.AllowedToBuild(cmpBuildRestrictions.GetCategory())) 530 551 { 531 552 if (g_DebugCommands) 532 553 { -
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); … … 373 373 if (template.BuildRestrictions.Distance.MaxDistance) ret.buildRestrictions.distance.max = +template.BuildRestrictions.Distance.MaxDistance; 374 374 } 375 375 } 376 376 377 if (template.TrainingRestrictions) 378 { 379 ret.trainingRestrictions = { 380 "category": template.TrainingRestrictions.Category, 381 }; 382 } 383 377 384 if (template.Cost) 378 385 { 379 386 ret.cost = {}; … … 442 449 ret.icon = template.Identity.Icon; 443 450 ret.tooltip = template.Identity.Tooltip; 444 451 ret.requiredTechnology = template.Identity.RequiredTechnology; 452 ret.identityClassesString = GetTemplateIdentityClassesString(template); 445 453 } 446 454 447 455 if (template.UnitMotion) -
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/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/components/ProductionQueue.js
199 199 if (!cmpPlayer.TrySubtractResources(totalCosts)) 200 200 return; 201 201 202 // Update entity count in the EntityLimits component 203 if (template.TrainingRestrictions) 204 { 205 var unitCategory = template.TrainingRestrictions.Category; 206 var cmpPlayerEntityLimits = QueryOwnerInterface(this.entity, IID_EntityLimits); 207 cmpPlayerEntityLimits.IncreaseCount(unitCategory, count); 208 } 209 202 210 this.queue.push({ 203 211 "id": this.nextID++, 204 212 "player": cmpPlayer.GetPlayerID(), … … 292 300 293 301 var cmpPlayer = QueryPlayerIDInterface(item.player, IID_Player); 294 302 303 // Update entity count in the EntityLimits component 304 if (item.unitTemplate) 305 { 306 var cmpTempMan = Engine.QueryInterface(SYSTEM_ENTITY, IID_TemplateManager); 307 var template = cmpTempMan.GetTemplate(item.unitTemplate); 308 if (template.TrainingRestrictions) 309 { 310 var unitCategory = template.TrainingRestrictions.Category; 311 var cmpPlayerEntityLimits = QueryOwnerInterface(this.entity, IID_EntityLimits); 312 cmpPlayerEntityLimits.DecreaseCount(unitCategory, item.count); 313 } 314 } 315 295 316 // Refund the resource cost for this batch 296 317 var totalCosts = {}; 297 318 for each (var r in ["food", "wood", "stone", "metal"]) … … 401 422 // so only create them once and use as needed 402 423 for (var i = 0; i < count; ++i) 403 424 { 404 this.entityCache.push(Engine.AddEntity(templateName)); 425 var ent = Engine.AddEntity(templateName); 426 this.entityCache.push(ent); 427 428 // Decrement entity count in the EntityLimits component 429 // since it will be increased by EntityLimits.OnGlobalOwnershipChanged function, 430 // i.e. we replace a 'trained' entity to an 'alive' one 431 var cmpTrainingRestrictions = Engine.QueryInterface(ent, IID_TrainingRestrictions); 432 if (cmpTrainingRestrictions) 433 { 434 var unitCategory = cmpTrainingRestrictions.GetCategory(); 435 var cmpPlayerEntityLimits = QueryOwnerInterface(this.entity, IID_EntityLimits); 436 cmpPlayerEntityLimits.DecrementCount(unitCategory); 437 } 405 438 } 406 439 } 407 440 -
binaries/data/mods/public/simulation/components/Player.js
343 343 Player.prototype.OnGlobalOwnershipChanged = function(msg) 344 344 { 345 345 var isConquestCritical = false; 346 347 346 // Load class list only if we're going to need it 348 347 if (msg.from == this.playerID || msg.to == this.playerID) 349 348 { 350 349 var cmpIdentity = Engine.QueryInterface(msg.entity, IID_Identity); 351 350 if (cmpIdentity) 352 351 { 353 var classes = cmpIdentity.GetClassesList(); 354 isConquestCritical = classes.indexOf("ConquestCritical") != -1; 352 isConquestCritical = cmpIdentity.HasClass("ConquestCritical"); 355 353 } 356 354 } 357 358 355 if (msg.from == this.playerID) 359 356 { 360 357 if (isConquestCritical) 361 this.conquestCriticalEntitiesCount--; 362 358 this.conquestCriticalEntitiesCount--; 363 359 var cost = Engine.QueryInterface(msg.entity, IID_Cost); 364 360 if (cost) 365 361 { … … 367 363 this.popBonuses -= cost.GetPopBonus(); 368 364 } 369 365 } 370 371 366 if (msg.to == this.playerID) 372 367 { 373 368 if (isConquestCritical) 374 369 this.conquestCriticalEntitiesCount++; 375 376 370 var cost = Engine.QueryInterface(msg.entity, IID_Cost); 377 371 if (cost) 378 372 { -
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/interfaces/TrainingRestrictions.js
1 Engine.RegisterInterface("TrainingRestrictions"); 2 -
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/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/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/qbot/gamestate.js
300 300 return this.updatingCollection("resource-" + resource, Filters.byResource(resource), this.getEntities()); 301 301 }; 302 302 303 GameState.prototype.get BuildLimits = function() {304 return this.playerData. buildLimits;303 GameState.prototype.getEntityLimits = function() { 304 return this.playerData.entityLimits; 305 305 }; 306 306 307 GameState.prototype.get BuildCounts = function() {308 return this.playerData. buildCounts;307 GameState.prototype.getEntityCounts = function() { 308 return this.playerData.entityCounts; 309 309 }; 310 310 311 311 // Checks whether the maximum number of buildings have been cnstructed for a certain catergory 312 GameState.prototype.is BuildLimitReached = function(category) {313 if(this.playerData. buildLimits[category] === undefined || this.playerData.buildCounts[category] === undefined)312 GameState.prototype.isEntityLimitReached = function(category) { 313 if(this.playerData.entityLimits[category] === undefined || this.playerData.entityCounts[category] === undefined) 314 314 return false; 315 if(this.playerData. buildLimits[category].LimitsPerCivCentre != undefined)316 return (this.playerData. buildCounts[category] >= this.playerData.buildCounts["CivilCentre"]*this.playerData.buildLimits[category].LimitPerCivCentre);315 if(this.playerData.entityLimits[category].LimitsPerCivCentre != undefined) 316 return (this.playerData.entityCounts[category] >= this.playerData.entityCounts["CivilCentre"]*this.playerData.entityLimits[category].LimitPerCivCentre); 317 317 else 318 return (this.playerData. buildCounts[category] >= this.playerData.buildLimits[category]);318 return (this.playerData.entityCounts[category] >= this.playerData.entityLimits[category]); 319 319 }; -
binaries/data/mods/public/simulation/ai/jubot/gamestate.js
415 415 * Returns player build limits 416 416 * an object where each key is a category corresponding to a build limit for the player. 417 417 */ 418 get BuildLimits: function()418 getEntityLimits: function() 419 419 { 420 return this.playerData. buildLimits;420 return this.playerData.entityLimits; 421 421 }, 422 422 423 423 /** 424 424 * Returns player build counts 425 425 * an object where each key is a category corresponding to the current building count for the player. 426 426 */ 427 get BuildCounts: function()427 getEntityCounts: function() 428 428 { 429 return this.playerData. buildCounts;429 return this.playerData.entityCounts; 430 430 }, 431 431 432 432 /** 433 433 * Checks if the player's build limit has been reached for the given category. 434 434 * The category comes from the entity tenplate, specifically the BuildRestrictions component. 435 435 */ 436 is BuildLimitReached: function(category)436 isEntityLimitReached: function(category) 437 437 { 438 if (this.playerData. buildLimits[category] === undefined || this.playerData.buildCounts[category] === undefined)438 if (this.playerData.entityLimits[category] === undefined || this.playerData.entityCounts[category] === undefined) 439 439 return false; 440 440 441 441 // There's a special case of build limits per civ centre, so check that first 442 if (this.playerData. buildLimits[category].LimitPerCivCentre !== undefined)443 return (this.playerData. buildCounts[category] >= this.playerData.buildCounts["CivilCentre"]*this.playerData.buildLimits[category].LimitPerCivCentre);442 if (this.playerData.entityLimits[category].LimitPerCivCentre !== undefined) 443 return (this.playerData.entityCounts[category] >= this.playerData.entityCounts["CivilCentre"]*this.playerData.entityLimits[category].LimitPerCivCentre); 444 444 else 445 return (this.playerData. buildCounts[category] >= this.playerData.buildLimits[category]);445 return (this.playerData.entityCounts[category] >= this.playerData.entityLimits[category]); 446 446 }, 447 447 }); -
binaries/data/mods/public/simulation/ai/testbot/gamestate.js
268 268 * Returns player build limits 269 269 * an object where each key is a category corresponding to a build limit for the player. 270 270 */ 271 get BuildLimits: function()271 getEntityLimits: function() 272 272 { 273 return this.playerData. buildLimits;273 return this.playerData.entityLimits; 274 274 }, 275 275 276 276 /** 277 * Returns player buildcounts278 * an object where each key is a category corresponding to the current buildingcount for the player.277 * Returns player entity counts 278 * an object where each key is a category corresponding to the current entity count for the player. 279 279 */ 280 get BuildCounts: function()280 getEntityCounts: function() 281 281 { 282 return this.playerData. buildCounts;282 return this.playerData.entityCounts; 283 283 }, 284 284 285 285 /** 286 * Checks if the player's buildlimit has been reached for the given category.286 * Checks if the player's entity limit has been reached for the given category. 287 287 * The category comes from the entity tenplate, specifically the BuildRestrictions component. 288 288 */ 289 is BuildLimitReached: function(category)289 isEntityLimitReached: function(category) 290 290 { 291 if (this.playerData. buildLimits[category] === undefined || this.playerData.buildCounts[category] === undefined)291 if (this.playerData.entityLimits[category] === undefined || this.playerData.entityCounts[category] === undefined) 292 292 return false; 293 293 294 294 // There's a special case of build limits per civ centre, so check that first 295 if (this.playerData. buildLimits[category].LimitPerCivCentre !== undefined)296 return (this.playerData. buildCounts[category] >= this.playerData.buildCounts["CivilCentre"]*this.playerData.buildLimits[category].LimitPerCivCentre);295 if (this.playerData.entityLimits[category].LimitPerCivCentre !== undefined) 296 return (this.playerData.entityCounts[category] >= this.playerData.entityCounts["CivilCentre"]*this.playerData.entityLimits[category].LimitPerCivCentre); 297 297 else 298 return (this.playerData. buildCounts[category] >= this.playerData.buildLimits[category]);298 return (this.playerData.entityCounts[category] >= this.playerData.entityLimits[category]); 299 299 }, 300 300 }); -
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/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>6</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_cavalry.xml
69 69 <Stamina> 70 70 <Max>2500</Max> 71 71 </Stamina> 72 <TrainingRestrictions> 73 <Category>Hero</Category> 74 </TrainingRestrictions> 72 75 <UnitMotion> 73 76 <WalkSpeed>11.0</WalkSpeed> 74 77 <Run> -
binaries/data/mods/public/simulation/templates/template_unit_hero.xml
62 62 <death>actor/human/death/death.xml</death> 63 63 </SoundGroups> 64 64 </Sound> 65 <TrainingRestrictions> 66 <Category>Hero</Category> 67 </TrainingRestrictions> 65 68 <UnitMotion> 66 69 <WalkSpeed>9.0</WalkSpeed> 67 70 <Run> -
binaries/data/mods/public/simulation/templates/template_unit_hero_infantry.xml
67 67 <Stamina> 68 68 <Max>1500</Max> 69 69 </Stamina> 70 <TrainingRestrictions> 71 <Category>Hero</Category> 72 </TrainingRestrictions> 70 73 <UnitMotion> 71 74 <WalkSpeed>8.5</WalkSpeed> 72 75 <Run> -
binaries/data/mods/public/simulation/templates/template_unit_hero_infantry_archer.xml
61 61 </Texture> 62 62 </Overlay> 63 63 </Selectable> 64 <TrainingRestrictions> 65 <Category>Hero</Category> 66 </TrainingRestrictions> 64 67 </Entity> -
binaries/data/mods/public/simulation/templates/template_unit_hero_infantry_javelinist.xml
65 65 </Texture> 66 66 </Overlay> 67 67 </Selectable> 68 <TrainingRestrictions> 69 <Category>Hero</Category> 70 </TrainingRestrictions> 68 71 </Entity> -
binaries/data/mods/public/simulation/templates/template_unit_hero_cavalry_archer.xml
69 69 </Texture> 70 70 </Overlay> 71 71 </Selectable> 72 <TrainingRestrictions> 73 <Category>Hero</Category> 74 </TrainingRestrictions> 72 75 <UnitMotion> 73 76 <WalkSpeed>11.0</WalkSpeed> 74 77 <Run> -
binaries/data/mods/public/simulation/templates/template_unit_hero_cavalry_javelinist.xml
59 59 </Texture> 60 60 </Overlay> 61 61 </Selectable> 62 <TrainingRestrictions> 63 <Category>Hero</Category> 64 </TrainingRestrictions> 62 65 <UnitMotion> 63 66 <WalkSpeed>11.5</WalkSpeed> 64 67 <Run> -
binaries/data/mods/public/simulation/templates/template_unit_support_female_citizen.xml
91 91 <Stamina> 92 92 <Max>500</Max> 93 93 </Stamina> 94 <TrainingRestrictions> 95 <Category>FemaleCitizen</Category> 96 </TrainingRestrictions> 94 97 <UnitMotion> 95 98 <WalkSpeed>8.0</WalkSpeed> 96 99 <Run>