Changeset View
Changeset View
Standalone View
Standalone View
binaries/data/mods/public/simulation/components/UnitAI.js
Show First 20 Lines • Show All 174 Lines • ▼ Show 20 Lines | UnitAI.prototype.UnitFsmSpec = { | ||||
"LosHealRangeUpdate": function(msg) { | "LosHealRangeUpdate": function(msg) { | ||||
// Ignore newly-seen injured units by default. | // Ignore newly-seen injured units by default. | ||||
}, | }, | ||||
"LosAttackRangeUpdate": function(msg) { | "LosAttackRangeUpdate": function(msg) { | ||||
// Ignore newly-seen enemy units by default. | // Ignore newly-seen enemy units by default. | ||||
}, | }, | ||||
"MissileHit": function(msg) { | |||||
// Ignore by default. | |||||
}, | |||||
"Attacked": function(msg) { | "Attacked": function(msg) { | ||||
// ignore attacker | // ignore attacker | ||||
}, | }, | ||||
"HealthChanged": function(msg) { | "HealthChanged": function(msg) { | ||||
// ignore | // ignore | ||||
}, | }, | ||||
▲ Show 20 Lines • Show All 1,725 Lines • ▼ Show 20 Lines | "COMBAT": { | ||||
let cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer); | let cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer); | ||||
let repeatLeft = this.lastAttacked + this.attackTimers.repeat - cmpTimer.GetTime(); | let repeatLeft = this.lastAttacked + this.attackTimers.repeat - cmpTimer.GetTime(); | ||||
prepare = Math.max(prepare, repeatLeft); | prepare = Math.max(prepare, repeatLeft); | ||||
} | } | ||||
if (!this.formationAnimationVariant) | if (!this.formationAnimationVariant) | ||||
this.SetAnimationVariant("combat"); | this.SetAnimationVariant("combat"); | ||||
this.failedAttacks = 0; | |||||
this.oldAttackType = this.order.data.attackType; | this.oldAttackType = this.order.data.attackType; | ||||
this.SelectAnimation("attack_" + this.order.data.attackType.toLowerCase()); | this.SelectAnimation("attack_" + this.order.data.attackType.toLowerCase()); | ||||
this.SetAnimationSync(prepare, this.attackTimers.repeat); | this.SetAnimationSync(prepare, this.attackTimers.repeat); | ||||
this.StartTimer(prepare, this.attackTimers.repeat); | this.StartTimer(prepare, this.attackTimers.repeat); | ||||
// TODO: we should probably only bother syncing projectile attacks, not melee | // TODO: we should probably only bother syncing projectile attacks, not melee | ||||
// If using a non-default prepare time, re-sync the animation when the timer runs. | // If using a non-default prepare time, re-sync the animation when the timer runs. | ||||
this.resyncAnimation = prepare != this.attackTimers.prepare; | this.resyncAnimation = prepare != this.attackTimers.prepare; | ||||
Show All 16 Lines | "COMBAT": { | ||||
}, | }, | ||||
"leave": function() { | "leave": function() { | ||||
let cmpBuildingAI = Engine.QueryInterface(this.entity, IID_BuildingAI); | let cmpBuildingAI = Engine.QueryInterface(this.entity, IID_BuildingAI); | ||||
if (cmpBuildingAI) | if (cmpBuildingAI) | ||||
cmpBuildingAI.SetUnitAITarget(0); | cmpBuildingAI.SetUnitAITarget(0); | ||||
this.StopTimer(); | this.StopTimer(); | ||||
this.ResetAnimation(); | this.ResetAnimation(); | ||||
delete this.failedAttacks; | |||||
}, | }, | ||||
"Timer": function(msg) { | "Timer": function(msg) { | ||||
let target = this.order.data.target; | let target = this.order.data.target; | ||||
let attackType = this.order.data.attackType; | let attackType = this.order.data.attackType; | ||||
if (!this.CanAttack(target)) | if (!this.CanAttack(target)) | ||||
{ | { | ||||
Show All 10 Lines | "COMBAT": { | ||||
this.FaceTowardsTarget(target); | this.FaceTowardsTarget(target); | ||||
// BuildingAI has it's own attack-routine | // BuildingAI has it's own attack-routine | ||||
let cmpBuildingAI = Engine.QueryInterface(this.entity, IID_BuildingAI); | let cmpBuildingAI = Engine.QueryInterface(this.entity, IID_BuildingAI); | ||||
if (!cmpBuildingAI) | if (!cmpBuildingAI) | ||||
{ | { | ||||
let cmpAttack = Engine.QueryInterface(this.entity, IID_Attack); | let cmpAttack = Engine.QueryInterface(this.entity, IID_Attack); | ||||
cmpAttack.PerformAttack(attackType, target); | cmpAttack.PerformAttack(attackType, target, this.failedAttacks > 5); | ||||
bb: magical constant 5 should be thought about. Not sure how many arrows Cleopatra can fire before… | |||||
} | } | ||||
// PerformAttack might have triggered messages that moved us to another state. | // PerformAttack might have triggered messages that moved us to another state. | ||||
// (use 'ends with' to handle animals/formation members copying our state). | // (use 'ends with' to handle animals/formation members copying our state). | ||||
if (!this.GetCurrentState().endsWith("COMBAT.ATTACKING")) | if (!this.GetCurrentState().endsWith("COMBAT.ATTACKING")) | ||||
return; | return; | ||||
Show All 25 Lines | "COMBAT": { | ||||
// TODO: respond to target deaths immediately, rather than waiting | // TODO: respond to target deaths immediately, rather than waiting | ||||
// until the next Timer event | // until the next Timer event | ||||
"Attacked": function(msg) { | "Attacked": function(msg) { | ||||
if (this.order.data.attackType == "Capture" && (this.GetStance().targetAttackersAlways || !this.order.data.force) | if (this.order.data.attackType == "Capture" && (this.GetStance().targetAttackersAlways || !this.order.data.force) | ||||
&& this.order.data.target != msg.data.attacker && this.GetBestAttackAgainst(msg.data.attacker, true) != "Capture") | && this.order.data.target != msg.data.attacker && this.GetBestAttackAgainst(msg.data.attacker, true) != "Capture") | ||||
this.RespondToTargetedEntities([msg.data.attacker]); | this.RespondToTargetedEntities([msg.data.attacker]); | ||||
}, | }, | ||||
"MissileHit": function(msg) { | |||||
if (!msg.success) | |||||
++this.failedAttacks; | |||||
}, | |||||
}, | }, | ||||
"FINDINGNEWTARGET": { | "FINDINGNEWTARGET": { | ||||
"Order.Cheer": function() { | "Order.Cheer": function() { | ||||
if (!this.cheeringTime) | if (!this.cheeringTime) | ||||
return { "discardOrder": true }; | return { "discardOrder": true }; | ||||
this.SetNextState("CHEERING"); | this.SetNextState("CHEERING"); | ||||
▲ Show 20 Lines • Show All 2,111 Lines • ▼ Show 20 Lines | if (!changed) | ||||
return; | return; | ||||
if (currentOrderChanged) | if (currentOrderChanged) | ||||
this.UnitFsm.ProcessMessage(this, { "type": "OrderTargetRenamed", "data": msg }); | this.UnitFsm.ProcessMessage(this, { "type": "OrderTargetRenamed", "data": msg }); | ||||
Engine.PostMessage(this.entity, MT_UnitAIOrderDataChanged, { "to": this.GetOrderData() }); | Engine.PostMessage(this.entity, MT_UnitAIOrderDataChanged, { "to": this.GetOrderData() }); | ||||
}; | }; | ||||
UnitAI.prototype.MissileHit = function(success) | |||||
{ | |||||
this.UnitFsm.ProcessMessage(this, {"type": "MissileHit", "success": success}); | |||||
bbUnsubmitted Not Done Inline Actionsspaces bb: spaces | |||||
}; | |||||
UnitAI.prototype.OnAttacked = function(msg) | UnitAI.prototype.OnAttacked = function(msg) | ||||
{ | { | ||||
if (msg.fromStatusEffect) | if (msg.fromStatusEffect) | ||||
return; | return; | ||||
this.UnitFsm.ProcessMessage(this, {"type": "Attacked", "data": msg}); | this.UnitFsm.ProcessMessage(this, {"type": "Attacked", "data": msg}); | ||||
}; | }; | ||||
▲ Show 20 Lines • Show All 2,230 Lines • Show Last 20 Lines |
Wildfire Games · Phabricator
magical constant 5 should be thought about. Not sure how many arrows Cleopatra can fire before the first one hit. the value should be somehow depend to the expectation value of misses (by spread) and the amount of arrows fired before the arrow arrives.