Changeset View
Changeset View
Standalone View
Standalone View
ps/trunk/binaries/data/mods/public/simulation/components/UnitAI.js
Show First 20 Lines • Show All 1,791 Lines • ▼ Show 20 Lines | "COMBAT": { | ||||
// Go to the last known position and try to find enemies there. | // Go to the last known position and try to find enemies there. | ||||
let lastPos = this.order.data.lastPos; | let lastPos = this.order.data.lastPos; | ||||
this.PushOrder("Walk", { "x": lastPos.x, "z": lastPos.z, "force": false }); | this.PushOrder("Walk", { "x": lastPos.x, "z": lastPos.z, "force": false }); | ||||
this.PushOrder("WalkAndFight", { "x": lastPos.x, "z": lastPos.z, "force": false }); | this.PushOrder("WalkAndFight", { "x": lastPos.x, "z": lastPos.z, "force": false }); | ||||
return; | return; | ||||
} | } | ||||
if (!this.CheckTargetAttackRange(this.order.data.target, this.order.data.attackType)) | if (!this.CheckTargetAttackRange(this.order.data.target, this.order.data.attackType)) | ||||
{ | |||||
// Try moving again, | |||||
// attack range uses a height-related formula and our actual max range might have changed. | |||||
if (!this.MoveToTargetAttackRange(this.order.data.target, this.order.data.attackType)) | |||||
this.FinishOrder(); | |||||
return; | return; | ||||
} | |||||
// If the unit needs to unpack, do so | // If the unit needs to unpack, do so | ||||
if (this.CanUnpack()) | if (this.CanUnpack()) | ||||
{ | { | ||||
this.PushOrderFront("Unpack", { "force": true }); | this.PushOrderFront("Unpack", { "force": true }); | ||||
return; | return; | ||||
} | } | ||||
this.SetNextState("ATTACKING"); | this.SetNextState("ATTACKING"); | ||||
▲ Show 20 Lines • Show All 2,386 Lines • ▼ Show 20 Lines | |||||
* for melee attacks, this goes straight to the default range checks | * for melee attacks, this goes straight to the default range checks | ||||
* for ranged attacks, the parabolic range is used | * for ranged attacks, the parabolic range is used | ||||
*/ | */ | ||||
UnitAI.prototype.MoveToTargetAttackRange = function(target, type) | UnitAI.prototype.MoveToTargetAttackRange = function(target, type) | ||||
{ | { | ||||
// for formation members, the formation will take care of the range check | // for formation members, the formation will take care of the range check | ||||
if (this.IsFormationMember()) | if (this.IsFormationMember()) | ||||
{ | { | ||||
var cmpFormationUnitAI = Engine.QueryInterface(this.formationController, IID_UnitAI); | let cmpFormationUnitAI = Engine.QueryInterface(this.formationController, IID_UnitAI); | ||||
if (cmpFormationUnitAI && cmpFormationUnitAI.IsAttackingAsFormation()) | if (cmpFormationUnitAI && cmpFormationUnitAI.IsAttackingAsFormation()) | ||||
return false; | return false; | ||||
} | } | ||||
var cmpFormation = Engine.QueryInterface(target, IID_Formation); | let cmpFormation = Engine.QueryInterface(target, IID_Formation); | ||||
if (cmpFormation) | if (cmpFormation) | ||||
target = cmpFormation.GetClosestMember(this.entity); | target = cmpFormation.GetClosestMember(this.entity); | ||||
if (type != "Ranged") | if (type != "Ranged") | ||||
return this.MoveToTargetRange(target, IID_Attack, type); | return this.MoveToTargetRange(target, IID_Attack, type); | ||||
if (!this.CheckTargetVisible(target)) | if (!this.CheckTargetVisible(target)) | ||||
return false; | return false; | ||||
var cmpAttack = Engine.QueryInterface(this.entity, IID_Attack); | let cmpAttack = Engine.QueryInterface(this.entity, IID_Attack); | ||||
var range = cmpAttack.GetRange(type); | let range = cmpAttack.GetRange(type); | ||||
var thisCmpPosition = Engine.QueryInterface(this.entity, IID_Position); | let thisCmpPosition = Engine.QueryInterface(this.entity, IID_Position); | ||||
if (!thisCmpPosition.IsInWorld()) | if (!thisCmpPosition.IsInWorld()) | ||||
return false; | return false; | ||||
var s = thisCmpPosition.GetPosition(); | let s = thisCmpPosition.GetPosition(); | ||||
var targetCmpPosition = Engine.QueryInterface(target, IID_Position); | let targetCmpPosition = Engine.QueryInterface(target, IID_Position); | ||||
if (!targetCmpPosition.IsInWorld()) | if (!targetCmpPosition.IsInWorld()) | ||||
return false; | return false; | ||||
var t = targetCmpPosition.GetPosition(); | let t = targetCmpPosition.GetPosition(); | ||||
// h is positive when I'm higher than the target | // h is positive when I'm higher than the target | ||||
var h = s.y-t.y+range.elevationBonus; | let h = s.y - t.y + range.elevationBonus; | ||||
let parabolicMaxRange = Math.sqrt(Math.square(range.max) + 2 * range.max * h); | |||||
// No negative roots please | // No negative roots please | ||||
if (h>-range.max/2) | if (h <= -range.max / 2) | ||||
var parabolicMaxRange = Math.sqrt(Math.square(range.max) + 2 * range.max * h); | |||||
else | |||||
// return false? Or hope you come close enough? | // return false? Or hope you come close enough? | ||||
var parabolicMaxRange = 0; | parabolicMaxRange = 0; | ||||
//return false; | |||||
// the parabole changes while walking, take something in the middle | // The parabole changes while walking so be cautious: | ||||
var guessedMaxRange = (range.max + parabolicMaxRange)/2; | let guessedMaxRange = parabolicMaxRange > range.max ? (range.max + parabolicMaxRange) / 2 : parabolicMaxRange; | ||||
var cmpUnitMotion = Engine.QueryInterface(this.entity, IID_UnitMotion); | let cmpUnitMotion = Engine.QueryInterface(this.entity, IID_UnitMotion); | ||||
if (cmpUnitMotion.MoveToTargetRange(target, range.min, guessedMaxRange)) | return cmpUnitMotion.MoveToTargetRange(target, range.min, guessedMaxRange); | ||||
return true; | |||||
// if that failed, try closer | |||||
return cmpUnitMotion.MoveToTargetRange(target, range.min, Math.min(range.max, parabolicMaxRange)); | |||||
}; | }; | ||||
UnitAI.prototype.MoveToTargetRangeExplicit = function(target, min, max) | UnitAI.prototype.MoveToTargetRangeExplicit = function(target, min, max) | ||||
{ | { | ||||
if (!this.CheckTargetVisible(target)) | if (!this.CheckTargetVisible(target)) | ||||
return false; | return false; | ||||
var cmpUnitMotion = Engine.QueryInterface(this.entity, IID_UnitMotion); | var cmpUnitMotion = Engine.QueryInterface(this.entity, IID_UnitMotion); | ||||
▲ Show 20 Lines • Show All 59 Lines • ▼ Show 20 Lines | |||||
* For ranged attacks, the parabolic formula is used to accout for bigger ranges | * For ranged attacks, the parabolic formula is used to accout for bigger ranges | ||||
* when the target is lower, and smaller ranges when the target is higher | * when the target is lower, and smaller ranges when the target is higher | ||||
*/ | */ | ||||
UnitAI.prototype.CheckTargetAttackRange = function(target, type) | UnitAI.prototype.CheckTargetAttackRange = function(target, type) | ||||
{ | { | ||||
// for formation members, the formation will take care of the range check | // for formation members, the formation will take care of the range check | ||||
if (this.IsFormationMember()) | if (this.IsFormationMember()) | ||||
{ | { | ||||
var cmpFormationUnitAI = Engine.QueryInterface(this.formationController, IID_UnitAI); | let cmpFormationUnitAI = Engine.QueryInterface(this.formationController, IID_UnitAI); | ||||
if (cmpFormationUnitAI && cmpFormationUnitAI.IsAttackingAsFormation() | if (cmpFormationUnitAI && cmpFormationUnitAI.IsAttackingAsFormation() && | ||||
&& cmpFormationUnitAI.order.data.target == target) | cmpFormationUnitAI.order.data.target == target) | ||||
return true; | return true; | ||||
} | } | ||||
var cmpFormation = Engine.QueryInterface(target, IID_Formation); | let cmpFormation = Engine.QueryInterface(target, IID_Formation); | ||||
if (cmpFormation) | if (cmpFormation) | ||||
target = cmpFormation.GetClosestMember(this.entity); | target = cmpFormation.GetClosestMember(this.entity); | ||||
if (type != "Ranged") | if (type != "Ranged") | ||||
return this.CheckTargetRange(target, IID_Attack, type); | return this.CheckTargetRange(target, IID_Attack, type); | ||||
var targetCmpPosition = Engine.QueryInterface(target, IID_Position); | let targetCmpPosition = Engine.QueryInterface(target, IID_Position); | ||||
if (!targetCmpPosition || !targetCmpPosition.IsInWorld()) | if (!targetCmpPosition || !targetCmpPosition.IsInWorld()) | ||||
return false; | return false; | ||||
var cmpAttack = Engine.QueryInterface(this.entity, IID_Attack); | let cmpAttack = Engine.QueryInterface(this.entity, IID_Attack); | ||||
var range = cmpAttack.GetRange(type); | let range = cmpAttack.GetRange(type); | ||||
var thisCmpPosition = Engine.QueryInterface(this.entity, IID_Position); | let thisCmpPosition = Engine.QueryInterface(this.entity, IID_Position); | ||||
if (!thisCmpPosition.IsInWorld()) | if (!thisCmpPosition.IsInWorld()) | ||||
return false; | return false; | ||||
var s = thisCmpPosition.GetPosition(); | let s = thisCmpPosition.GetPosition(); | ||||
var t = targetCmpPosition.GetPosition(); | let t = targetCmpPosition.GetPosition(); | ||||
var h = s.y-t.y+range.elevationBonus; | let h = s.y - t.y + range.elevationBonus; | ||||
var maxRangeSq = 2*range.max*(h + range.max/2); | let maxRange = Math.sqrt(Math.square(range.max) + 2 * range.max * h); | ||||
if (maxRangeSq < 0) | if (maxRange < 0) | ||||
return false; | return false; | ||||
let cmpObstructionManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_ObstructionManager); | let cmpObstructionManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_ObstructionManager); | ||||
return cmpObstructionManager.IsInTargetRange(this.entity, target, range.min, Math.sqrt(maxRangeSq), false); | return cmpObstructionManager.IsInTargetRange(this.entity, target, range.min, maxRange, false); | ||||
}; | }; | ||||
UnitAI.prototype.CheckTargetRangeExplicit = function(target, min, max) | UnitAI.prototype.CheckTargetRangeExplicit = function(target, min, max) | ||||
{ | { | ||||
let cmpObstructionManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_ObstructionManager); | let cmpObstructionManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_ObstructionManager); | ||||
return cmpObstructionManager.IsInTargetRange(this.entity, target, min, max, false); | return cmpObstructionManager.IsInTargetRange(this.entity, target, min, max, false); | ||||
}; | }; | ||||
▲ Show 20 Lines • Show All 1,573 Lines • Show Last 20 Lines |
Wildfire Games · Phabricator