Index: ps/trunk/binaries/data/mods/public/simulation/components/tests/test_Barter.js =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/components/tests/test_Barter.js (revision 22379) +++ ps/trunk/binaries/data/mods/public/simulation/components/tests/test_Barter.js (revision 22380) @@ -1,194 +1,193 @@ Engine.LoadHelperScript("Player.js"); Engine.LoadComponentScript("interfaces/Barter.js"); Engine.LoadComponentScript("interfaces/Foundation.js"); Engine.LoadComponentScript("interfaces/Player.js"); Engine.LoadComponentScript("interfaces/StatisticsTracker.js"); Engine.LoadComponentScript("interfaces/Timer.js"); Engine.LoadComponentScript("Barter.js"); // truePrice. Use the same for each resource for those tests. const truePrice = 110; Resources = { "GetCodes": () => ["wood", "stone", "metal"], "GetResource": (resource) => ({ "truePrice": truePrice }) }; const playerID = 1; const playerEnt = 11; AddMock(SYSTEM_ENTITY, IID_PlayerManager, { "GetPlayerByID": id => playerEnt }); let timerActivated = false; let bought = 0; let sold = 0; let multiplier = { "buy": { "wood": 1.0, "stone": 1.0, "metal": 1.0 }, "sell": { "wood": 1.0, "stone": 1.0, "metal": 1.0 } }; +let cmpBarter = ConstructComponent(SYSTEM_ENTITY, "Barter"); AddMock(SYSTEM_ENTITY, IID_Timer, { "CancelTimer": id => { timerActivated = false; }, "SetInterval": (ent, iid, funcname, time, repeattime, data) => { TS_ASSERT_EQUALS(time, cmpBarter.RESTORE_TIMER_INTERVAL); TS_ASSERT_EQUALS(repeattime, cmpBarter.RESTORE_TIMER_INTERVAL); timerActivated = true; return 7; } }); -let cmpBarter = ConstructComponent(SYSTEM_ENTITY, "Barter"); - // Init TS_ASSERT_EQUALS(cmpBarter.restoreTimer, undefined); TS_ASSERT_UNEVAL_EQUALS(cmpBarter.priceDifferences, { "wood": 0, "stone": 0, "metal": 0 }); AddMock(playerEnt, IID_Player, { "TrySubtractResources": amounts => { sold = amounts[Object.keys(amounts)[0]]; return true; }, "AddResource": (type, amount) => { bought = amount; return true; }, "GetBarterMultiplier": () => multiplier }); AddMock(SYSTEM_ENTITY, IID_RangeManager, { "GetEntitiesByPlayer": (id) => id == playerID ? [62, 60, 61, 63] : [] }); AddMock(60, IID_Identity, { "HasClass": (cl) => true }); AddMock(60, IID_Foundation, {}); // GetPrices cmpBarter.priceDifferences = { "wood": 8, "stone": 0, "metal": 0 }; TS_ASSERT_UNEVAL_EQUALS(cmpBarter.GetPrices(playerID).buy, { "wood": truePrice * (100 + 8 + cmpBarter.CONSTANT_DIFFERENCE) / 100, "stone": truePrice * (100 + cmpBarter.CONSTANT_DIFFERENCE) / 100, "metal": truePrice * (100 + cmpBarter.CONSTANT_DIFFERENCE) / 100 }); TS_ASSERT_UNEVAL_EQUALS(cmpBarter.GetPrices(playerID).sell, { "wood": truePrice * (100 + 8 - cmpBarter.CONSTANT_DIFFERENCE) / 100, "stone": truePrice * (100 - cmpBarter.CONSTANT_DIFFERENCE) / 100, "metal": truePrice * (100 - cmpBarter.CONSTANT_DIFFERENCE) / 100 }); multiplier.buy.stone = 2.0; TS_ASSERT_UNEVAL_EQUALS(cmpBarter.GetPrices(playerID).buy, { "wood": truePrice * (100 + 8 + cmpBarter.CONSTANT_DIFFERENCE) / 100, "stone": truePrice * (100 + cmpBarter.CONSTANT_DIFFERENCE) * 2.0 / 100, "metal": truePrice * (100 + cmpBarter.CONSTANT_DIFFERENCE) / 100 }); TS_ASSERT_UNEVAL_EQUALS(cmpBarter.GetPrices(playerID).sell, { "wood": truePrice * (100 + 8 - cmpBarter.CONSTANT_DIFFERENCE) / 100, "stone": truePrice * (100 - cmpBarter.CONSTANT_DIFFERENCE) / 100, "metal": truePrice * (100 - cmpBarter.CONSTANT_DIFFERENCE) / 100 }); multiplier.buy.stone = 1.0; // PlayerHasMarket TS_ASSERT(!cmpBarter.PlayerHasMarket(playerID)); AddMock(61, IID_Identity, { "HasClass": (cl) => true }); TS_ASSERT(cmpBarter.PlayerHasMarket(playerID)); // ExchangeResources // Price differences magnitude are caped by 99 - CONSTANT_DIFFERENCE. // If we have a bigger DIFFERENCE_PER_DEAL than 99 - CONSTANT_DIFFERENCE at each deal we reach the cap. TS_ASSERT(cmpBarter.DIFFERENCE_PER_DEAL < 99 - cmpBarter.CONSTANT_DIFFERENCE); cmpBarter.priceDifferences = { "wood": 0, "stone": 0, "metal": 0 }; cmpBarter.ExchangeResources(playerID, "wood", "stone", 100); TS_ASSERT_EQUALS(cmpBarter.restoreTimer, 7); TS_ASSERT(timerActivated); TS_ASSERT_UNEVAL_EQUALS(cmpBarter.priceDifferences, { "wood": -cmpBarter.DIFFERENCE_PER_DEAL, "stone": cmpBarter.DIFFERENCE_PER_DEAL, "metal": 0 }); TS_ASSERT_EQUALS(sold, 100); TS_ASSERT_EQUALS(bought, Math.round(100 * (100 - cmpBarter.CONSTANT_DIFFERENCE + 0) / (100 + cmpBarter.CONSTANT_DIFFERENCE + 0))); // Amount which is not 100 or 500 is invalid. cmpBarter.priceDifferences = { "wood": 0, "stone": 0, "metal": 0 }; cmpBarter.ExchangeResources(playerID, "wood", "stone", 40); bought = 0; sold = 0; timerActivated = false; TS_ASSERT(!timerActivated); TS_ASSERT_UNEVAL_EQUALS(cmpBarter.priceDifferences, { "wood": 0, "stone": 0, "metal": 0 }); TS_ASSERT_EQUALS(sold, 0); TS_ASSERT_EQUALS(bought, 0); // Amount which is NaN is invalid. cmpBarter.priceDifferences = { "wood": 0, "stone": 0, "metal": 0 }; cmpBarter.ExchangeResources(playerID, "wood", "stone", NaN); TS_ASSERT(!timerActivated); TS_ASSERT_UNEVAL_EQUALS(cmpBarter.priceDifferences, { "wood": 0, "stone": 0, "metal": 0 }); TS_ASSERT_EQUALS(sold, 0); TS_ASSERT_EQUALS(bought, 0); cmpBarter.priceDifferences = { "wood": 0, "stone": 99 - cmpBarter.CONSTANT_DIFFERENCE, "metal": 0 }; cmpBarter.ExchangeResources(playerID, "wood", "stone", 100); TS_ASSERT_UNEVAL_EQUALS(cmpBarter.priceDifferences, { "wood": -cmpBarter.DIFFERENCE_PER_DEAL, "stone": 99 - cmpBarter.CONSTANT_DIFFERENCE, "metal": 0 }); TS_ASSERT_EQUALS(bought, Math.round(100 * (100 - cmpBarter.CONSTANT_DIFFERENCE + 0) / (100 + cmpBarter.CONSTANT_DIFFERENCE + 99 - cmpBarter.CONSTANT_DIFFERENCE))); cmpBarter.priceDifferences = { "wood": -99 + cmpBarter.CONSTANT_DIFFERENCE, "stone": 0, "metal": 0 }; cmpBarter.ExchangeResources(playerID, "wood", "stone", 100); TS_ASSERT_UNEVAL_EQUALS(cmpBarter.priceDifferences, { "wood": -99 + cmpBarter.CONSTANT_DIFFERENCE, "stone": cmpBarter.DIFFERENCE_PER_DEAL, "metal": 0 }); TS_ASSERT_EQUALS(bought, Math.round(100 * (100 - cmpBarter.CONSTANT_DIFFERENCE - 99 + cmpBarter.CONSTANT_DIFFERENCE) / (100 + cmpBarter.CONSTANT_DIFFERENCE + 0))); cmpBarter.priceDifferences = { "wood": 0, "stone": 0, "metal": 0 }; cmpBarter.restoreTimer = undefined; timerActivated = false; AddMock(playerEnt, IID_Player, { "TrySubtractResources": () => false, "AddResource": () => {}, "GetBarterMultiplier": () => multiplier }); cmpBarter.ExchangeResources(playerID, "wood", "stone", 100); // It seems useless to try to activate the timer if we don't barter any resources. TS_ASSERT_EQUALS(cmpBarter.restoreTimer, 7); TS_ASSERT(timerActivated); TS_ASSERT_UNEVAL_EQUALS(cmpBarter.priceDifferences, { "wood": 0, "stone": 0, "metal": 0 }); DeleteMock(playerEnt, IID_Player); // ProgressTimeout // Price difference restoration magnitude is capped by DIFFERENCE_RESTORE. AddMock(playerEnt, IID_Player, { "TrySubtractResources": () => true, "AddResource": () => {} }); timerActivated = true; cmpBarter.restoreTimer = 7; cmpBarter.priceDifferences = { "wood": -cmpBarter.DIFFERENCE_RESTORE, "stone": -1 - cmpBarter.DIFFERENCE_RESTORE, "metal": cmpBarter.DIFFERENCE_RESTORE }; cmpBarter.ProgressTimeout(); TS_ASSERT_EQUALS(cmpBarter.restoreTimer, 7); TS_ASSERT(timerActivated); TS_ASSERT_UNEVAL_EQUALS(cmpBarter.priceDifferences, { "wood": 0, "stone": -1, "metal": 0 }); cmpBarter.restoreTimer = 7; cmpBarter.priceDifferences = { "wood": -cmpBarter.DIFFERENCE_RESTORE, "stone": cmpBarter.DIFFERENCE_RESTORE / 2, "metal": cmpBarter.DIFFERENCE_RESTORE }; cmpBarter.ProgressTimeout(); TS_ASSERT_EQUALS(cmpBarter.restoreTimer, undefined); TS_ASSERT(!timerActivated); TS_ASSERT_UNEVAL_EQUALS(cmpBarter.priceDifferences, { "wood": 0, "stone": 0, "metal": 0 }); Index: ps/trunk/binaries/data/mods/public/simulation/components/tests/test_Foundation.js =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/components/tests/test_Foundation.js (revision 22379) +++ ps/trunk/binaries/data/mods/public/simulation/components/tests/test_Foundation.js (revision 22380) @@ -1,210 +1,211 @@ Engine.LoadHelperScript("Player.js"); Engine.LoadComponentScript("interfaces/Builder.js"); Engine.LoadComponentScript("interfaces/Cost.js"); Engine.LoadComponentScript("interfaces/Foundation.js"); Engine.LoadComponentScript("interfaces/Health.js"); Engine.LoadComponentScript("interfaces/StatisticsTracker.js"); Engine.LoadComponentScript("interfaces/TerritoryDecay.js"); Engine.LoadComponentScript("interfaces/Trigger.js"); Engine.LoadComponentScript("Foundation.js"); let player = 1; let playerEnt = 3; let foundationEnt = 20; let previewEnt = 21; let newEnt = 22; function testFoundation(...mocks) { ResetState(); + let finalTemplate = "structures/athen_civil_centre.xml"; + let foundationHP = 1; + let maxHP = 100; + let rot = new Vector3D(1, 2, 3); + let pos = new Vector2D(4, 5); + let cmpFoundation; + AddMock(SYSTEM_ENTITY, IID_Trigger, { "CallEvent": () => {}, }); AddMock(SYSTEM_ENTITY, IID_PlayerManager, { "GetPlayerByID": () => playerEnt, }); AddMock(SYSTEM_ENTITY, IID_TerritoryManager, { "GetOwner": (x, y) => { TS_ASSERT_EQUALS(x, pos.x); TS_ASSERT_EQUALS(y, pos.y); return player; }, }); Engine.RegisterGlobal("PlaySound", (name, source) => { TS_ASSERT_EQUALS(name, "constructed"); TS_ASSERT_EQUALS(source, newEnt); }); Engine.RegisterGlobal("MT_EntityRenamed", "entityRenamed"); - let finalTemplate = "structures/athen_civil_centre.xml"; - let foundationHP = 1; - let maxHP = 100; - let rot = new Vector3D(1, 2, 3); - let pos = new Vector2D(4, 5); - AddMock(foundationEnt, IID_Cost, { "GetBuildTime": () => 50, "GetResourceCosts": () => ({ "wood": 100 }), }); AddMock(foundationEnt, IID_Health, { "GetHitpoints": () => foundationHP, "GetMaxHitpoints": () => maxHP, "Increase": hp => { foundationHP = Math.min(foundationHP + hp, maxHP); cmpFoundation.OnHealthChanged(); }, }); AddMock(foundationEnt, IID_Obstruction, { "GetBlockMovementFlag": () => true, "GetEntitiesBlockingConstruction": () => [], "GetEntitiesDeletedUponConstruction": () => [], "SetDisableBlockMovementPathfinding": () => {}, }); AddMock(foundationEnt, IID_Ownership, { "GetOwner": () => player, }); AddMock(foundationEnt, IID_Position, { "GetPosition2D": () => pos, "GetRotation": () => rot, "SetConstructionProgress": () => {}, "IsInWorld": () => true, }); AddMock(previewEnt, IID_Ownership, { "SetOwner": owner => { TS_ASSERT_EQUALS(owner, player); }, }); AddMock(previewEnt, IID_Position, { "JumpTo": (x, y) => { TS_ASSERT_EQUALS(x, pos.x); TS_ASSERT_EQUALS(y, pos.y); }, "SetConstructionProgress": p => {}, "SetYRotation": r => { TS_ASSERT_EQUALS(r, rot.y); }, "SetXZRotation": (rx, rz) => { TS_ASSERT_EQUALS(rx, rot.x); TS_ASSERT_EQUALS(rz, rot.z); }, }); AddMock(newEnt, IID_Ownership, { "SetOwner": owner => { TS_ASSERT_EQUALS(owner, player); }, }); AddMock(newEnt, IID_Position, { "JumpTo": (x, y) => { TS_ASSERT_EQUALS(x, pos.x); TS_ASSERT_EQUALS(y, pos.y); }, "SetYRotation": r => { TS_ASSERT_EQUALS(r, rot.y); }, "SetXZRotation": (rx, rz) => { TS_ASSERT_EQUALS(rx, rot.x); TS_ASSERT_EQUALS(rz, rot.z); }, }); for (let mock of mocks) AddMock(...mock); // INITIALISE Engine.AddEntity = function(template) { TS_ASSERT_EQUALS(template, "construction|" + finalTemplate); return previewEnt; }; - let cmpFoundation = ConstructComponent(foundationEnt, "Foundation", {}); + cmpFoundation = ConstructComponent(foundationEnt, "Foundation", {}); cmpFoundation.InitialiseConstruction(player, finalTemplate); TS_ASSERT_EQUALS(cmpFoundation.owner, player); TS_ASSERT_EQUALS(cmpFoundation.finalTemplateName, finalTemplate); TS_ASSERT_EQUALS(cmpFoundation.maxProgress, 0); TS_ASSERT_EQUALS(cmpFoundation.initialised, true); // BUILDER COUNT, BUILD RATE, TIME REMAINING AddMock(10, IID_Builder, { "GetRate": () => 1.0 }); AddMock(11, IID_Builder, { "GetRate": () => 1.0 }); let twoBuilderMultiplier = Math.pow(2, cmpFoundation.buildTimePenalty) / 2; let threeBuilderMultiplier = Math.pow(3, cmpFoundation.buildTimePenalty) / 3; TS_ASSERT_EQUALS(cmpFoundation.CalculateBuildMultiplier(1), 1); TS_ASSERT_EQUALS(cmpFoundation.CalculateBuildMultiplier(2), twoBuilderMultiplier); TS_ASSERT_EQUALS(cmpFoundation.CalculateBuildMultiplier(3), threeBuilderMultiplier); TS_ASSERT_EQUALS(cmpFoundation.GetBuildRate(), 2); TS_ASSERT_EQUALS(cmpFoundation.GetNumBuilders(), 0); TS_ASSERT_EQUALS(cmpFoundation.totalBuilderRate, 0); cmpFoundation.AddBuilder(10); TS_ASSERT_EQUALS(cmpFoundation.GetNumBuilders(), 1); TS_ASSERT_EQUALS(cmpFoundation.buildMultiplier, 1); TS_ASSERT_EQUALS(cmpFoundation.totalBuilderRate, 1); // Foundation starts with 1 hp, so there's 50 * 99/100 = 49.5 seconds left. TS_ASSERT_UNEVAL_EQUALS(cmpFoundation.GetBuildTime(), { 'timeRemaining': 49.5, 'timeRemainingNew': 49.5 / (2 * twoBuilderMultiplier) }); cmpFoundation.AddBuilder(11); TS_ASSERT_EQUALS(cmpFoundation.GetNumBuilders(), 2); TS_ASSERT_EQUALS(cmpFoundation.buildMultiplier, twoBuilderMultiplier); TS_ASSERT_EQUALS(cmpFoundation.totalBuilderRate, 2); TS_ASSERT_UNEVAL_EQUALS(cmpFoundation.GetBuildTime(), { 'timeRemaining': 49.5 / (2 * twoBuilderMultiplier), 'timeRemainingNew': 49.5 / (3 * threeBuilderMultiplier) }); cmpFoundation.AddBuilder(11); TS_ASSERT_EQUALS(cmpFoundation.GetNumBuilders(), 2); TS_ASSERT_EQUALS(cmpFoundation.buildMultiplier, twoBuilderMultiplier); cmpFoundation.RemoveBuilder(11); TS_ASSERT_EQUALS(cmpFoundation.GetNumBuilders(), 1); TS_ASSERT_EQUALS(cmpFoundation.buildMultiplier, 1); cmpFoundation.RemoveBuilder(11); TS_ASSERT_EQUALS(cmpFoundation.GetNumBuilders(), 1); TS_ASSERT_EQUALS(cmpFoundation.buildMultiplier, 1); TS_ASSERT_EQUALS(cmpFoundation.totalBuilderRate, 1); // COMMIT FOUNDATION TS_ASSERT_EQUALS(cmpFoundation.committed, false); let work = 5; cmpFoundation.Build(10, work); TS_ASSERT_EQUALS(cmpFoundation.committed, true); TS_ASSERT_EQUALS(foundationHP, 1 + work * cmpFoundation.GetBuildRate() * cmpFoundation.buildMultiplier); TS_ASSERT_EQUALS(cmpFoundation.maxProgress, foundationHP / maxHP); TS_ASSERT_EQUALS(cmpFoundation.totalBuilderRate, 5); // FINISH CONSTRUCTION Engine.AddEntity = function(template) { TS_ASSERT_EQUALS(template, finalTemplate); return newEnt; }; cmpFoundation.Build(10, 1000); TS_ASSERT_EQUALS(cmpFoundation.maxProgress, 1); TS_ASSERT_EQUALS(foundationHP, maxHP); } testFoundation(); testFoundation([foundationEnt, IID_Visual, { "SetVariable": (key, num) => { TS_ASSERT_EQUALS(key, "numbuilders"); TS_ASSERT(num == 1 || num == 2); }, "SelectAnimation": (name, once, speed) => name, "HasConstructionPreview": () => true, }]); testFoundation([newEnt, IID_TerritoryDecay, { "HasTerritoryOwnership": () => true, }]); testFoundation([playerEnt, IID_StatisticsTracker, { "IncreaseConstructedBuildingsCounter": ent => { TS_ASSERT_EQUALS(ent, newEnt); }, }]); Index: ps/trunk/build/jenkins/lint-config/eslintrc.json =================================================================== --- ps/trunk/build/jenkins/lint-config/eslintrc.json (revision 22379) +++ ps/trunk/build/jenkins/lint-config/eslintrc.json (revision 22380) @@ -1,95 +1,96 @@ { "parserOptions": { "ecmaVersion": 6 }, "plugins": [ "brace-rules" ], "rules": { "no-cond-assign": 1, "no-constant-condition": ["error", { "checkLoops": false }], "no-dupe-args": 1, "no-dupe-keys": 1, "no-duplicate-case": 1, "no-empty": 1, "no-extra-boolean-cast": 0, "no-extra-parens": 0, "no-extra-semi": 1, "no-func-assign": 1, "no-negated-in-lhs": 1, "no-obj-calls": 1, "no-unreachable": 1, + "no-use-before-define": ["error", "nofunc"], "use-isnan": 1, "valid-jsdoc": 0, "valid-typeof": 1, "block-scoped-var": 0, "consistent-return": 1, "curly": ["warn", "multi"], "default-case": 1, "dot-notation": 1, "no-else-return": 1, "no-invalid-this": 1, "no-lone-blocks": 1, "no-loop-func": 0, "no-multi-spaces": ["warn", { "ignoreEOLComments": true }], "no-new": 1, "no-redeclare": 0, "no-return-assign": 1, "no-self-assign": 1, "no-self-compare": 1, "no-unmodified-loop-condition": 1, "no-unused-expressions": 1, "no-unused-labels": 1, "no-useless-concat": 0, "yoda": 1, "no-delete-var": 1, "no-label-var": 1, "no-shadow-restricted-names": 1, "no-shadow": 1, "no-undef": 0, "no-undef-init": 1, "no-unused-vars": 0, "comma-spacing": 1, "indent": ["warn", "tab", { "outerIIFEBody": 0 }], "key-spacing": 1, "new-cap": 0, "new-parens": 1, "no-mixed-spaces-and-tabs": ["warn", "smart-tabs"], "no-multi-assign": 1, "no-trailing-spaces": 1, "no-unneeded-ternary": 1, "object-curly-spacing": ["warn", "always"], "operator-assignment": 1, "operator-linebreak": ["warn", "after"], "quote-props": 1, "semi": 1, "semi-spacing": 1, "space-before-function-paren": ["warn", "never"], "space-in-parens": 1, "space-unary-ops": 1, "spaced-comment": ["warn", "always"], "no-class-assign": 1, "no-const-assign": 1, "no-dupe-class-members" : 1, "prefer-const": 0, "brace-rules/brace-on-same-line": ["warn", { "FunctionDeclaration": "never", "FunctionExpression": "ignore", "ArrowFunctionExpression": "always", "IfStatement": "never", "TryStatement": "ignore", "CatchClause": "ignore", "DoWhileStatement": "never", "WhileStatement": "never", "ForStatement": "never", "ForInStatement": "never", "ForOfStatement": "never", "SwitchStatement": "never" }, { "allowSingleLine": true }] } }