Changeset View
Changeset View
Standalone View
Standalone View
binaries/data/mods/public/simulation/components/UnitAI.js
Show First 20 Lines • Show All 3,681 Lines • ▼ Show 20 Lines | if (!this.orderQueue.length) | ||||
var stack = new Error().stack.trimRight().replace(/^/mg, ' '); // indent each line | var stack = new Error().stack.trimRight().replace(/^/mg, ' '); // indent each line | ||||
var cmpTemplateManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_TemplateManager); | var cmpTemplateManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_TemplateManager); | ||||
var template = cmpTemplateManager.GetCurrentTemplateName(this.entity); | var template = cmpTemplateManager.GetCurrentTemplateName(this.entity); | ||||
error("FinishOrder called for entity " + this.entity + " (" + template + ") when order queue is empty\n" + stack); | error("FinishOrder called for entity " + this.entity + " (" + template + ") when order queue is empty\n" + stack); | ||||
} | } | ||||
this.orderQueue.shift(); | this.orderQueue.shift(); | ||||
this.order = this.orderQueue[0]; | this.order = this.orderQueue[0]; | ||||
// Remove current waypoint | |||||
let cmpWayPoint = Engine.QueryInterface(this.entity, IID_WayPoint); | |||||
if (cmpWayPoint) | |||||
{ | |||||
cmpWayPoint.Shift(); | |||||
let cmpWayPointRenderer = Engine.QueryInterface(this.entity, IID_WayPointRenderer); | |||||
if (cmpWayPointRenderer) | |||||
cmpWayPointRenderer.Shift(); | |||||
} | |||||
// TODO: Waypoints for formations | |||||
if (this.orderQueue.length) | if (this.orderQueue.length) | ||||
{ | { | ||||
let ret = this.UnitFsm.ProcessMessage(this, | let ret = this.UnitFsm.ProcessMessage(this, | ||||
{"type": "Order."+this.order.type, "data": this.order.data} | {"type": "Order."+this.order.type, "data": this.order.data} | ||||
); | ); | ||||
Engine.PostMessage(this.entity, MT_UnitAIOrderDataChanged, { "to": this.GetOrderData() }); | Engine.PostMessage(this.entity, MT_UnitAIOrderDataChanged, { "to": this.GetOrderData() }); | ||||
Show All 35 Lines | |||||
* Add an order onto the back of the queue, | * Add an order onto the back of the queue, | ||||
* and execute it if we didn't already have an order. | * and execute it if we didn't already have an order. | ||||
*/ | */ | ||||
UnitAI.prototype.PushOrder = function(type, data) | UnitAI.prototype.PushOrder = function(type, data) | ||||
{ | { | ||||
var order = { "type": type, "data": data }; | var order = { "type": type, "data": data }; | ||||
this.orderQueue.push(order); | this.orderQueue.push(order); | ||||
if (!order.data.force) | |||||
this.AddWayPoint(data); | |||||
// If we didn't already have an order, then process this new one | // If we didn't already have an order, then process this new one | ||||
if (this.orderQueue.length == 1) | if (this.orderQueue.length == 1) | ||||
{ | { | ||||
this.order = order; | this.order = order; | ||||
let ret = this.UnitFsm.ProcessMessage(this, | let ret = this.UnitFsm.ProcessMessage(this, | ||||
{"type": "Order."+this.order.type, "data": this.order.data} | { "type": "Order." + this.order.type, "data": this.order.data } | ||||
); | ); | ||||
// If the order was rejected then immediately take it off | // If the order was rejected then immediately take it off | ||||
// and process the remaining queue | // and process the remaining queue | ||||
if (ret && ret.discardOrder) | if (ret && ret.discardOrder) | ||||
this.FinishOrder(); | this.FinishOrder(); | ||||
} | } | ||||
Engine.PostMessage(this.entity, MT_UnitAIOrderDataChanged, { "to": this.GetOrderData() }); | Engine.PostMessage(this.entity, MT_UnitAIOrderDataChanged, { "to": this.GetOrderData() }); | ||||
}; | }; | ||||
/** | /** | ||||
* Add an order onto the front of the queue, | * Add an order onto the front of the queue, | ||||
* and execute it immediately. | * and execute it immediately. | ||||
*/ | */ | ||||
UnitAI.prototype.PushOrderFront = function(type, data) | UnitAI.prototype.PushOrderFront = function(type, data) | ||||
{ | { | ||||
var order = { "type": type, "data": data }; | var order = { "type": type, "data": data }; | ||||
// If current order is cheering then add new order after it | // If current order is cheering then add new order after it | ||||
// same thing if current order if packing/unpacking | // same thing if current order if packing/unpacking | ||||
if (this.order && this.order.type == "Cheering") | if (this.order && this.order.type == "Cheering") | ||||
{ | { | ||||
var cheeringOrder = this.orderQueue.shift(); | var cheeringOrder = this.orderQueue.shift(); | ||||
this.orderQueue.unshift(cheeringOrder, order); | this.orderQueue.unshift(cheeringOrder, order); | ||||
// TODO: AddWayPoint | |||||
} | } | ||||
else if (this.order && this.IsPacking()) | else if (this.order && this.IsPacking()) | ||||
{ | { | ||||
var packingOrder = this.orderQueue.shift(); | var packingOrder = this.orderQueue.shift(); | ||||
this.orderQueue.unshift(packingOrder, order); | this.orderQueue.unshift(packingOrder, order); | ||||
} | } | ||||
else | else | ||||
{ | { | ||||
this.orderQueue.unshift(order); | this.orderQueue.unshift(order); | ||||
this.order = order; | this.order = order; | ||||
this.StackWayPoint(data); | |||||
let ret = this.UnitFsm.ProcessMessage(this, | let ret = this.UnitFsm.ProcessMessage(this, | ||||
{"type": "Order."+this.order.type, "data": this.order.data} | {"type": "Order."+this.order.type, "data": this.order.data} | ||||
); | ); | ||||
// If the order was rejected then immediately take it off again; | // If the order was rejected then immediately take it off again; | ||||
// assume the previous active order is still valid (the short-lived | // assume the previous active order is still valid (the short-lived | ||||
// new order hasn't changed state or anything) so we can carry on | // new order hasn't changed state or anything) so we can carry on | ||||
// as if nothing had happened | // as if nothing had happened | ||||
if (ret && ret.discardOrder) | if (ret && ret.discardOrder) | ||||
{ | { | ||||
this.orderQueue.shift(); | this.orderQueue.shift(); | ||||
this.order = this.orderQueue[0]; | this.order = this.orderQueue[0]; | ||||
} | } | ||||
// TODO: WayPoints | |||||
} | } | ||||
Engine.PostMessage(this.entity, MT_UnitAIOrderDataChanged, { "to": this.GetOrderData() }); | Engine.PostMessage(this.entity, MT_UnitAIOrderDataChanged, { "to": this.GetOrderData() }); | ||||
}; | }; | ||||
/** | /** | ||||
* Insert an order after the last forced order onto the queue | * Insert an order after the last forced order onto the queue | ||||
▲ Show 20 Lines • Show All 42 Lines • ▼ Show 20 Lines | if (this.order && this.order.type == "Cheering") | ||||
var cheeringOrder = this.orderQueue.shift(); | var cheeringOrder = this.orderQueue.shift(); | ||||
this.orderQueue = [cheeringOrder, order]; | this.orderQueue = [cheeringOrder, order]; | ||||
} | } | ||||
else if (this.IsPacking() && type != "CancelPack" && type != "CancelUnpack") | else if (this.IsPacking() && type != "CancelPack" && type != "CancelUnpack") | ||||
{ | { | ||||
var order = { "type": type, "data": data }; | var order = { "type": type, "data": data }; | ||||
var packingOrder = this.orderQueue.shift(); | var packingOrder = this.orderQueue.shift(); | ||||
this.orderQueue = [packingOrder, order]; | this.orderQueue = [packingOrder, order]; | ||||
// TODO Waypoints | |||||
} | } | ||||
else | else | ||||
{ | { | ||||
this.orderQueue = []; | this.orderQueue = []; | ||||
this.PushOrder(type, data); | this.PushOrder(type, data); | ||||
this.ReplaceWayPoint(data); | |||||
} | } | ||||
Engine.PostMessage(this.entity, MT_UnitAIOrderDataChanged, { "to": this.GetOrderData() }); | Engine.PostMessage(this.entity, MT_UnitAIOrderDataChanged, { "to": this.GetOrderData() }); | ||||
}; | }; | ||||
UnitAI.prototype.StackWayPoint = function(data) | |||||
{ | |||||
let cmpWayPoint = Engine.QueryInterface(this.entity, IID_WayPoint); | |||||
if(!cmpWayPoint) | |||||
return; | |||||
let pos; | |||||
let cmpPosition = Engine.QueryInterface(data.target, IID_Position); | |||||
if (data.target && cmpPosition) | |||||
pos = cmpPosition.GetPosition(); | |||||
else | |||||
pos = {'x': data.x, 'z': data.z }; | |||||
cmpWayPoint.AddPositionFront(pos.x, pos.z); | |||||
let cmpWayPointRenderer = Engine.QueryInterface(this.entity, IID_WayPointRenderer); | |||||
// AddPositionFront takes a CFixedVector2D which has X/Y components, not X/Z | |||||
if (cmpWayPointRenderer) | |||||
cmpWayPointRenderer.Stack({'x': pos.x, 'y': pos.z}); | |||||
}; | |||||
UnitAI.prototype.AddWayPoint = function(data) | |||||
{ | |||||
var cmpWayPoint = Engine.QueryInterface(this.entity, IID_WayPoint); | |||||
if (cmpWayPoint) | |||||
{ | |||||
var pos; | |||||
var cmpPosition; | |||||
if (data.target && (cmpPosition = Engine.QueryInterface(data.target, IID_Position))) | |||||
pos = cmpPosition.GetPosition(); | |||||
else if (data.x && data.z) | |||||
pos = {'x': data.x, 'z': data.z}; | |||||
else | |||||
return; | |||||
cmpWayPoint.AddPosition(pos.x, pos.z); | |||||
var cmpWayPointRenderer = Engine.QueryInterface(this.entity, IID_WayPointRenderer); | |||||
if (cmpWayPointRenderer) | |||||
cmpWayPointRenderer.AddPosition({'x': pos.x, 'y': pos.z}); // AddPosition takes a CFixedVector2D which has X/Y components, not X/Z | |||||
} | |||||
}; | |||||
UnitAI.prototype.ReplaceWayPoint = function(data) | |||||
{ | |||||
let cmpWayPoint = Engine.QueryInterface(this.entity, IID_WayPoint); | |||||
if (!cmpWayPoint) | |||||
return; | |||||
let pos; | |||||
let cmpPosition; | |||||
cmpWayPoint.Unset(); | |||||
if (data.target && (cmpPosition = Engine.QueryInterface(data.target, IID_Position))) | |||||
pos = cmpPosition.GetPosition(); | |||||
else if (data.x && data.z) | |||||
pos = {'x': data.x, 'z': data.z}; | |||||
else | |||||
return; | |||||
cmpWayPoint.AddPosition(pos.x, pos.z); | |||||
let cmpWayPointRenderer = Engine.QueryInterface(this.entity, IID_WayPointRenderer); | |||||
// SetPosition takes a CFixedVector2D which has X/Y components, not X/Z | |||||
if (cmpWayPointRenderer) | |||||
cmpWayPointRenderer.SetPosition({'x': pos.x, 'y': pos.z}); } | |||||
UnitAI.prototype.GetOrders = function() | UnitAI.prototype.GetOrders = function() | ||||
{ | { | ||||
return this.orderQueue.slice(); | return this.orderQueue.slice(); | ||||
}; | }; | ||||
UnitAI.prototype.AddOrders = function(orders) | UnitAI.prototype.AddOrders = function(orders) | ||||
{ | { | ||||
orders.forEach(order => this.PushOrder(order.type, order.data)); | orders.forEach(order => this.PushOrder(order.type, order.data)); | ||||
▲ Show 20 Lines • Show All 1,418 Lines • ▼ Show 20 Lines | UnitAI.prototype.SetupTradeRoute = function(target, source, route, queued) | ||||
var marketsChanged = this.SetTargetMarket(target, source); | var marketsChanged = this.SetTargetMarket(target, source); | ||||
if (!marketsChanged) | if (!marketsChanged) | ||||
return; | return; | ||||
var cmpTrader = Engine.QueryInterface(this.entity, IID_Trader); | var cmpTrader = Engine.QueryInterface(this.entity, IID_Trader); | ||||
if (cmpTrader.HasBothMarkets()) | if (cmpTrader.HasBothMarkets()) | ||||
{ | { | ||||
this.AddWayPoint({"target": cmpTrader.GetFirstMarket()}); | |||||
this.AddWayPoint({"target": cmpTrader.GetSecondMarket()}); | |||||
let data = { | let data = { | ||||
"target": cmpTrader.GetFirstMarket(), | "target": cmpTrader.GetFirstMarket(), | ||||
"route": route, | "route": route, | ||||
"force": false | "force": false | ||||
}; | }; | ||||
if (this.expectedRoute) | if (this.expectedRoute) | ||||
{ | { | ||||
Show All 38 Lines | |||||
UnitAI.prototype.SwitchMarketOrder = function(oldMarket, newMarket) | UnitAI.prototype.SwitchMarketOrder = function(oldMarket, newMarket) | ||||
{ | { | ||||
if (this.order && this.order.data && this.order.data.target && this.order.data.target == oldMarket) | if (this.order && this.order.data && this.order.data.target && this.order.data.target == oldMarket) | ||||
this.order.data.target = newMarket; | this.order.data.target = newMarket; | ||||
}; | }; | ||||
UnitAI.prototype.MoveToMarket = function(targetMarket) | UnitAI.prototype.MoveToMarket = function(targetMarket) | ||||
{ | { | ||||
let cmpWayPoint = Engine.QueryInterface(this.entity, IID_WayPoint); | |||||
if (cmpWayPoint) | |||||
{ | |||||
cmpWayPoint.Shift(); | |||||
let cmpWayPointRenderer = Engine.QueryInterface(this.entity, IID_WayPointRenderer); | |||||
if (cmpWayPointRenderer) | |||||
cmpWayPointRenderer.Shift(); | |||||
} | |||||
if (this.waypoints && this.waypoints.length > 1) | if (this.waypoints && this.waypoints.length > 1) | ||||
{ | { | ||||
let point = this.waypoints.pop(); | let point = this.waypoints.pop(); | ||||
return this.MoveToPoint(point.x, point.z) || this.MoveToMarket(targetMarket); | return this.MoveToPoint(point.x, point.z) || this.MoveToMarket(targetMarket); | ||||
} | } | ||||
this.waypoints = undefined; | this.waypoints = undefined; | ||||
return this.MoveToTarget(targetMarket); | return this.MoveToTarget(targetMarket); | ||||
}; | }; | ||||
UnitAI.prototype.PerformTradeAndMoveToNextMarket = function(currentMarket) | UnitAI.prototype.PerformTradeAndMoveToNextMarket = function(currentMarket) | ||||
{ | { | ||||
if (!this.CanTrade(currentMarket)) | if (!this.CanTrade(currentMarket)) | ||||
{ | { | ||||
this.StopTrading(); | this.StopTrading(); | ||||
// TODO clear waypoints | |||||
return; | return; | ||||
} | } | ||||
if (!this.CheckTargetRange(currentMarket, IID_Trader)) | if (!this.CheckTargetRange(currentMarket, IID_Trader)) | ||||
{ | { | ||||
this.AddWayPoint({"target": currentMarket}); | |||||
if (!this.MoveToMarket(currentMarket)) // If the current market is not reached try again | if (!this.MoveToMarket(currentMarket)) // If the current market is not reached try again | ||||
this.StopTrading(); | this.StopTrading(); | ||||
return; | return; | ||||
} | } | ||||
let cmpTrader = Engine.QueryInterface(this.entity, IID_Trader); | let cmpTrader = Engine.QueryInterface(this.entity, IID_Trader); | ||||
let nextMarket = cmpTrader.PerformTrade(currentMarket); | let nextMarket = cmpTrader.PerformTrade(currentMarket); | ||||
let amount = cmpTrader.GetGoods().amount; | let amount = cmpTrader.GetGoods().amount; | ||||
▲ Show 20 Lines • Show All 733 Lines • Show Last 20 Lines |
Wildfire Games · Phabricator