Changeset View
Changeset View
Standalone View
Standalone View
binaries/data/mods/public/simulation/components/Promotion.js
function Promotion() {} | function Promotion() {} | ||||
const ModificationSchema = | |||||
"<zeroOrMore>" + | |||||
"<element>" + | |||||
"<anyName />" + | |||||
"<interleave>" + | |||||
"<optional>" + | |||||
"<element name='Affects'>" + | |||||
"<attribute name='datatype'>" + | |||||
"<value>tokens</value>" + | |||||
"</attribute>" + | |||||
"<text/>" + | |||||
"</element>" + | |||||
"</optional>" + | |||||
"<choice>" + | |||||
"<element name='Add'>" + | |||||
"<data type='decimal' />" + | |||||
"</element>" + | |||||
"<element name='Multiply'>" + | |||||
"<data type='decimal' />" + | |||||
"</element>" + | |||||
"<element name='Replace'>" + | |||||
"<text/>" + | |||||
"</element>" + | |||||
"</choice>" + | |||||
"</interleave>" + | |||||
"</element>" + | |||||
"</zeroOrMore>"; | |||||
const DeriveModificationsFromTemplate = function(template) | |||||
{ | |||||
let ret = {}; | |||||
if (template.Add) | |||||
ret.add = +template.Add; | |||||
if (template.Multiply) | |||||
ret.multiply = +template.Multiply; | |||||
if (template.Replace) | |||||
ret.replace = template.Replace; | |||||
if (template.Affects) | |||||
ret.affects = template.Affects._string.split(/\s/); | |||||
else | |||||
ret.affects = []; | |||||
return ret; | |||||
}; | |||||
Promotion.prototype.Schema = | Promotion.prototype.Schema = | ||||
"<choice>" + | |||||
"<interleave>" + | |||||
"<element name='Entity'>" + | "<element name='Entity'>" + | ||||
"<text/>" + | "<text/>" + | ||||
"</element>" + | "</element>" + | ||||
"<element name='RequiredXp'>" + | "<element name='RequiredXp'>" + | ||||
"<data type='positiveInteger'/>" + | "<data type='positiveInteger'/>" + | ||||
"</element>"; | "</element>" + | ||||
"</interleave>" + | |||||
"<oneOrMore>" + | |||||
"<element>" + | |||||
"<anyName />" + | |||||
"<attribute name='from'>" + | |||||
"<data type='nonNegativeInteger'/>" + | |||||
"</attribute>" + | |||||
"<optional>" + | |||||
"<attribute name='until'>" + | |||||
"<data type='positiveInteger'/>" + | |||||
"</attribute>" + | |||||
"</optional>" + | |||||
"<interleave>" + | |||||
"<element name='RequiredXp'>" + | |||||
"<data type='positiveInteger'/>" + | |||||
"</element>" + | |||||
"<element name='Modifiers'>" + | |||||
ModificationSchema + | |||||
"</element>" + | |||||
"</interleave>" + | |||||
"</element>" + | |||||
"</oneOrMore>" + | |||||
"</choice>"; | |||||
Promotion.prototype.Init = function() | Promotion.prototype.Init = function() | ||||
{ | { | ||||
this.currentXp = 0; | this.currentXp = 0; | ||||
this.level = 0; | |||||
}; | |||||
Promotion.prototype.IsEntity = function() | |||||
{ | |||||
return this.template.Entity !== undefined; | |||||
}; | |||||
Promotion.prototype._template = function() | |||||
{ | |||||
if (this.IsEntity()) | |||||
return this.template; | |||||
for (let level in this.template) | |||||
if (this.level >= this.template[level]["@from"] && | |||||
(!this.template[level]["@until"] || this.level < this.template[level]["@until"])) | |||||
return this.template[level]; | |||||
return undefined; | |||||
}; | }; | ||||
/** | |||||
* @returns the required XP to promote or undefined if the unit cannot promote (i.e. is at its maximum level) | |||||
*/ | |||||
Promotion.prototype.GetRequiredXp = function() | Promotion.prototype.GetRequiredXp = function() | ||||
{ | { | ||||
return ApplyValueModificationsToEntity("Promotion/RequiredXp", +this.template.RequiredXp, this.entity); | if (!this._template()) | ||||
return undefined; | |||||
return ApplyValueModificationsToEntity("Promotion/RequiredXp", +this._template().RequiredXp, this.entity); | |||||
}; | }; | ||||
Stan: array.find ? | |||||
Promotion.prototype.GetCurrentXp = function() | Promotion.prototype.GetCurrentXp = function() | ||||
{ | { | ||||
return this.currentXp; | return this.currentXp; | ||||
}; | }; | ||||
Promotion.prototype.GetPromotedTemplateName = function() | Promotion.prototype.GetPromotedTemplateName = function() | ||||
{ | { | ||||
return this.template.Entity; | return this.template.Entity; | ||||
}; | }; | ||||
Not Done Inline ActionsArray.find() ? Stan: Array.find() ? | |||||
Not Done Inline ActionsMaybe we should not call the function but use the members instead? Stan: Maybe we should not call the function but use the members instead? | |||||
Promotion.prototype.Promote = function(promotedTemplateName) | Promotion.prototype.GetCurrentLevel = function() | ||||
{ | |||||
return this.level; | |||||
}; | |||||
Promotion.prototype.Promote = function() | |||||
{ | { | ||||
// If the unit is dead, don't promote it | // If the unit is dead, don't promote it | ||||
let cmpHealth = Engine.QueryInterface(this.entity, IID_Health); | let cmpHealth = Engine.QueryInterface(this.entity, IID_Health); | ||||
if (cmpHealth && cmpHealth.GetHitpoints() == 0) | if (cmpHealth && cmpHealth.GetHitpoints() == 0) | ||||
return; | return; | ||||
if (this.IsEntity()) | |||||
{ | |||||
let cmpTemplateManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_TemplateManager); | |||||
let playerID = QueryOwnerInterface(this.entity, IID_Player).GetPlayerID(); | |||||
let promotedTemplateName = this.GetPromotedTemplateName(); | |||||
this.currentXp -= this.GetRequiredXp(); | |||||
// Check if we can upgrade a second time (or even more). | |||||
while (true) | |||||
{ | |||||
let template = cmpTemplateManager.GetTemplate(promotedTemplateName); | |||||
if (!template.Promotion || !template.Promotion.Entity) | |||||
break; | |||||
let requiredXp = ApplyValueModificationsToTemplate("Promotion/RequiredXp", +template.Promotion.RequiredXp, playerID, template); | |||||
// compare the current xp to the required xp of the promoted entity | |||||
StanUnsubmitted Not Done Inline ActionsCapital. Stan: Capital. | |||||
if (this.currentXp < requiredXp) | |||||
break; | |||||
this.currentXp -= requiredXp; | |||||
promotedTemplateName = template.Promotion.Entity; | |||||
} | |||||
// save the entity id | // save the entity id | ||||
this.promotedUnitEntity = ChangeEntityTemplate(this.entity, promotedTemplateName); | this.promotedUnitEntity = ChangeEntityTemplate(this.entity, promotedTemplateName); | ||||
let cmpPromotion = Engine.QueryInterface(this.promotedUnitEntity, IID_Promotion); | |||||
if (cmpPromotion && this.currentXp > 0 && this.promotedUnitEntity != this.entity) | |||||
cmpPromotion.IncreaseXp(this.currentXp); | |||||
} | |||||
else | |||||
{ | |||||
// False if GetRequiredXp returns undefined. | |||||
let cmpModificationsManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_ModificationsManager); | |||||
while (this.currentXp >= this.GetRequiredXp()) | |||||
{ | |||||
this.currentXp -= this.GetRequiredXp(); | |||||
for (let propName in this._template().Modifiers) | |||||
// TODO: use stackability | |||||
cmpModificationsManager.AddModif(propName.replace("-", "/"), "level_" + (this.level + 1), DeriveModificationsFromTemplate(this._template().Modifiers[propName]), this.entity); | |||||
this.level++; | |||||
} | |||||
this.promotedUnitEntity = this.entity; | |||||
} | |||||
let cmpPosition = Engine.QueryInterface(this.promotedUnitEntity, IID_Position); | let cmpPosition = Engine.QueryInterface(this.promotedUnitEntity, IID_Position); | ||||
let cmpUnitAI = Engine.QueryInterface(this.promotedUnitEntity, IID_UnitAI); | let cmpUnitAI = Engine.QueryInterface(this.promotedUnitEntity, IID_UnitAI); | ||||
if (cmpPosition && cmpPosition.IsInWorld() && cmpUnitAI) | if (cmpPosition && cmpPosition.IsInWorld() && cmpUnitAI) | ||||
cmpUnitAI.Cheer(); | cmpUnitAI.Cheer(); | ||||
if (this.promotedUnitEntity == this.entity) | |||||
this.promotedUnitEntity = null; | |||||
StanUnsubmitted Not Done Inline Actionsdelete ? Stan: delete ? | |||||
}; | }; | ||||
Promotion.prototype.IncreaseXp = function(amount) | Promotion.prototype.IncreaseXp = function(amount) | ||||
{ | { | ||||
Not Done Inline Actionscheck for cmpPlayer? Stan: check for cmpPlayer? | |||||
// if the unit was already promoted, but is waiting for the engine to be destroyed | // if the unit was already promoted, but is waiting for the engine to be destroyed | ||||
// transfer the gained xp to the promoted unit if applicable | // transfer the gained xp to the promoted unit if applicable | ||||
if (this.promotedUnitEntity) | if (this.promotedUnitEntity) | ||||
{ | { | ||||
let cmpPromotion = Engine.QueryInterface(this.promotedUnitEntity, IID_Promotion); | let cmpPromotion = Engine.QueryInterface(this.promotedUnitEntity, IID_Promotion); | ||||
if (cmpPromotion) | if (cmpPromotion) | ||||
cmpPromotion.IncreaseXp(amount); | cmpPromotion.IncreaseXp(amount); | ||||
return; | return; | ||||
} | } | ||||
// Cannot upgrade. | |||||
if (!this.GetRequiredXp()) | |||||
SilierUnsubmitted Not Done Inline Actions!! cheat promote unit is replacing requiredXp with 0, so this is breaking cheats Silier: !! cheat promote unit is replacing requiredXp with 0, so this is breaking cheats | |||||
return; | |||||
FreagarachUnsubmitted Not Done Inline ActionsWhen there is no requiredXP, it does not necesarrily mean XP is not to be added? Freagarach: When there is no requiredXP, it does not necesarrily mean XP is not to be added?
There may be… | |||||
this.currentXp += +(amount); | this.currentXp += +(amount); | ||||
var requiredXp = this.GetRequiredXp(); | |||||
if (this.currentXp >= requiredXp) | if (this.currentXp >= this.GetRequiredXp()) | ||||
{ | this.Promote(); | ||||
var cmpTemplateManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_TemplateManager); | |||||
var playerID = QueryOwnerInterface(this.entity, IID_Player).GetPlayerID(); | |||||
this.currentXp -= requiredXp; | |||||
var promotedTemplateName = this.GetPromotedTemplateName(); | |||||
// check if we can upgrade a second time (or even more) | |||||
while (true) | |||||
{ | |||||
var template = cmpTemplateManager.GetTemplate(promotedTemplateName); | |||||
if (!template.Promotion) | |||||
break; | |||||
requiredXp = ApplyValueModificationsToTemplate("Promotion/RequiredXp", +template.Promotion.RequiredXp, playerID, template); | |||||
// compare the current xp to the required xp of the promoted entity | |||||
if (this.currentXp < requiredXp) | |||||
break; | |||||
this.currentXp -= requiredXp; | |||||
promotedTemplateName = template.Promotion.Entity; | |||||
} | |||||
this.Promote(promotedTemplateName); | |||||
let cmpPromotion = Engine.QueryInterface(this.promotedUnitEntity, IID_Promotion); | |||||
if (cmpPromotion) | |||||
cmpPromotion.IncreaseXp(this.currentXp); | |||||
} | |||||
Engine.PostMessage(this.entity, MT_ExperienceChanged, {}); | Engine.PostMessage(this.entity, MT_ExperienceChanged, {}); | ||||
}; | }; | ||||
Promotion.prototype.OnValueModification = function(msg) | Promotion.prototype.OnValueModification = function(msg) | ||||
{ | { | ||||
if (msg.component == "Promotion") | if (msg.component == "Promotion") | ||||
this.IncreaseXp(0); | this.IncreaseXp(0); | ||||
}; | }; | ||||
Engine.RegisterComponentType(IID_Promotion, "Promotion", Promotion); | Engine.RegisterComponentType(IID_Promotion, "Promotion", Promotion); |
Wildfire Games · Phabricator
array.find ?