Make rally points work for trade. Patch from Deiz/F00. Fixes #1173.

This was SVN commit r12191.
This commit is contained in:
quantumstate 2012-07-25 21:38:56 +00:00
parent 006aa8ee21
commit 0dc1d2139e
7 changed files with 109 additions and 42 deletions

View file

@ -210,6 +210,7 @@ function getActionInfo(action, target)
var gaiaOwned = (targetState.player == 0);
var cursor = "";
var tooltip;
// default to walking there
var data = {command: "walk"};
@ -254,8 +255,29 @@ function getActionInfo(action, target)
data.target = target;
cursor = "action-repair";
}
else if (hasClass(entState, "Market") && hasClass(targetState, "Market") && entState.id != targetState.id &&
(!hasClass(entState, "NavalMarket") || hasClass(targetState, "NavalMarket")))
{
// Find a trader (if any) that this building can produce.
var trader;
if (entState.production && entState.production.entities.length)
for (var i = 0; i < entState.production.entities.length; ++i)
if ((trader = GetTemplateData(entState.production.entities[i]).trader))
break;
var traderData = { "firstMarket": entState.id, "secondMarket": targetState.id, "template": trader };
var gain = Engine.GuiInterfaceCall("GetTradingRouteGain", traderData);
if (gain !== null)
{
data.command = "trade";
data.target = traderData.secondMarket;
data.source = traderData.firstMarket;
cursor = "action-setup-trade-route";
tooltip = "Click to establish a default route for new traders. Gain: " + gain + " metal.";
}
}
return {"possible": true, "data": data, "position": targetState.position, "cursor": cursor};
return {"possible": true, "data": data, "position": targetState.position, "cursor": cursor, "tooltip": tooltip};
}
for each (var entityID in selection)
@ -463,7 +485,7 @@ function determineAction(x, y, fromMinimap)
else if (getActionInfo("repair", target).possible)
return {"type": "build", "cursor": "action-repair", "target": target};
else if ((actionInfo = getActionInfo("set-rallypoint", target)).possible)
return {"type": "set-rallypoint", "cursor": actionInfo.cursor, "data": actionInfo.data, "position": actionInfo.position};
return {"type": "set-rallypoint", "cursor": actionInfo.cursor, "data": actionInfo.data, "tooltip": actionInfo.tooltip, "position": actionInfo.position};
else if (getActionInfo("heal", target).possible)
return {"type": "heal", "cursor": "action-heal", "target": target};
else if (getActionInfo("attack", target).possible)

View file

@ -452,6 +452,9 @@ GuiInterface.prototype.GetTemplateData = function(player, name)
if (template.UnitMotion.Run) ret.speed.run = +template.UnitMotion.Run.Speed;
}
if (template.Trader)
ret.trader = template.Trader;
if (template.WallSet)
{
ret.wallSet = {
@ -1474,6 +1477,14 @@ GuiInterface.prototype.FindIdleUnit = function(player, data)
return 0;
};
GuiInterface.prototype.GetTradingRouteGain = function(player, data)
{
if (!data.firstMarket || !data.secondMarket)
return null;
return CalculateTraderGain(data.firstMarket, data.secondMarket, data.template);
}
GuiInterface.prototype.GetTradingDetails = function(player, data)
{
var cmpEntityTrader = Engine.QueryInterface(data.trader, IID_Trader);
@ -1595,6 +1606,7 @@ var exposedFunctions = {
"GetFoundationSnapData": 1,
"PlaySound": 1,
"FindIdleUnit": 1,
"GetTradingRouteGain": 1,
"GetTradingDetails": 1,
"CanAttack": 1,

View file

@ -1,8 +1,6 @@
// This constant used to adjust gain value depending on distance
const DISTANCE_FACTOR = 1 / 110;
// See helpers/TraderGain.js for the CalculateTaderGain() function which works out how many
// resources a trader gets
// Additional gain for trading performed between markets of different players, in percents
const INTERNATIONAL_TRADING_ADDITION = 50;
// Additional gain for ships for each garrisoned trader, in percents
const GARRISONED_TRADER_ADDITION = 20;
@ -36,30 +34,13 @@ Trader.prototype.Init = function()
this.goods = { "type": null, "amount": 0 };
}
Trader.prototype.CalculateGain = function(firstMarket, secondMarket)
Trader.prototype.CalculateGain = function(firstMarket, secondMarket, template)
{
var cmpFirstMarketPosition = Engine.QueryInterface(firstMarket, IID_Position);
var cmpSecondMarketPosition = Engine.QueryInterface(secondMarket, IID_Position);
if (!cmpFirstMarketPosition || !cmpFirstMarketPosition.IsInWorld() || !cmpSecondMarketPosition || !cmpSecondMarketPosition.IsInWorld())
return null;
var firstMarketPosition = cmpFirstMarketPosition.GetPosition2D();
var secondMarketPosition = cmpSecondMarketPosition.GetPosition2D();
// Calculate ordinary Euclidean distance between markets.
// We don't use pathfinder, because ordinary distance looks more fair.
var distance = Math.sqrt(Math.pow(firstMarketPosition.x - secondMarketPosition.x, 2) + Math.pow(firstMarketPosition.y - secondMarketPosition.y, 2));
// We calculate gain as square of distance to encourage trading between remote markets
var gain = Math.pow(distance * DISTANCE_FACTOR, 2);
// If markets belongs to different players, multiple gain to INTERNATIONAL_TRADING_MULTIPLIER
var cmpFirstMarketOwnership = Engine.QueryInterface(firstMarket, IID_Ownership);
var cmpSecondMarketOwnership = Engine.QueryInterface(secondMarket, IID_Ownership);
if (cmpFirstMarketOwnership.GetOwner() != cmpSecondMarketOwnership.GetOwner())
gain *= 1 + INTERNATIONAL_TRADING_ADDITION / 100;
// For ship increase gain for each garrisoned trader
// Calculate this here to save passing unnecessary stuff into the CalculatetraderGain function
var garrisonMultiplier = 1;
var cmpIdentity = Engine.QueryInterface(this.entity, IID_Identity);
if (cmpIdentity.HasClass("Ship"))
if (cmpIdentity && cmpIdentity.HasClass("Ship"))
{
var cmpGarrisonHolder = Engine.QueryInterface(this.entity, IID_GarrisonHolder);
if (cmpGarrisonHolder)
@ -71,14 +52,11 @@ Trader.prototype.CalculateGain = function(firstMarket, secondMarket)
if (cmpGarrisonedUnitTrader)
garrisonedTradersCount++;
}
gain *= 1 + GARRISONED_TRADER_ADDITION * garrisonedTradersCount / 100;
garrisonMultiplier *= 1 + GARRISONED_TRADER_ADDITION * garrisonedTradersCount / 100;
}
}
if (this.template.GainMultiplier)
gain *= this.template.GainMultiplier;
gain = Math.round(gain);
return gain;
return garrisonMultiplier * CalculateTraderGain(firstMarket, secondMarket, this.template);
}
Trader.prototype.GetGain = function()
@ -88,7 +66,7 @@ Trader.prototype.GetGain = function()
// Set target as target market.
// Return true if at least one of markets was changed.
Trader.prototype.SetTargetMarket = function(target)
Trader.prototype.SetTargetMarket = function(target, source)
{
// Check that target is a market
var cmpTargetIdentity = Engine.QueryInterface(target, IID_Identity);
@ -96,24 +74,37 @@ Trader.prototype.SetTargetMarket = function(target)
return false;
if (!cmpTargetIdentity.HasClass("Market") && !cmpTargetIdentity.HasClass("NavalMarket"))
return false;
var marketsChanged = false;
var marketsChanged = true;
if (source)
{
// Establish a trade route with both markets in one go.
cmpTargetIdentity = Engine.QueryInterface(source, IID_Identity);
if (!cmpTargetIdentity)
return false;
if (!cmpTargetIdentity.HasClass("Market") && !cmpTargetIdentity.HasClass("NavalMarket"))
return false;
this.firstMarket = source;
this.secondMarket = INVALID_ENTITY;
}
if (this.secondMarket)
{
// If we already have both markets - drop them
// and use the target as first market
this.firstMarket = target;
this.secondMarket = INVALID_ENTITY;
marketsChanged = true;
}
else if (this.firstMarket)
{
// If we have only one market and target is different from it,
// set the target as second one
if (target != this.firstMarket)
if (target == this.firstMarket)
marketsChanged = false;
else
{
this.secondMarket = target;
this.gain = this.CalculateGain(this.firstMarket, this.secondMarket);
marketsChanged = true;
}
}
else
@ -121,7 +112,6 @@ Trader.prototype.SetTargetMarket = function(target)
// Else we don't have target markets at all,
// set the target as first market
this.firstMarket = target;
marketsChanged = true;
}
if (marketsChanged)
{

View file

@ -2919,7 +2919,7 @@ UnitAI.prototype.ReturnResource = function(target, queued)
* Adds trade order to the queue. Either walk to the first market, or
* start a new route. Not forced, so it can be interrupted by attacks.
*/
UnitAI.prototype.SetupTradeRoute = function(target, queued)
UnitAI.prototype.SetupTradeRoute = function(target, source, queued)
{
if (!this.CanTrade(target))
{
@ -2928,7 +2928,7 @@ UnitAI.prototype.SetupTradeRoute = function(target, queued)
}
var cmpTrader = Engine.QueryInterface(this.entity, IID_Trader);
var marketsChanged = cmpTrader.SetTargetMarket(target);
var marketsChanged = cmpTrader.SetTargetMarket(target, source);
if (marketsChanged)
{
if (cmpTrader.HasBothMarkets())

View file

@ -379,7 +379,7 @@ function ProcessCommand(player, cmd)
{
var cmpUnitAI = Engine.QueryInterface(ent, IID_UnitAI);
if (cmpUnitAI)
cmpUnitAI.SetupTradeRoute(cmd.target);
cmpUnitAI.SetupTradeRoute(cmd.target, cmd.source);
}
break;

View file

@ -60,6 +60,15 @@ function GetRallyPointCommands(cmpRallyPoint, spawnedEnts)
"queued": true
});
break;
case "trade":
ret.push( {
"type": "setup-trade-route",
"entities": spawnedEnts,
"source": data[i].source,
"target": data[i].target,
"queued": true
});
break;
default:
ret.push( {
"type": "walk",

View file

@ -0,0 +1,34 @@
// This constant used to adjust gain value depending on distance
const DISTANCE_FACTOR = 1 / 110;
// Additional gain for trading performed between markets of different players, in percents
const INTERNATIONAL_TRADING_ADDITION = 50;
function CalculateTraderGain(firstMarket, secondMarket, template)
{
var cmpFirstMarketPosition = Engine.QueryInterface(firstMarket, IID_Position);
var cmpSecondMarketPosition = Engine.QueryInterface(secondMarket, IID_Position);
if (!cmpFirstMarketPosition || !cmpFirstMarketPosition.IsInWorld() || !cmpSecondMarketPosition || !cmpSecondMarketPosition.IsInWorld())
return null;
var firstMarketPosition = cmpFirstMarketPosition.GetPosition2D();
var secondMarketPosition = cmpSecondMarketPosition.GetPosition2D();
// Calculate ordinary Euclidean distance between markets.
// We don't use pathfinder, because ordinary distance looks more fair.
var distance = Math.sqrt(Math.pow(firstMarketPosition.x - secondMarketPosition.x, 2) + Math.pow(firstMarketPosition.y - secondMarketPosition.y, 2));
// We calculate gain as square of distance to encourage trading between remote markets
var gain = Math.pow(distance * DISTANCE_FACTOR, 2);
// If markets belongs to different players, multiple gain to INTERNATIONAL_TRADING_MULTIPLIER
var cmpFirstMarketOwnership = Engine.QueryInterface(firstMarket, IID_Ownership);
var cmpSecondMarketOwnership = Engine.QueryInterface(secondMarket, IID_Ownership);
if (cmpFirstMarketOwnership.GetOwner() != cmpSecondMarketOwnership.GetOwner())
gain *= 1 + INTERNATIONAL_TRADING_ADDITION / 100;
if (template.GainMultiplier)
gain *= template.GainMultiplier;
gain = Math.round(gain);
return gain;
}
Engine.RegisterGlobal("CalculateTraderGain", CalculateTraderGain);