Ticket #1207: 2+-way-trade.patch
File 2+-way-trade.patch, 14.3 KB (added by , 11 years ago) |
---|
-
binaries/data/mods/public/gui/session/input.js
1368 1368 return true; 1369 1369 1370 1370 case "setup-trade-route": 1371 Engine.PostNetworkCommand({"type": "setup-trade-route", "entities": selection, "target": action.target });1371 Engine.PostNetworkCommand({"type": "setup-trade-route", "entities": selection, "target": action.target, "queued": queued}); 1372 1372 Engine.GuiInterfaceCall("PlaySound", { "name": "order_trade", "entity": selection[0] }); 1373 1373 return true; 1374 1374 -
binaries/data/mods/public/simulation/components/GuiInterface.js
1608 1608 1609 1609 GuiInterface.prototype.GetTradingRouteGain = function(player, data) 1610 1610 { 1611 // TODO 1611 1612 if (!data.firstMarket || !data.secondMarket) 1612 1613 return null; 1613 1614 … … 1616 1617 1617 1618 GuiInterface.prototype.GetTradingDetails = function(player, data) 1618 1619 { 1620 // TODO 1621 1619 1622 var cmpEntityTrader = Engine.QueryInterface(data.trader, IID_Trader); 1620 1623 if (!cmpEntityTrader || !cmpEntityTrader.CanTrade(data.target)) 1621 1624 return null; 1622 var firstMarket = cmpEntityTrader.GetFirstMarket();1625 /*var firstMarket = cmpEntityTrader.GetFirstMarket(); 1623 1626 var secondMarket = cmpEntityTrader.GetSecondMarket(); 1624 var result = null;1627 */var result = null;/* 1625 1628 if (data.target === firstMarket) 1626 1629 { 1627 1630 result = { … … 1652 1655 "goods": cmpEntityTrader.GetPreferredGoods() 1653 1656 }; 1654 1657 } 1655 else 1658 else*/ 1656 1659 { 1657 1660 // Else both markets are not null and target is different from them 1658 1661 result = {"type": "set first"}; -
binaries/data/mods/public/simulation/components/Trader.js
24 24 25 25 Trader.prototype.Init = function() 26 26 { 27 this. firstMarket = INVALID_ENTITY;28 this.secondMarket = INVALID_ENTITY; 27 this.markets = []; 28 29 29 // Gain from one pass between markets 30 this.gain = null; 30 this.gain = []; // from the current to the next 31 32 this.pos = 0; // Current market 33 31 34 // Selected resource for trading 32 35 this.preferredGoods = "metal"; 33 36 // Currently carried goods 34 37 this.goods = { "type": null, "amount": 0 }; 35 } 38 }; 36 39 37 40 Trader.prototype.CalculateGain = function(firstMarket, secondMarket, template) 38 41 { … … 57 60 } 58 61 59 62 return garrisonMultiplier * CalculateTraderGain(firstMarket, secondMarket, this.template); 60 } 63 }; 61 64 62 65 Trader.prototype.GetGain = function() 63 66 { 64 return this.gain ;65 } 67 return this.gain[pos]; 68 }; 66 69 67 // Set target as targetmarket.68 // Return true if at least one of markets was changed.69 Trader.prototype. SetTargetMarket = function(target, source)70 // Add a market. 71 // Returns true if adding succeeded 72 Trader.prototype.AddMarket = function(target) 70 73 { 71 74 // Check that target is a market 72 var cmp TargetIdentity = Engine.QueryInterface(target, IID_Identity);73 if (!cmp TargetIdentity)75 var cmpIdentity = Engine.QueryInterface(target, IID_Identity); 76 if (!cmpIdentity) 74 77 return false; 75 if (!cmp TargetIdentity.HasClass("Market") && !cmpTargetIdentity.HasClass("NavalMarket"))78 if (!cmpIdentity.HasClass("Market") && !cmpIdentity.HasClass("NavalMarket")) 76 79 return false; 77 var marketsChanged = true;78 if (source)79 {80 // Establish a trade route with both markets in one go.81 cmpTargetIdentity = Engine.QueryInterface(source, IID_Identity);82 if (!cmpTargetIdentity)83 return false;84 if (!cmpTargetIdentity.HasClass("Market") && !cmpTargetIdentity.HasClass("NavalMarket"))85 return false;86 87 this.firstMarket = source;88 this.secondMarket = INVALID_ENTITY;89 }90 80 91 if (this.secondMarket) 92 { 93 // If we already have both markets - drop them 94 // and use the target as first market 95 this.firstMarket = target; 96 this.secondMarket = INVALID_ENTITY; 97 } 98 else if (this.firstMarket) 81 // Insert the market at the end of our current tour (right before 82 this.markets.splice(this.pos-1, 0, target); 83 84 if (this.markets.length <=1) 99 85 { 100 // If we have only one market and target is different from it, 101 // set the target as second one 102 if (target == this.firstMarket) 103 marketsChanged = false; 104 else 105 { 106 this.secondMarket = target; 107 this.gain = this.CalculateGain(this.firstMarket, this.secondMarket); 108 } 86 this.gain.push(0); 109 87 } 110 else 88 else if (this.markets.length <= 2) 111 89 { 112 // Else we don't have target markets at all, 113 // set the target as first market 114 this.firstMarket = target; 90 this.gain[0] = this.CalculateGain(this.markets[0], this.markets[1]); 91 this.gain.push(this.gain[0]); 115 92 } 116 if (marketsChanged)93 else // this.markets.length > 2 117 94 { 118 // Drop carried goods 119 this.goods.amount = 0; 95 // We are approaching a[this.pos] 96 // So we need to update a[pos-2] and insert a[pos-1] 97 98 this.gain.splice(this.pos-1, 0, 0); 99 100 var p = this.pos; 101 var p1 = p - 1; 102 var p2 = p - 2; 103 104 if (p2 < 0) 105 p2 += this.markets.length; 106 if (p1 < 0) 107 p1 += this.markets.length; 108 109 this.gain[p2] = this.CalculateGain(this.markets[p2], this.markets[p1]); 110 this.gain[p1] = this.CalculateGain(this.markets[p1], this.markets[p]); 120 111 } 121 return marketsChanged;122 }123 112 124 Trader.prototype.GetFirstMarket = function() 125 { 126 return this.firstMarket; 127 } 113 return true; 114 }; 128 115 129 Trader.prototype. GetSecondMarket = function()116 Trader.prototype.AdvanceMarket = function() 130 117 { 131 return this.secondMarket;118 this.pos = (this.pos + 1) % this.markets.length; 132 119 } 133 120 134 Trader.prototype.Has BothMarkets = function()121 Trader.prototype.HasEnoughMarkets = function() 135 122 { 136 return this.firstMarket && this.secondMarket;137 } 123 return (this.markets.length >= 2); 124 }; 138 125 139 126 Trader.prototype.GetPreferredGoods = function() 140 127 { 141 128 return this.preferredGoods; 142 } 129 }; 143 130 144 131 Trader.prototype.SetPreferredGoods = function(preferredGoods) 145 132 { … … 147 134 if (RESOURCES.indexOf(preferredGoods) == -1) 148 135 return; 149 136 this.preferredGoods = preferredGoods; 150 } 137 }; 151 138 152 139 Trader.prototype.CanTrade = function(target) 153 140 { … … 173 160 if (!ownershipSuitableForTrading) 174 161 return false; 175 162 return true; 176 } 163 }; 177 164 178 165 Trader.prototype.PerformTrade = function() 179 166 { … … 187 174 cmpStatisticsTracker.IncreaseTradeIncomeCounter(this.goods.amount); 188 175 } 189 176 this.goods.type = this.preferredGoods; 190 this.goods.amount = this.gain ;191 } 177 this.goods.amount = this.gain[this.pos]; 178 }; 192 179 193 180 Trader.prototype.GetGoods = function() 194 181 { 195 182 return this.goods; 196 } 183 }; 197 184 198 185 Trader.prototype.StopTrading = function() 199 186 { 200 187 // Drop carried goods 201 188 this.goods.amount = 0; 202 189 // Reset markets 203 this.firstMarket = INVALID_ENTITY; 204 this.secondMarket = INVALID_ENTITY; 205 } 190 this.markets = []; 191 this.gain = []; 192 this.pos = 0; 193 }; 206 194 207 195 // Get range in which deals with market are available, 208 196 // i.e. trader should be in no more than MaxDistance from market … … 210 198 Trader.prototype.GetRange = function() 211 199 { 212 200 return { "min": 0, "max": +this.template.MaxDistance }; 213 } 201 }; 214 202 215 203 Engine.RegisterComponentType(IID_Trader, "Trader", Trader); 216 -
binaries/data/mods/public/simulation/components/UnitAI.js
230 230 231 231 // Stop moving immediately. 232 232 this.StopMoving(); 233 this.StopTrading(); 233 234 this.FinishOrder(); 234 235 235 236 // No orders left, we're an individual now … … 562 563 }, 563 564 564 565 "Order.Trade": function(msg) { 565 if (this.MoveToMarket(this.order.data. firstMarket))566 if (this.MoveToMarket(this.order.data.target)) 566 567 { 568 this.cycle = true; 567 569 // We've started walking to the first market 568 this.SetNextState("INDIVIDUAL.TRADE.APPROACHING FIRSTMARKET");570 this.SetNextState("INDIVIDUAL.TRADE.APPROACHINGMARKET"); 569 571 } 570 572 }, 571 573 … … 2028 2030 // TODO: Inform player 2029 2031 }, 2030 2032 2031 "APPROACHING FIRSTMARKET": {2033 "APPROACHINGMARKET": { 2032 2034 "enter": function () { 2033 2035 this.SelectAnimation("move"); 2034 2036 }, 2035 2037 2036 2038 "MoveCompleted": function() { 2037 this.PerformTradeAndMoveToNextMarket(this.order.data.firstMarket, this.order.data.secondMarket, "INDIVIDUAL.TRADE.APPROACHINGSECONDMARKET"); 2038 }, 2039 }, 2039 var cmpTrader = Engine.QueryInterface(this.entity, IID_Trader); 2040 if (!cmpTrader || !this.CanTrade(this.order.data.target)) 2041 { 2042 // The target market probably stopped existing 2043 this.StopTrading(); 2044 this.FinishOrder(); 2045 return; 2046 } 2040 2047 2041 "APPROACHINGSECONDMARKET": { 2042 "enter": function () { 2043 this.SelectAnimation("move"); 2044 }, 2048 if (!this.CheckTargetRange(this.order.data.target, IID_Trader)) 2049 { 2050 this.MoveToMarket(this.order.data.target); 2051 return; 2052 } 2045 2053 2046 "MoveCompleted": function() { 2047 this.order.data.firstPass = false; 2048 this.PerformTradeAndMoveToNextMarket(this.order.data.secondMarket, this.order.data.firstMarket, "INDIVIDUAL.TRADE.APPROACHINGFIRSTMARKET"); 2054 if (!cmpTrader.HasEnoughMarkets()) 2055 warn("we should wait and not move on"); 2056 // TODO: Check if we have more than one market, else wait 2057 2058 this.PerformTrade(); 2059 // Get next market 2060 cmpTrader.AdvanceMarket(); 2061 this.FinishOrder(); 2049 2062 }, 2050 2063 }, 2051 2064 }, … … 2443 2456 this.isIdle = false; 2444 2457 this.lastFormationName = ""; 2445 2458 this.finishedOrder = false; // used to find if all formation members finished the order 2459 this.cycle = false; 2446 2460 2447 2461 // For preventing increased action rate due to Stop orders or target death. 2448 2462 this.lastAttacked = undefined; … … 2743 2757 error("FinishOrder called for entity " + this.entity + " (" + template + ") when order queue is empty\n" + stack); 2744 2758 } 2745 2759 2746 this.orderQueue.shift();2760 var oldOrder = this.orderQueue.shift(); 2747 2761 this.order = this.orderQueue[0]; 2748 2762 2763 // TODO: Ensure Stop orders work (they should, but double checking doesn't hurt) 2764 if (this.cycle) 2765 this.orderQueue.push(oldOrder); 2766 2749 2767 if (this.orderQueue.length) 2750 2768 { 2751 2769 var ret = UnitFsm.ProcessMessage(this, … … 2768 2786 { 2769 2787 this.SetNextState("IDLE"); 2770 2788 2789 this.StopTrading(); 2790 2771 2791 // Check if there are queued formation orders 2772 2792 if (this.IsFormationMember()) 2773 2793 { … … 3876 3896 * Adds trade order to the queue. Either walk to the first market, or 3877 3897 * start a new route. Not forced, so it can be interrupted by attacks. 3878 3898 */ 3879 UnitAI.prototype.SetupTradeRoute = function(target, source,queued)3899 UnitAI.prototype.SetupTradeRoute = function(target, queued) 3880 3900 { 3881 3901 if (!this.CanTrade(target)) 3882 3902 { … … 3885 3905 } 3886 3906 3887 3907 var cmpTrader = Engine.QueryInterface(this.entity, IID_Trader); 3888 var marketsChanged = cmpTrader.SetTargetMarket(target, source); 3889 if (marketsChanged) 3908 if (cmpTrader.AddMarket(target)) 3890 3909 { 3891 if (cmpTrader.HasBothMarkets()) 3892 this.AddOrder("Trade", { "firstMarket": cmpTrader.GetFirstMarket(), "secondMarket": cmpTrader.GetSecondMarket(), "force": false }, queued); 3910 if (cmpTrader.HasEnoughMarkets()) 3911 { 3912 // We assume (for now) that both markets get set separately 3913 // We'll just assume this always. 3914 3915 // TODO: Handle queued == false properly and not just ignore it 3916 this.AddOrder("Trade", { "target": target, "force": false }, true); // We already have one market, so we need to start cycling 3917 } 3893 3918 else 3894 this. WalkToTarget(cmpTrader.GetFirstMarket(), queued);3919 this.AddOrder("Trade", { "target": target, "force": false }, queued); 3895 3920 } 3896 3921 }; 3897 3922 … … 3908 3933 // Give up. 3909 3934 this.StopMoving(); 3910 3935 this.StopTrading(); 3936 this.FinishOrder(); 3911 3937 return false; 3912 3938 } 3913 3939 }; 3914 3940 3915 UnitAI.prototype.PerformTradeAndMoveToNextMarket = function(currentMarket, nextMarket, nextFsmStateName)3916 {3917 if (!this.CanTrade(currentMarket))3918 {3919 this.StopTrading();3920 return;3921 }3922 3923 if (this.CheckTargetRange(currentMarket, IID_Trader))3924 {3925 this.PerformTrade();3926 if (this.MoveToMarket(nextMarket))3927 {3928 // We've started walking to the next market3929 this.SetNextState(nextFsmStateName);3930 }3931 }3932 else3933 {3934 // If the current market is not reached try again3935 this.MoveToMarket(currentMarket);3936 }3937 };3938 3939 3941 UnitAI.prototype.PerformTrade = function() 3940 3942 { 3941 3943 var cmpTrader = Engine.QueryInterface(this.entity, IID_Trader); … … 3944 3946 3945 3947 UnitAI.prototype.StopTrading = function() 3946 3948 { 3947 this.FinishOrder();3948 3949 var cmpTrader = Engine.QueryInterface(this.entity, IID_Trader); 3949 cmpTrader.StopTrading(); 3950 if (cmpTrader) 3951 { 3952 this.cycle = false; 3953 cmpTrader.StopTrading(); 3954 } 3950 3955 }; 3951 3956 3952 3957 /** -
binaries/data/mods/public/simulation/helpers/Commands.js
441 441 break; 442 442 443 443 case "setup-trade-route": 444 for each (var ent in entities) 445 { 446 var cmpUnitAI = Engine.QueryInterface(ent, IID_UnitAI); 447 if (cmpUnitAI) 448 cmpUnitAI.SetupTradeRoute(cmd.target, cmd.source); 449 } 444 GetFormationUnitAIs(entities, player).forEach(function(cmpUnitAI) { 445 cmpUnitAI.SetupTradeRoute(cmd.target, cmd.queued); 446 }); 450 447 break; 451 448 452 449 case "select-trading-goods": -
binaries/data/mods/public/simulation/helpers/RallyPointCommands.js
5 5 var data = cmpRallyPoint.GetData(); 6 6 var rallyPos = cmpRallyPoint.GetPositions(); 7 7 var ret = []; 8 var trade = 0; 8 9 for(var i = 0; i < rallyPos.length; ++i) 9 10 { 10 11 // Look and see if there is a command in the rally point data, otherwise just walk there. … … 64 65 ret.push( { 65 66 "type": "setup-trade-route", 66 67 "entities": spawnedEnts, 67 "source": data[i].source,68 68 "target": data[i].target, 69 69 "queued": true 70 70 }); 71 trade++; 71 72 break; 72 73 default: 73 74 ret.push( { … … 80 81 break; 81 82 } 82 83 } 84 if (trade == 1) 85 ; // TODO: Figure out if we have a trader, if yes add the current building (if market) in front with a trade order 86 83 87 return ret; 84 88 } 85 89