Changeset View
Standalone View
binaries/data/mods/public/simulation/components/StatusEffectsReceiver.js
function StatusEffectsReceiver() {} | function StatusEffectsReceiver() {} | ||||
/** | |||||
Freagarach: Some GlobalScript perhaps? | |||||
Done Inline ActionsTemplates.js ? Stan: Templates.js ? | |||||
Done Inline ActionsThis is intrasically tied to the schema we use to specify modifiers in JSON and in XML, which are sadly already different. iirc only simulation code uses the tech/aura equivalent of this, so I would put it in a helper next to the schema definition. wraitii: This is intrasically tied to the schema we use to specify modifiers in JSON and in XML, which… | |||||
* Initialises the status effects. | |||||
*/ | |||||
StatusEffectsReceiver.prototype.Init = function() | StatusEffectsReceiver.prototype.Init = function() | ||||
{ | { | ||||
this.activeStatusEffects = {}; | this.activeStatusEffects = {}; | ||||
}; | }; | ||||
/** | |||||
Done Inline ActionsString to bool conversion ? Stan: String to bool conversion ? | |||||
Done Inline ActionsWhat do you mean here exactly? Freagarach: What do you mean here exactly? | |||||
* Which status effects are active on this entity. | |||||
Done Inline Actions\n Freagarach: `\n`
Further down the file as well. | |||||
* | |||||
Done Inline ActionsTernary ? Stan: Ternary ? | |||||
Done Inline ActionsI think yes here. wraitii: I think yes here. | |||||
Done Inline ActionsShould we default to ["Unit", "Structure"]? Freagarach: Should we default to `["Unit", "Structure"]`? | |||||
* @return {Object} - An object containing the status effects which currently affect the entity. | |||||
*/ | |||||
StatusEffectsReceiver.prototype.GetActiveStatuses = function() | StatusEffectsReceiver.prototype.GetActiveStatuses = function() | ||||
{ | { | ||||
return this.activeStatusEffects; | return this.activeStatusEffects; | ||||
}; | }; | ||||
// Called by attacking effects. | /** | ||||
* Called by Attacking effects. Adds status effects for each entry in the effectData. | |||||
* | |||||
* @param {Object} effectData - An object containing the status effects to give to the entity. | |||||
* @param {number} attacker - The entity ID of the attacker. | |||||
* @param {number} attackerOwner - The player ID of the attacker. | |||||
* @param {number} bonusMultiplier - A value to multiply the damage with (not implemented yet for SE). | |||||
* | |||||
* @return {Object} - The names of the status effects which were processed. | |||||
*/ | |||||
StatusEffectsReceiver.prototype.GiveStatus = function(effectData, attacker, attackerOwner, bonusMultiplier) | StatusEffectsReceiver.prototype.GiveStatus = function(effectData, attacker, attackerOwner, bonusMultiplier) | ||||
{ | { | ||||
for (let effect in effectData) | for (let effect in effectData) | ||||
this.AddStatus(effect, effectData[effect]); | this.AddStatus(effect, effectData[effect]); | ||||
Done Inline ActionsShould be a variable defined earlier to prevent unnecessary object creation. Freagarach: Should be a variable defined earlier to prevent unnecessary object creation. | |||||
// TODO: implement loot / resistance. | // TODO: implement loot / resistance. | ||||
return { "inflictedStatuses": Object.keys(effectData) }; | return { "inflictedStatuses": Object.keys(effectData) }; | ||||
}; | }; | ||||
/** | |||||
* Adds a status effect to the entity. | |||||
* | |||||
* @param {string} statusName - The name of the status effect. | |||||
* @param {object} data - The various effects and timings. | |||||
*/ | |||||
StatusEffectsReceiver.prototype.AddStatus = function(statusName, data) | StatusEffectsReceiver.prototype.AddStatus = function(statusName, data) | ||||
{ | { | ||||
if (this.activeStatusEffects[statusName]) | if (this.activeStatusEffects[statusName]) | ||||
{ | |||||
// TODO: implement different behaviour when receiving the same status multiple times. | |||||
// For now, these are ignored. | |||||
return; | return; | ||||
} | |||||
Done Inline ActionsThis should go in a separate patch.
But this is more complex to do correctly and should come later. wraitii: This should go in a separate patch.
I see 4 ways to handle being hit with the same status… | |||||
this.activeStatusEffects[statusName] = {}; | this.activeStatusEffects[statusName] = {}; | ||||
let status = this.activeStatusEffects[statusName]; | let status = this.activeStatusEffects[statusName]; | ||||
Done Inline ActionsIs the arbitrary number 10 enough? I would say not. Freagarach: Is the arbitrary number 10 enough? I would say not. | |||||
Done Inline ActionsTBH I wouldn't handle stackability in this diff. There are tricky issues associated with it. Slow and steady wins the race. wraitii: TBH I wouldn't handle stackability in this diff. There are tricky issues associated with it. | |||||
Done Inline ActionsWhy 10 ? Stan: Why 10 ? | |||||
Object.assign(status, data); | Object.assign(status, data); | ||||
status.Interval = +data.Interval; | |||||
Done Inline ActionsPretty sure it's missing some spaces, I guess the linter will complain :D Stan: Pretty sure it's missing some spaces, I guess the linter will complain :D | |||||
Done Inline Actionslooks like long line, maybe you should format it and make multiple lines of it :) Silier: looks like long line, maybe you should format it and make multiple lines of it :) | |||||
Done Inline ActionsBoth correct, waiting for the discussion how to unify and properly pass things. Thanks for noticing :) Freagarach: Both correct, waiting for the discussion how to unify and properly pass things. Thanks for… | |||||
Done Inline ActionsMissing space. Stan: Missing space. | |||||
status.TimeElapsed = 0; | if (status.Modifiers) | ||||
status.FirstTime = true; | { | ||||
let modifications = DeriveModificationsFromXMLTemplate(status.Modifiers); | |||||
let cmpModifiersManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_ModifiersManager); | |||||
cmpModifiersManager.AddModifiers(statusName, modifications, this.entity); | |||||
} | |||||
Done Inline ActionsDon't we have a function to do that ? Stan: Don't we have a function to do that ? | |||||
// With neither an interval nor a duration, there is no point in starting a timer. | |||||
if (!status.Duration && !status.Interval) | |||||
return; | |||||
// We want an interval to update the GUI to show how much time of the status effect | |||||
// is left even if the status effect itself has no interval. | |||||
Done Inline ActionsWhat if 0 ? Stan: What if 0 ? | |||||
Done Inline Actionsinterval = 0 does not work for timer if (typeof repeattime != "number" || !(repeattime > 0)) error("Invalid repeattime to SetInterval of "+funcname); Silier: interval = 0 does not work for timer
```
if (typeof repeattime != "number" || !(repeattime >… | |||||
Done Inline ActionsAh yeah that famous warning :D Stan: Ah yeah that famous warning :D | |||||
if (!status.Interval) | |||||
status._interval = 1000; | |||||
Done Inline Actions(StatusEffectsReceiver.prototype.Interval = 1000) elexis: (StatusEffectsReceiver.prototype.Interval = 1000) | |||||
status._timeElapsed = 0; | |||||
status._firstTime = true; | |||||
let cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer); | let cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer); | ||||
status.Timer = cmpTimer.SetInterval(this.entity, IID_StatusEffectsReceiver, "ExecuteEffect", 0, +status.Interval, statusName); | status._timer = cmpTimer.SetInterval(this.entity, IID_StatusEffectsReceiver, "ExecuteEffect", 0, +(status.Interval || status._interval), statusName); | ||||
}; | }; | ||||
/** | |||||
Done Inline Actionsoversight :) Stan: oversight :) | |||||
* Removes a status effect from the entity. | |||||
* | |||||
* @param {string} statusName - The status effect to be removed. | |||||
*/ | |||||
StatusEffectsReceiver.prototype.RemoveStatus = function(statusName) | StatusEffectsReceiver.prototype.RemoveStatus = function(statusName) | ||||
{ | { | ||||
if (!this.activeStatusEffects[statusName]) | let statusEffect = this.activeStatusEffects[statusName]; | ||||
if (!statusEffect) | |||||
return; | return; | ||||
if (statusEffect.Modifiers) | |||||
{ | |||||
let cmpModifiersManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_ModifiersManager); | |||||
cmpModifiersManager.RemoveAllModifiers(statusName, this.entity); | |||||
} | |||||
if (statusEffect._timer) | |||||
{ | |||||
let cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer); | let cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer); | ||||
cmpTimer.CancelTimer(this.activeStatusEffects[statusName].Timer); | cmpTimer.CancelTimer(statusEffect._timer); | ||||
} | |||||
Done Inline ActionsI realise I did the capitalisation here, but I would downgrade this to lower-case as it doesn't come from the template. In fact, I might write it _timer to make the difference more explicit. Same for 'timeelapsed' and 'firstTime' wraitii: I realise I did the capitalisation here, but I would downgrade this to lower-case as it doesn't… | |||||
delete this.activeStatusEffects[statusName]; | delete this.activeStatusEffects[statusName]; | ||||
}; | }; | ||||
/** | |||||
* Called by the timers. Executes a status effect. | |||||
* | |||||
* @param {string} statusName - The name of the status effect to be executed. | |||||
* @param {number} lateness - The delay between the calling of the function and the actual execution (turn time?). | |||||
*/ | |||||
StatusEffectsReceiver.prototype.ExecuteEffect = function(statusName, lateness) | StatusEffectsReceiver.prototype.ExecuteEffect = function(statusName, lateness) | ||||
{ | { | ||||
let status = this.activeStatusEffects[statusName]; | let status = this.activeStatusEffects[statusName]; | ||||
if (!status) | if (!status) | ||||
return; | return; | ||||
if (status.FirstTime) | if (status.Damage || status.Capture) | ||||
Attacking.HandleAttackEffects(statusName, status, this.entity, INVALID_ENTITY, INVALID_PLAYER); | |||||
if (!status.Duration) | |||||
return; | |||||
if (status._firstTime) | |||||
{ | { | ||||
status.FirstTime = false; | status._firstTime = false; | ||||
status.TimeElapsed += lateness; | status._timeElapsed += lateness; | ||||
} | } | ||||
else | else | ||||
status.TimeElapsed += status.Interval + lateness; | status._timeElapsed += +(status.Interval || status._interval) + lateness; | ||||
Attacking.HandleAttackEffects(statusName, status, this.entity, -1, -1); | |||||
Done Inline ActionsINVALID_ENTITY, INVALID_PLAYER Silier: INVALID_ENTITY, INVALID_PLAYER | |||||
if (status.Duration && status.TimeElapsed >= +status.Duration) | if (status._timeElapsed >= +status.Duration) | ||||
this.RemoveStatus(statusName); | this.RemoveStatus(statusName); | ||||
}; | }; | ||||
Engine.RegisterComponentType(IID_StatusEffectsReceiver, "StatusEffectsReceiver", StatusEffectsReceiver); | Engine.RegisterComponentType(IID_StatusEffectsReceiver, "StatusEffectsReceiver", StatusEffectsReceiver); |
Some GlobalScript perhaps?