mirror of
https://gitea.wildfiregames.com/0ad/0ad
synced 2026-06-18 14:23:56 -07:00
eslint --no-config-lookup --fix --rule '"prefer-const": 1' \
binaries/data/mods/public/simulation/components/[H-P]*
Ref: #7812
Signed-off-by: Ralph Sennhauser <ralph.sennhauser@gmail.com>
220 lines
6.6 KiB
JavaScript
220 lines
6.6 KiB
JavaScript
function Market() {}
|
|
|
|
Market.prototype.Schema =
|
|
"<element name='TradeType' a:help='Specifies the type of possible trade route (land or naval).'>" +
|
|
"<list>" +
|
|
"<oneOrMore>" +
|
|
"<choice>" +
|
|
"<value>land</value>" +
|
|
"<value>naval</value>" +
|
|
"</choice>" +
|
|
"</oneOrMore>" +
|
|
"</list>" +
|
|
"</element>" +
|
|
"<element name='InternationalBonus' a:help='Additional part of the gain donated when two different players trade'>" +
|
|
"<ref name='nonNegativeDecimal'/>" +
|
|
"</element>";
|
|
|
|
Market.prototype.Init = function()
|
|
{
|
|
this.traders = new Set(); // list of traders with a route on this market
|
|
this.tradeType = new Set(this.template.TradeType.split(/\s+/));
|
|
};
|
|
|
|
Market.prototype.AddTrader = function(ent)
|
|
{
|
|
this.traders.add(ent);
|
|
};
|
|
|
|
Market.prototype.RemoveTrader = function(ent)
|
|
{
|
|
this.traders.delete(ent);
|
|
};
|
|
|
|
Market.prototype.GetInternationalBonus = function()
|
|
{
|
|
return ApplyValueModificationsToEntity("Market/InternationalBonus", +this.template.InternationalBonus, this.entity);
|
|
};
|
|
|
|
Market.prototype.HasType = function(type)
|
|
{
|
|
return this.tradeType.has(type);
|
|
};
|
|
|
|
Market.prototype.GetType = function()
|
|
{
|
|
return this.tradeType;
|
|
};
|
|
|
|
Market.prototype.GetTraders = function()
|
|
{
|
|
return this.traders;
|
|
};
|
|
|
|
/**
|
|
* Check if the traders attached to this market can still trade with it
|
|
* Warning: traders currently trading with a mirage of this market are dealt with in Mirage.js
|
|
*/
|
|
|
|
Market.prototype.UpdateTraders = function(onDestruction)
|
|
{
|
|
for (const trader of this.traders)
|
|
{
|
|
const cmpTrader = Engine.QueryInterface(trader, IID_Trader);
|
|
if (!cmpTrader)
|
|
{
|
|
this.RemoveTrader(trader);
|
|
continue;
|
|
}
|
|
if (!cmpTrader.HasMarket(this.entity) || !onDestruction && cmpTrader.CanTrade(this.entity))
|
|
continue;
|
|
// this trader can no more trade
|
|
this.RemoveTrader(trader);
|
|
cmpTrader.RemoveMarket(this.entity);
|
|
}
|
|
};
|
|
|
|
Market.prototype.CalculateTraderGain = function(secondMarket, traderTemplate, trader)
|
|
{
|
|
const cmpMarket2 = QueryMiragedInterface(secondMarket, IID_Market);
|
|
if (!cmpMarket2)
|
|
return null;
|
|
|
|
const cmpMarket1Player = QueryOwnerInterface(this.entity);
|
|
const cmpMarket2Player = QueryOwnerInterface(secondMarket);
|
|
if (!cmpMarket1Player || !cmpMarket2Player)
|
|
return null;
|
|
|
|
const cmpFirstMarketPosition = Engine.QueryInterface(this.entity, IID_Position);
|
|
const cmpSecondMarketPosition = Engine.QueryInterface(secondMarket, IID_Position);
|
|
if (!cmpFirstMarketPosition || !cmpFirstMarketPosition.IsInWorld() ||
|
|
!cmpSecondMarketPosition || !cmpSecondMarketPosition.IsInWorld())
|
|
return null;
|
|
const firstMarketPosition = cmpFirstMarketPosition.GetPosition2D();
|
|
const secondMarketPosition = cmpSecondMarketPosition.GetPosition2D();
|
|
|
|
const mapSize = Engine.QueryInterface(SYSTEM_ENTITY, IID_Terrain).GetMapSize();
|
|
let gainMultiplier = TradeGainNormalization(mapSize);
|
|
if (trader)
|
|
{
|
|
const cmpTrader = Engine.QueryInterface(trader, IID_Trader);
|
|
if (!cmpTrader)
|
|
return null;
|
|
gainMultiplier *= cmpTrader.GetTraderGainMultiplier();
|
|
}
|
|
// Called from the gui, modifications already applied.
|
|
else
|
|
{
|
|
if (!traderTemplate || !traderTemplate.GainMultiplier)
|
|
return null;
|
|
gainMultiplier *= traderTemplate.GainMultiplier;
|
|
}
|
|
|
|
const gain = {};
|
|
|
|
// Calculate ordinary Euclidean distance between markets.
|
|
// We don't use pathfinder, because ordinary distance looks more fair.
|
|
const distanceSq = firstMarketPosition.distanceToSquared(secondMarketPosition);
|
|
// We calculate gain as square of distance to encourage trading between remote markets
|
|
// and gainMultiplier corresponds to the gain for a 100m distance
|
|
gain.traderGain = Math.round(gainMultiplier * TradeGain(distanceSq, mapSize));
|
|
|
|
gain.market1Owner = cmpMarket1Player.GetPlayerID();
|
|
gain.market2Owner = cmpMarket2Player.GetPlayerID();
|
|
// If trader undefined, the trader owner is supposed to be the same as the first market.
|
|
const cmpPlayer = trader ? QueryOwnerInterface(trader) : cmpMarket1Player;
|
|
if (!cmpPlayer)
|
|
return null;
|
|
gain.traderOwner = cmpPlayer.GetPlayerID();
|
|
|
|
if (gain.market1Owner != gain.market2Owner)
|
|
{
|
|
const internationalBonus1 = this.GetInternationalBonus();
|
|
const internationalBonus2 = cmpMarket2.GetInternationalBonus();
|
|
gain.market1Gain = Math.round(gain.traderGain * internationalBonus1);
|
|
gain.market2Gain = Math.round(gain.traderGain * internationalBonus2);
|
|
}
|
|
|
|
return gain;
|
|
};
|
|
|
|
Market.prototype.OnDiplomacyChanged = function(msg)
|
|
{
|
|
this.UpdateTraders(false);
|
|
};
|
|
|
|
Market.prototype.OnOwnershipChanged = function(msg)
|
|
{
|
|
this.UpdateTraders(msg.to == INVALID_PLAYER);
|
|
};
|
|
|
|
function MarketMirage() {}
|
|
MarketMirage.prototype.Init = function(cmpMarket, entity, parent, player)
|
|
{
|
|
this.entity = entity;
|
|
this.parent = parent;
|
|
this.player = player;
|
|
|
|
this.traders = new Set();
|
|
for (const trader of cmpMarket.GetTraders())
|
|
{
|
|
const cmpTrader = Engine.QueryInterface(trader, IID_Trader);
|
|
const cmpOwnership = Engine.QueryInterface(trader, IID_Ownership);
|
|
if (!cmpTrader || !cmpOwnership)
|
|
{
|
|
cmpMarket.RemoveTrader(trader);
|
|
continue;
|
|
}
|
|
if (this.player != cmpOwnership.GetOwner())
|
|
continue;
|
|
cmpTrader.SwitchMarket(cmpMarket.entity, this.entity);
|
|
cmpMarket.RemoveTrader(trader);
|
|
this.AddTrader(trader);
|
|
}
|
|
this.marketType = cmpMarket.GetType();
|
|
this.internationalBonus = cmpMarket.GetInternationalBonus();
|
|
};
|
|
|
|
MarketMirage.prototype.HasType = function(type) { return this.marketType.has(type); };
|
|
MarketMirage.prototype.GetInternationalBonus = function() { return this.internationalBonus; };
|
|
MarketMirage.prototype.AddTrader = function(trader) { this.traders.add(trader); };
|
|
MarketMirage.prototype.RemoveTrader = function(trader) { this.traders.delete(trader); };
|
|
|
|
MarketMirage.prototype.UpdateTraders = function(msg)
|
|
{
|
|
const cmpMarket = Engine.QueryInterface(this.parent, IID_Market);
|
|
if (!cmpMarket) // The parent market does not exist anymore
|
|
{
|
|
for (const trader of this.traders)
|
|
{
|
|
const cmpTrader = Engine.QueryInterface(trader, IID_Trader);
|
|
if (cmpTrader)
|
|
cmpTrader.RemoveMarket(this.entity);
|
|
}
|
|
return;
|
|
}
|
|
|
|
// The market becomes visible, switch all traders from the mirage to the market
|
|
for (const trader of this.traders)
|
|
{
|
|
const cmpTrader = Engine.QueryInterface(trader, IID_Trader);
|
|
if (!cmpTrader)
|
|
continue;
|
|
cmpTrader.SwitchMarket(this.entity, cmpMarket.entity);
|
|
this.RemoveTrader(trader);
|
|
cmpMarket.AddTrader(trader);
|
|
}
|
|
};
|
|
|
|
MarketMirage.prototype.CalculateTraderGain = Market.prototype.CalculateTraderGain;
|
|
|
|
Engine.RegisterGlobal("MarketMirage", MarketMirage);
|
|
|
|
Market.prototype.Mirage = function(mirageID, miragePlayer)
|
|
{
|
|
const mirage = new MarketMirage();
|
|
mirage.Init(this, mirageID, this.entity, miragePlayer);
|
|
return mirage;
|
|
};
|
|
|
|
Engine.RegisterComponentType(IID_Market, "Market", Market);
|