Line data Source code
1 : function Barter() {} 2 : 3 1 : Barter.prototype.Schema = 4 : "<a:component type='system'/><empty/>"; 5 : 6 : /** 7 : * The "true price" is a base price of 100 units of resource (for the case of some resources being of more worth than others). 8 : * With current bartering system only relative values makes sense so if for example stone is two times more expensive than wood, 9 : * there will 2:1 exchange rate. 10 : * 11 : * Constant part of price percentage difference between true price and buy/sell price. 12 : * Buy price equal to true price plus constant difference. 13 : * Sell price equal to true price minus constant difference. 14 : */ 15 1 : Barter.prototype.CONSTANT_DIFFERENCE = 10; 16 : /** 17 : * Additional difference of prices in percents, added after each deal to specified resource price. 18 : */ 19 1 : Barter.prototype.DIFFERENCE_PER_DEAL = 2; 20 : /** 21 : * Price difference percentage which restored each restore timer tick 22 : */ 23 1 : Barter.prototype.DIFFERENCE_RESTORE = 0.5; 24 : /** 25 : * Interval of timer which slowly restore prices after deals 26 : */ 27 1 : Barter.prototype.RESTORE_TIMER_INTERVAL = 5000; 28 : 29 1 : Barter.prototype.Init = function() 30 : { 31 1 : this.priceDifferences = {}; 32 1 : for (let resource of Resources.GetBarterableCodes()) 33 3 : this.priceDifferences[resource] = 0; 34 1 : this.restoreTimer = undefined; 35 : }; 36 : 37 1 : Barter.prototype.GetPrices = function(cmpPlayer) 38 : { 39 8 : let prices = { "buy": {}, "sell": {} }; 40 8 : let multiplier = cmpPlayer.GetBarterMultiplier(); 41 8 : for (let resource of Resources.GetBarterableCodes()) 42 : { 43 24 : let truePrice = Resources.GetResource(resource).truePrice; 44 24 : prices.buy[resource] = truePrice * (100 + this.CONSTANT_DIFFERENCE + this.priceDifferences[resource]) * multiplier.buy[resource] / 100; 45 24 : prices.sell[resource] = truePrice * (100 - this.CONSTANT_DIFFERENCE + this.priceDifferences[resource]) * multiplier.sell[resource] / 100; 46 : } 47 8 : return prices; 48 : }; 49 : 50 1 : Barter.prototype.ExchangeResources = function(playerID, resourceToSell, resourceToBuy, amount) 51 : { 52 6 : if (amount <= 0) 53 : { 54 0 : warn("ExchangeResources: incorrect amount: " + uneval(amount)); 55 0 : return; 56 : } 57 : 58 6 : let availResources = Resources.GetBarterableCodes(); 59 6 : if (availResources.indexOf(resourceToSell) == -1) 60 : { 61 0 : warn("ExchangeResources: incorrect resource to sell: " + uneval(resourceToSell)); 62 0 : return; 63 : } 64 : 65 6 : if (availResources.indexOf(resourceToBuy) == -1) 66 : { 67 0 : warn("ExchangeResources: incorrect resource to buy: " + uneval(resourceToBuy)); 68 0 : return; 69 : } 70 : 71 6 : if (amount != 100 && amount != 500) 72 2 : return; 73 : 74 4 : let cmpPlayer = QueryPlayerIDInterface(playerID); 75 4 : if (!cmpPlayer || !cmpPlayer.CanBarter()) 76 0 : return; 77 : 78 4 : let prices = this.GetPrices(cmpPlayer); 79 4 : let amountsToSubtract = {}; 80 4 : amountsToSubtract[resourceToSell] = amount; 81 4 : if (cmpPlayer.TrySubtractResources(amountsToSubtract)) 82 : { 83 3 : let amountToAdd = Math.round(prices.sell[resourceToSell] / prices.buy[resourceToBuy] * amount); 84 3 : cmpPlayer.AddResource(resourceToBuy, amountToAdd); 85 : 86 : // Display chat message to observers. 87 3 : let cmpGUIInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface); 88 3 : if (cmpGUIInterface) 89 0 : cmpGUIInterface.PushNotification({ 90 : "type": "barter", 91 : "players": [playerID], 92 : "amountGiven": amount, 93 : "amountGained": amountToAdd, 94 : "resourceGiven": resourceToSell, 95 : "resourceGained": resourceToBuy 96 : }); 97 : 98 3 : let cmpStatisticsTracker = QueryPlayerIDInterface(playerID, IID_StatisticsTracker); 99 3 : if (cmpStatisticsTracker) 100 : { 101 0 : cmpStatisticsTracker.IncreaseResourcesSoldCounter(resourceToSell, amount); 102 0 : cmpStatisticsTracker.IncreaseResourcesBoughtCounter(resourceToBuy, amountToAdd); 103 : } 104 : 105 3 : let difference = this.DIFFERENCE_PER_DEAL * amount / 100; 106 : // Increase price difference for both exchange resources. 107 : // Overall price difference (dynamic +/- constant) can't exceed +-99%. 108 3 : this.priceDifferences[resourceToSell] -= difference; 109 3 : this.priceDifferences[resourceToSell] = Math.min(99 - this.CONSTANT_DIFFERENCE, Math.max(this.CONSTANT_DIFFERENCE - 99, this.priceDifferences[resourceToSell])); 110 3 : this.priceDifferences[resourceToBuy] += difference; 111 3 : this.priceDifferences[resourceToBuy] = Math.min(99 - this.CONSTANT_DIFFERENCE, Math.max(this.CONSTANT_DIFFERENCE - 99, this.priceDifferences[resourceToBuy])); 112 : } 113 : 114 4 : if (this.restoreTimer === undefined) 115 2 : this.restoreTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer).SetInterval(this.entity, IID_Barter, "ProgressTimeout", this.RESTORE_TIMER_INTERVAL, this.RESTORE_TIMER_INTERVAL, {}); 116 : }; 117 : 118 1 : Barter.prototype.ProgressTimeout = function(data) 119 : { 120 2 : let needRestore = false; 121 2 : for (let resource of Resources.GetBarterableCodes()) 122 : { 123 : // Calculate value to restore, it should be limited to [-DIFFERENCE_RESTORE; DIFFERENCE_RESTORE] interval 124 6 : let differenceRestore = Math.min(this.DIFFERENCE_RESTORE, Math.max(-this.DIFFERENCE_RESTORE, this.priceDifferences[resource])); 125 6 : differenceRestore = -differenceRestore; 126 6 : this.priceDifferences[resource] += differenceRestore; 127 : // If price difference still exists then set flag to run timer again 128 6 : if (this.priceDifferences[resource] != 0) 129 1 : needRestore = true; 130 : } 131 : 132 2 : if (!needRestore) 133 : { 134 1 : let cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer); 135 1 : cmpTimer.CancelTimer(this.restoreTimer); 136 1 : this.restoreTimer = undefined; 137 : } 138 : }; 139 : 140 1 : Engine.RegisterSystemComponentType(IID_Barter, "Barter", Barter);