Changeset View
Changeset View
Standalone View
Standalone View
binaries/data/mods/public/simulation/components/Gate.js
Show All 9 Lines | Gate.prototype.Schema = | ||||
"</element>"; | "</element>"; | ||||
/** | /** | ||||
* Initialize Gate component | * Initialize Gate component | ||||
*/ | */ | ||||
Gate.prototype.Init = function() | Gate.prototype.Init = function() | ||||
{ | { | ||||
this.allies = []; | this.allies = []; | ||||
this.ignoreList = []; | |||||
this.opened = false; | this.opened = false; | ||||
this.locked = false; | this.locked = false; | ||||
}; | }; | ||||
/** | |||||
* Handle the renaming case (from long-wall to gate) | |||||
* because that does not trigger ownershipchange or diplomacy change | |||||
* and units don't get added to the ignorelist. | |||||
*/ | |||||
Gate.prototype.OnEntityRenamed = function(msg) | |||||
{ | |||||
let cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership); | |||||
if (!cmpOwnership || cmpOwnership.GetOwner() == INVALID_PLAYER) | |||||
return; | |||||
this.SetupRangeQuery(); | |||||
}; | |||||
Gate.prototype.OnOwnershipChanged = function(msg) | Gate.prototype.OnOwnershipChanged = function(msg) | ||||
{ | { | ||||
if (msg.to != INVALID_PLAYER) | if (msg.to != INVALID_PLAYER) | ||||
{ | { | ||||
this.SetupRangeQuery(msg.to); | this.SetupRangeQuery(msg.to); | ||||
// Set the initial state, but don't play unlocking sound | // Set the initial state, but don't play unlocking sound | ||||
if (!this.locked) | if (!this.locked) | ||||
this.UnlockGate(true); | this.UnlockGate(true); | ||||
} | } | ||||
}; | }; | ||||
Gate.prototype.OnDiplomacyChanged = function(msg) | Gate.prototype.OnDiplomacyChanged = function(msg) | ||||
{ | { | ||||
var cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership); | let cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership); | ||||
if (cmpOwnership && cmpOwnership.GetOwner() == msg.player) | if (cmpOwnership && cmpOwnership.GetOwner() == msg.player) | ||||
{ | { | ||||
this.allies = []; | this.allies = []; | ||||
this.ignoreList = []; | |||||
this.SetupRangeQuery(msg.player); | this.SetupRangeQuery(msg.player); | ||||
} | } | ||||
}; | }; | ||||
/** | /** | ||||
* Cleanup on destroy | * Cleanup on destroy | ||||
*/ | */ | ||||
Gate.prototype.OnDestroy = function() | Gate.prototype.OnDestroy = function() | ||||
{ | { | ||||
// Clean up range query | // Clean up range query | ||||
var cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager); | var cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager); | ||||
if (this.unitsQuery) | if (this.unitsQuery) | ||||
cmpRangeManager.DestroyActiveQuery(this.unitsQuery); | cmpRangeManager.DestroyActiveQuery(this.unitsQuery); | ||||
// Cancel the closing-blocked timer if it's running. | // Cancel the closing-blocked timer if it's running. | ||||
if (this.timer) | if (this.timer) | ||||
temple: Seems like we might want this for all turrets, see:
https://wildfiregames.com/forum/index.php? | |||||
Not Done Inline ActionsThere is a ticket now: #5151 Imarok: There is a ticket now: #5151 | |||||
{ | { | ||||
var cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer); | var cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer); | ||||
cmpTimer.CancelTimer(this.timer); | cmpTimer.CancelTimer(this.timer); | ||||
this.timer = undefined; | this.timer = undefined; | ||||
} | } | ||||
}; | }; | ||||
/** | /** | ||||
Show All 23 Lines | |||||
*/ | */ | ||||
Gate.prototype.OnRangeUpdate = function(msg) | Gate.prototype.OnRangeUpdate = function(msg) | ||||
{ | { | ||||
if (msg.tag != this.unitsQuery) | if (msg.tag != this.unitsQuery) | ||||
return; | return; | ||||
if (msg.added.length > 0) | if (msg.added.length > 0) | ||||
for (let entity of msg.added) | for (let entity of msg.added) | ||||
{ | |||||
// Ignore entities that cannot move as those won't be able to go through the gate. | |||||
let unitAI = Engine.QueryInterface(entity, IID_UnitAI); | |||||
if (!unitAI.AbleToMove()) | |||||
this.ignoreList.push(entity); | |||||
this.allies.push(entity); | this.allies.push(entity); | ||||
} | |||||
if (msg.removed.length > 0) | if (msg.removed.length > 0) | ||||
for (let entity of msg.removed) | for (let entity of msg.removed) | ||||
{ | |||||
let index = this.ignoreList.indexOf(entity); | |||||
if (index !== -1) | |||||
this.ignoreList.splice(index, 1); | |||||
this.allies.splice(this.allies.indexOf(entity), 1); | this.allies.splice(this.allies.indexOf(entity), 1); | ||||
} | |||||
this.OperateGate(); | |||||
}; | |||||
Gate.prototype.OnGlobalUnitAbleToMoveChanged = function(msg) | |||||
{ | |||||
if (this.allies.indexOf(msg.entity) === -1) | |||||
return; | |||||
let index = this.ignoreList.indexOf(msg.entity); | |||||
if (msg.ableToMove && index !== -1) | |||||
this.ignoreList.splice(index, 1); | |||||
else if (!msg.ableToMove && index === -1) | |||||
this.ignoreList.push(msg.entity); | |||||
this.OperateGate(); | this.OperateGate(); | ||||
}; | }; | ||||
/** | /** | ||||
* Get the range in which units are detected | * Get the range in which units are detected | ||||
*/ | */ | ||||
Gate.prototype.GetPassRange = function() | Gate.prototype.GetPassRange = function() | ||||
{ | { | ||||
return +this.template.PassRange; | return +this.template.PassRange; | ||||
}; | }; | ||||
Gate.prototype.ShouldOpen = function() | |||||
{ | |||||
return this.allies.some(ent => this.ignoreList.indexOf(ent) === -1); | |||||
}; | |||||
Not Done Inline Actions==? Freagarach: `==`? | |||||
Not Done Inline Actionsprobably return this.allies.some(ent => this.ignoreList.indexOf(ent) === -1); would be nicer. Stan: probably return this.allies.some(ent => this.ignoreList.indexOf(ent) === -1); would be nicer. | |||||
Done Inline ActionsI don't really care for our "no ===" convention. It's faster. wraitii: I don't really care for our "no ===" convention. It's faster.
I switched to a some indeed. | |||||
/** | /** | ||||
* Attempt to open or close the gate. | * Attempt to open or close the gate. | ||||
* An ally must be in range to open the gate, but an unlocked gate will only close | * An ally must be in range to open the gate, but an unlocked gate will only close | ||||
* if there are no allies in range and no units are inside the gate's obstruction. | * if there are no allies in range and no units are inside the gate's obstruction. | ||||
*/ | */ | ||||
Gate.prototype.OperateGate = function() | Gate.prototype.OperateGate = function() | ||||
{ | { | ||||
// Cancel the closing-blocked timer if it's running. | // Cancel the closing-blocked timer if it's running. | ||||
if (this.timer) | if (this.timer) | ||||
{ | { | ||||
var cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer); | var cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer); | ||||
cmpTimer.CancelTimer(this.timer); | cmpTimer.CancelTimer(this.timer); | ||||
this.timer = undefined; | this.timer = undefined; | ||||
} | } | ||||
if (this.opened && (this.locked || !this.ShouldOpen())) | |||||
Not Done Inline ActionsThis seems unrelated? wraitii: This seems unrelated? | |||||
Not Done Inline ActionsAh right no I understand now. wraitii: Ah right no I understand now. | |||||
if (this.opened && (this.allies.length == 0 || this.locked)) | |||||
this.CloseGate(); | this.CloseGate(); | ||||
else if (!this.opened && this.allies.length) | else if (!this.opened && this.ShouldOpen()) | ||||
this.OpenGate(); | this.OpenGate(); | ||||
}; | }; | ||||
Gate.prototype.IsLocked = function() | Gate.prototype.IsLocked = function() | ||||
{ | { | ||||
return this.locked; | return this.locked; | ||||
}; | }; | ||||
▲ Show 20 Lines • Show All 73 Lines • ▼ Show 20 Lines | |||||
/** | /** | ||||
* Close the gate, with sound and animation. | * Close the gate, with sound and animation. | ||||
* | * | ||||
* The gate may fail to close due to unit obstruction. If this occurs, the | * The gate may fail to close due to unit obstruction. If this occurs, the | ||||
* gate will start a timer and attempt to close on each simulation update. | * gate will start a timer and attempt to close on each simulation update. | ||||
*/ | */ | ||||
Gate.prototype.CloseGate = function() | Gate.prototype.CloseGate = function() | ||||
{ | { | ||||
var cmpObstruction = Engine.QueryInterface(this.entity, IID_Obstruction); | let cmpObstruction = Engine.QueryInterface(this.entity, IID_Obstruction); | ||||
if (!cmpObstruction) | if (!cmpObstruction) | ||||
return; | return; | ||||
// The gate can't be closed if there are entities colliding with it. | // The gate can't be closed if there are entities colliding with it. | ||||
var collisions = cmpObstruction.GetEntitiesBlockingConstruction(); | let collisions = cmpObstruction.GetEntitiesBlockingMovement(); | ||||
if (collisions.length) | if (collisions.length) | ||||
{ | { | ||||
if (!this.timer) | if (!this.timer) | ||||
{ | { | ||||
// Set an "instant" timer which will run on the next simulation turn. | // Set an "instant" timer which will run on the next simulation turn. | ||||
var cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer); | let cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer); | ||||
Done Inline Actionslet Freagarach: `let` | |||||
this.timer = cmpTimer.SetTimeout(this.entity, IID_Gate, "OperateGate", 0, {}); | this.timer = cmpTimer.SetTimeout(this.entity, IID_Gate, "OperateGate", 0); | ||||
Done Inline Actions(Object not needed.) Freagarach: (Object not needed.) | |||||
} | } | ||||
return; | return; | ||||
} | } | ||||
// If we ordered the gate to be locked, enable 'block movement' and 'block pathfinding' | // If we ordered the gate to be locked, enable 'block movement' and 'block pathfinding' | ||||
if (this.locked) | if (this.locked) | ||||
cmpObstruction.SetDisableBlockMovementPathfinding(false, false, 0); | cmpObstruction.SetDisableBlockMovementPathfinding(false, false, 0); | ||||
// Else just enable 'block movement' | // Else just enable 'block movement' | ||||
else | else | ||||
cmpObstruction.SetDisableBlockMovementPathfinding(false, true, 0); | cmpObstruction.SetDisableBlockMovementPathfinding(false, true, 0); | ||||
this.opened = false; | this.opened = false; | ||||
PlaySound("gate_closing", this.entity); | PlaySound("gate_closing", this.entity); | ||||
var cmpVisual = Engine.QueryInterface(this.entity, IID_Visual); | let cmpVisual = Engine.QueryInterface(this.entity, IID_Visual); | ||||
if (cmpVisual) | if (cmpVisual) | ||||
cmpVisual.SelectAnimation("gate_closing", true, 1.0); | cmpVisual.SelectAnimation("gate_closing", true, 1.0); | ||||
}; | }; | ||||
Engine.RegisterComponentType(IID_Gate, "Gate", Gate); | Engine.RegisterComponentType(IID_Gate, "Gate", Gate); |
Wildfire Games · Phabricator
Seems like we might want this for all turrets, see:
https://wildfiregames.com/forum/index.php?/topic/22638-hyrule-conquest/&do=findComment&comment=352793