Ticket #3277: trading_v5.patch
File trading_v5.patch, 16.1 KB (added by , 8 years ago) |
---|
-
binaries/data/mods/public/simulation/components/GuiInterface.js
1684 1684 let firstMarket = cmpEntityTrader.GetFirstMarket(); 1685 1685 let secondMarket = cmpEntityTrader.GetSecondMarket(); 1686 1686 let result = null; 1687 if (data.target === firstMarket) 1687 if (!firstMarket) 1688 result = { "type": "set first" }; 1689 else if (!secondMarket) 1688 1690 { 1689 1691 result = { 1692 "type": "set second", 1693 "gain": cmpEntityTrader.CalculateGain(firstMarket, data.target), 1694 }; 1695 } 1696 else if (data.target === firstMarket) 1697 { 1698 result = { 1690 1699 "type": "is first", 1691 1700 "hasBothMarkets": cmpEntityTrader.HasBothMarkets() 1692 1701 }; … … 1700 1709 "gain": cmpEntityTrader.GetGoods().amount, 1701 1710 }; 1702 1711 } 1703 else if (!firstMarket)1704 {1705 result = { "type": "set first" };1706 }1707 else if (!secondMarket)1708 {1709 result = {1710 "type": "set second",1711 "gain": cmpEntityTrader.CalculateGain(firstMarket, data.target),1712 };1713 }1714 1712 else 1715 1713 { 1716 1714 // Else both markets are not null and target is different from them -
binaries/data/mods/public/simulation/components/Market.js
1 /** 2 @file Market.js 3 Component used for the management of market and trade units in the field 4 */ 5 function Market() {} 6 7 Market.prototype.Schema = "<a:component type='system'/><empty/>"; 8 9 Market.prototype.Init = function() 10 { 11 this.tradeEntities = []; // List of trade entities from which this market works as a target 12 }; 13 14 /** 15 Subscribes a new trader to this market. 16 @param {Object} trader - The trader object expected being subscribed inside the market. 17 */ 18 19 Market.prototype.SubscribeTrader = function(trader) 20 { 21 if (this.tradeEntities.indexOf(trader) === -1) 22 this.tradeEntities.push(trader); 23 }; 24 25 Market.prototype.OnDestroy = function() 26 { 27 this.NotifySubscribedTraders(); 28 }; 29 30 Market.prototype.OnOwnershipChanged = function(msg) 31 { 32 if (msg.to != -1 && msg.from != -1) 33 this.NotifySubscribedTraders(); 34 }; 35 36 Market.prototype.OnDiplomacyChanged = function(msg) 37 { 38 this.NotifySubscribedTraders(); 39 } 40 41 /** 42 Notifies traders subscribed to this market to change their trading behavior 43 */ 44 Market.prototype.NotifySubscribedTraders = function() { 45 46 let cmpUnitAI = undefined; 47 // When the market is invalidated for an entity, this should be unsubscribed 48 // from the market. But this creates a change in the size of the array, 49 // generating an error that when the iterator arrives to half of the sub array 50 // that would be eliminated, the upper half will be the new lower half. This 51 // generate a problem because then the array returns null after the iterator 52 // has moved passed the half for the next half of elements. To eliminate 53 // this problem we create a temporal array where the index of the trade 54 // elements that will be unsubscribed are temporarily saved and 55 // eliminated in the future 56 let entitiesToEliminate = []; 57 for(let trader of this.tradeEntities) 58 { 59 if (!trader) 60 continue; 61 62 cmpUnitAI = Engine.QueryInterface(trader, IID_UnitAI); 63 if (cmpUnitAI && !cmpUnitAI.CanTrade(this.entity)) 64 { 65 // Unsubscribe the trader from the market 66 entitiesToEliminate.push(this.tradeEntities.indexOf(trader)); 67 cmpUnitAI.InvalidateTradingMarket(this.entity); 68 } 69 } 70 71 // Unsubscribe the entities from this market 72 for(let index of entitiesToEliminate) 73 { 74 this.tradeEntities.splice(index, 1); 75 } 76 } 77 78 Engine.RegisterComponentType(IID_Market, "Market", Market); -
binaries/data/mods/public/simulation/components/Trader.js
1 // See helpers/TraderGain.js for the CalculateTaderGain() function which works out how many 2 // resources a trader gets 1 // See helpers/TraderGain.js for the CalculateTaderGain() function which works out how many 2 // resources a trader gets 3 3 4 4 // Additional gain for ships for each garrisoned trader, in percents 5 5 const GARRISONED_TRADER_ADDITION = 20; … … 61 61 gain.market2Gain = Math.round(garrisonMultiplier * gain.market2Gain); 62 62 } 63 63 } 64 64 65 65 return gain; 66 66 }; 67 67 … … 166 166 var cmpTraderPlayer = QueryOwnerInterface(this.entity, IID_Player); 167 167 var traderPlayerId = cmpTraderPlayer.GetPlayerID(); 168 168 var cmpTargetPlayer = QueryOwnerInterface(target, IID_Player); 169 if (!cmpTargetPlayer) 170 return false; 169 171 var targetPlayerId = cmpTargetPlayer.GetPlayerID(); 170 172 var ownershipSuitableForTrading = cmpTraderPlayer.IsAlly(targetPlayerId) || cmpTraderPlayer.IsNeutral(targetPlayerId); 171 173 if (!ownershipSuitableForTrading) … … 270 272 this.goods.amount = this.CalculateGain(this.markets[0], this.markets[1]); 271 273 }; 272 274 275 Trader.prototype.InvalidateFirstMarket = function() 276 { 277 this.markets[0] = INVALID_ENTITY; 278 } 279 280 Trader.prototype.InvalidateSecondMarket = function() 281 { 282 this.markets[1] = INVALID_ENTITY; 283 } 284 273 285 Engine.RegisterComponentType(IID_Trader, "Trader", Trader); -
binaries/data/mods/public/simulation/components/UnitAI.js
58 58 // There some targeting options: 59 59 // targetVisibleEnemies: anything in vision range is a viable target 60 60 // targetAttackersAlways: anything that hurts us is a viable target, 61 // 61 // possibly overriding user orders! 62 62 // targetAttackersPassive: anything that hurts us is a viable target, 63 // 63 // if we're on a passive/unforced order (e.g. gathering/building) 64 64 // There are some response options, triggered when targets are detected: 65 65 // respondFlee: run away 66 66 // respondChase: start chasing after the enemy 67 67 // respondChaseBeyondVision: start chasing, and don't stop even if it's out 68 // 68 // of this unit's vision range (though still visible to the player) 69 69 // respondStandGround: attack enemy but don't move at all 70 70 // respondHoldGround: attack enemy but don't move far from current position 71 71 // TODO: maybe add targetAggressiveEnemies (don't worry about lone scouts, … … 349 349 return; 350 350 } 351 351 352 // Check if we need to move 352 // Check if we need to move TODO implement a better way to know if we are on the shoreline 353 353 var needToMove = true; 354 354 var cmpPosition = Engine.QueryInterface(this.entity, IID_Position); 355 355 if (this.lastShorelinePosition && cmpPosition && (this.lastShorelinePosition.x == cmpPosition.GetPosition().x) 356 356 && (this.lastShorelinePosition.z == cmpPosition.GetPosition().z)) 357 357 { 358 358 // we were already on the shoreline, and have not moved since 359 359 if (DistanceBetweenEntities(this.entity, this.order.data.target) < 50) … … 1080 1080 var cmpGarrisonHolder = Engine.QueryInterface(this.order.data.target, IID_GarrisonHolder); 1081 1081 if (cmpGarrisonHolder && cmpGarrisonHolder.CanPickup(this.entity)) 1082 1082 { 1083 this.pickup = this.order.data.target; 1083 this.pickup = this.order.data.target; // temporary, deleted in "leave" 1084 1084 Engine.PostMessage(this.pickup, MT_PickupRequested, { "entity": this.entity }); 1085 1085 } 1086 1086 }, … … 1387 1387 var cmpIdentity = Engine.QueryInterface(this.entity, IID_Identity); 1388 1388 var cmpHealth = Engine.QueryInterface(this.isGuardOf, IID_Health); 1389 1389 if (cmpIdentity && cmpIdentity.HasClass("Support") && 1390 1390 cmpHealth && cmpHealth.GetHitpoints() < cmpHealth.GetMaxHitpoints()) 1391 1391 { 1392 1392 if (this.CanHeal(this.isGuardOf)) 1393 1393 this.PushOrderFront("Heal", { "target": this.isGuardOf, "force": false }); … … 1795 1795 } 1796 1796 // Check the target is still alive and attackable 1797 1797 if (this.TargetIsAlive(target) && 1798 1799 1798 this.CanAttack(target, this.order.data.forceResponse || null) && 1799 !this.CheckTargetAttackRange(target, this.order.data.attackType)) 1800 1800 { 1801 1801 // Can't reach it - try to chase after it 1802 1802 if (this.ShouldChaseTargetedEntity(target, this.order.data.force)) … … 2037 2037 var cmpSupply = Engine.QueryInterface(this.gatheringTarget, IID_ResourceSupply); 2038 2038 var cmpMirage = Engine.QueryInterface(this.gatheringTarget, IID_Mirage); 2039 2039 if ((!cmpMirage || !cmpMirage.Mirages(IID_ResourceSupply)) && 2040 2040 (!cmpSupply || !cmpSupply.AddGatherer(cmpOwnership.GetOwner(), this.entity))) 2041 2041 { 2042 2042 // Save the current order's data in case we need it later 2043 2043 var oldType = this.order.data.type; … … 2614 2614 this.PerformTradeAndMoveToNextMarket(this.order.data.target); 2615 2615 }, 2616 2616 }, 2617 2618 "INVALIDATINGMARKET": { 2619 "enter": function() { 2620 this.StartTimer(50,1000); 2621 }, 2622 2623 "Timer": function(msg) { 2624 if(!this.CheckTargetVisible(this.order.data.target)) 2625 this.InvalidateTradingMarket(this.order.data.target); 2626 }, 2627 2628 "leave": function() { 2629 this.StopTimer(); 2630 this.StopTrading(); 2631 }, 2632 2633 "MoveCompleted": function() { 2634 this.StopTimer(); 2635 this.SetNextState("IDLE"); 2636 } 2637 2638 }, 2639 2617 2640 }, 2618 2641 2619 2642 "REPAIR": { … … 2724 2747 let dropsiteTypes = cmpResourceDropsite.GetTypes(); 2725 2748 cmpResourceGatherer.CommitResources(dropsiteTypes); 2726 2749 this.SetGathererAnimationOverride(); 2727 } 2750 } 2728 2751 2729 2752 // We finished building it. 2730 2753 // Switch to the next order (if any) … … 2799 2822 var cmpGarrisonHolder = Engine.QueryInterface(this.order.data.target, IID_GarrisonHolder); 2800 2823 if (cmpGarrisonHolder && cmpGarrisonHolder.CanPickup(this.entity)) 2801 2824 { 2802 this.pickup = this.order.data.target; 2825 this.pickup = this.order.data.target; // temporary, deleted in "leave" 2803 2826 Engine.PostMessage(this.pickup, MT_PickupRequested, { "entity": this.entity }); 2804 2827 } 2805 2828 }, … … 3054 3077 "ANIMAL": { 3055 3078 "Attacked": function(msg) { 3056 3079 if (this.template.NaturalBehaviour == "skittish" || 3057 3080 this.template.NaturalBehaviour == "passive") 3058 3081 { 3059 3082 this.Flee(msg.data.attacker, false); 3060 3083 } … … 3436 3459 var cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager); 3437 3460 if (this.losRangeQuery) 3438 3461 this.SetupRangeQuery(cmpRangeManager.IsActiveQueryEnabled(this.losRangeQuery)); 3439 3462 3440 3463 if (this.IsHealer() && this.losHealRangeQuery) 3441 3464 this.SetupHealRangeQuery(cmpRangeManager.IsActiveQueryEnabled(this.losHealRangeQuery)); 3442 3465 }; … … 5156 5179 return; 5157 5180 } 5158 5181 5159 varmarketsChanged = this.SetTargetMarket(target, source);5182 let marketsChanged = this.SetTargetMarket(target, source); 5160 5183 if (!marketsChanged) 5161 5184 return; 5162 5185 5163 var cmpTrader = Engine.QueryInterface(this.entity, IID_Trader); 5186 let cmpTrader = Engine.QueryInterface(this.entity, IID_Trader); 5187 let cmpMarket = Engine.QueryInterface(target, IID_Market); 5188 if(!cmpTrader || !cmpMarket) 5189 return; 5190 5191 cmpMarket.SubscribeTrader(this.entity); 5192 5164 5193 if (cmpTrader.HasBothMarkets()) 5165 5194 { 5166 5195 let data = { … … 5179 5208 if (this.IsFormationController()) 5180 5209 { 5181 5210 this.CallMemberFunction("AddOrder", ["Trade", data, queued]); 5182 varcmpFormation = Engine.QueryInterface(this.entity, IID_Formation);5211 let cmpFormation = Engine.QueryInterface(this.entity, IID_Formation); 5183 5212 if (cmpFormation) 5184 5213 cmpFormation.Disband(); 5185 5214 } … … 5227 5256 return ok; 5228 5257 }; 5229 5258 5259 /** 5260 * Makes a routing trade invalid sending the trader unit to the next 5261 * possible market. 5262 */ 5263 UnitAI.prototype.InvalidateTradingMarket = function(market) 5264 { 5265 // Find the entity inside the one of the markets in the trader 5266 // 5267 // If the market is found as the first market then send the trader to the 5268 // second market. 5269 // 5270 // If the market is found in the second market then send the trader to the 5271 // first market 5272 // 5273 // If the source and target have been captured then stop 5274 // trading 5275 let cmpTrader = Engine.QueryInterface(this.entity, IID_Trader); 5276 5277 // Check if the market is visible, otherwise add it to the Queue 5278 if(cmpTrader && !this.CheckTargetVisible(market)) 5279 { 5280 if (!cmpTrader.GetFirstMarket() && !cmpTrader.GetSecondMarket()) 5281 this.StopTrading(); 5282 else if(cmpTrader.GetFirstMarket() === market) 5283 { 5284 cmpTrader.InvalidateFirstMarket(); 5285 if(this.order.data.target === market) 5286 this.MoveToMarket(cmpTrader.GetSecondMarket()); 5287 } 5288 else if(cmpTrader.GetSecondMarket() === market) 5289 { 5290 cmpTrader.InvalidateSecondMarket(); 5291 if(this.order.data.target === market) 5292 this.MoveToMarket(cmpTrader.GetFirstMarket()); 5293 } 5294 } 5295 else if(this.GetCurrentState() !== "INDIVIDUAL.TRADE.INVALIDATINGMARKET") 5296 { 5297 this.order.data.target = market; 5298 this.SetNextState("INDIVIDUAL.TRADE.INVALIDATINGMARKET"); 5299 } 5300 }; 5301 5230 5302 UnitAI.prototype.PerformTradeAndMoveToNextMarket = function(currentMarket) 5231 5303 { 5232 5304 if (!this.CanTrade(currentMarket)) … … 5243 5315 } 5244 5316 5245 5317 let cmpTrader = Engine.QueryInterface(this.entity, IID_Trader); 5318 if(!cmpTrader) 5319 { 5320 this.StopTrading(); 5321 return; 5322 } 5323 5246 5324 cmpTrader.PerformTrade(currentMarket); 5247 5325 let amount = cmpTrader.GetGoods().amount; 5248 5326 if (!amount || !amount.traderGain) … … 5271 5349 UnitAI.prototype.StopTrading = function() 5272 5350 { 5273 5351 this.StopMoving(); 5274 this.FinishOrder(); 5275 var cmpTrader = Engine.QueryInterface(this.entity, IID_Trader); 5352 let cmpTrader = Engine.QueryInterface(this.entity, IID_Trader); 5276 5353 cmpTrader.StopTrading(); 5277 5354 }; 5278 5355 … … 5775 5852 if (cmpOwnership && IsOwnedByPlayer(cmpOwnership.GetOwner(), target)) 5776 5853 return true; 5777 5854 return cmpPlayer && cmpPlayer.HasSharedDropsites() && cmpResourceDropsite.IsShared() && 5778 5855 cmpOwnership && IsOwnedByMutualAllyOfPlayer(cmpOwnership.GetOwner(), target); 5779 5856 }; 5780 5857 5781 5858 UnitAI.prototype.CanTrade = function(target) -
binaries/data/mods/public/simulation/components/interfaces/Market.js
1 Engine.RegisterInterface("Market"); -
binaries/data/mods/public/simulation/templates/template_structure_economic_market.xml
64 64 <Vision> 65 65 <Range>32</Range> 66 66 </Vision> 67 <Market/> 67 68 <VisualActor> 68 69 <FoundationActor>structures/fndn_5x5.xml</FoundationActor> 69 70 </VisualActor> -
binaries/data/mods/public/simulation/templates/template_structure_military_dock.xml
75 75 <Vision> 76 76 <Range>40</Range> 77 77 </Vision> 78 <Market/> 78 79 <VisualActor> 79 80 <FoundationActor>structures/fndn_4x4_dock.xml</FoundationActor> 80 81 </VisualActor>