Index: ps/trunk/binaries/data/mods/public/simulation/components/Promotion.js =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/components/Promotion.js +++ ps/trunk/binaries/data/mods/public/simulation/components/Promotion.js @@ -31,103 +31,18 @@ Promotion.prototype.Promote = function(promotedTemplateName) { // If the unit is dead, don't promote it - var cmpCurrentUnitHealth = Engine.QueryInterface(this.entity, IID_Health); - if (cmpCurrentUnitHealth.GetHitpoints() == 0) + let cmpHealth = Engine.QueryInterface(this.entity, IID_Health); + if (cmpHealth && cmpHealth.GetHitpoints() == 0) return; - // Create promoted unit entity - var promotedUnitEntity = Engine.AddEntity(promotedTemplateName); + // Save the entity id. + this.promotedUnitEntity = ChangeEntityTemplate(this.entity, promotedTemplateName); - // Copy parameters from current entity to promoted one - var cmpCurrentUnitPosition = Engine.QueryInterface(this.entity, IID_Position); - var cmpPromotedUnitPosition = Engine.QueryInterface(promotedUnitEntity, IID_Position); - if (cmpCurrentUnitPosition.IsInWorld()) - { - var pos = cmpCurrentUnitPosition.GetPosition2D(); - cmpPromotedUnitPosition.JumpTo(pos.x, pos.y); - } - var rot = cmpCurrentUnitPosition.GetRotation(); - cmpPromotedUnitPosition.SetYRotation(rot.y); - cmpPromotedUnitPosition.SetXZRotation(rot.x, rot.z); - var heightOffset = cmpCurrentUnitPosition.GetHeightOffset(); - cmpPromotedUnitPosition.SetHeightOffset(heightOffset); - - var cmpCurrentUnitOwnership = Engine.QueryInterface(this.entity, IID_Ownership); - var cmpPromotedUnitOwnership = Engine.QueryInterface(promotedUnitEntity, IID_Ownership); - cmpPromotedUnitOwnership.SetOwner(cmpCurrentUnitOwnership.GetOwner()); - - // change promoted unit health to the same percent of hitpoints as unit had before promotion - var cmpPromotedUnitHealth = Engine.QueryInterface(promotedUnitEntity, IID_Health); - var healthFraction = Math.max(0, Math.min(1, cmpCurrentUnitHealth.GetHitpoints() / cmpCurrentUnitHealth.GetMaxHitpoints())); - var promotedUnitHitpoints = cmpPromotedUnitHealth.GetMaxHitpoints() * healthFraction; - cmpPromotedUnitHealth.SetHitpoints(promotedUnitHitpoints); - - var cmpPromotedUnitPromotion = Engine.QueryInterface(promotedUnitEntity, IID_Promotion); - if (cmpPromotedUnitPromotion) - cmpPromotedUnitPromotion.IncreaseXp(this.currentXp); - - var cmpCurrentUnitResourceGatherer = Engine.QueryInterface(this.entity, IID_ResourceGatherer); - var cmpPromotedUnitResourceGatherer = Engine.QueryInterface(promotedUnitEntity, IID_ResourceGatherer); - if (cmpCurrentUnitResourceGatherer && cmpPromotedUnitResourceGatherer) - { - var carriedResorces = cmpCurrentUnitResourceGatherer.GetCarryingStatus(); - cmpPromotedUnitResourceGatherer.GiveResources(carriedResorces); - } - - var cmpCurrentUnitAI = Engine.QueryInterface(this.entity, IID_UnitAI); - var cmpPromotedUnitAI = Engine.QueryInterface(promotedUnitEntity, IID_UnitAI); - var heldPos = cmpCurrentUnitAI.GetHeldPosition(); - if (heldPos) - cmpPromotedUnitAI.SetHeldPosition(heldPos.x, heldPos.z); - if (cmpCurrentUnitAI.GetStanceName()) - cmpPromotedUnitAI.SwitchToStance(cmpCurrentUnitAI.GetStanceName()); - - var orders = cmpCurrentUnitAI.GetOrders(); - if (cmpCurrentUnitPosition.IsInWorld()) // do not cheer if not visibly garrisoned - cmpPromotedUnitAI.Cheer(); - if (cmpCurrentUnitAI.IsGarrisoned()) - cmpPromotedUnitAI.SetGarrisoned(); - cmpPromotedUnitAI.AddOrders(orders); - - var workOrders = cmpCurrentUnitAI.GetWorkOrders(); - cmpPromotedUnitAI.SetWorkOrders(workOrders); - - if (cmpCurrentUnitAI.IsGuardOf()) - { - let guarded = cmpCurrentUnitAI.IsGuardOf(); - let cmpGuard = Engine.QueryInterface(guarded, IID_Guard); - if (cmpGuard) - { - cmpGuard.RenameGuard(this.entity, promotedUnitEntity); - cmpPromotedUnitAI.SetGuardOf(guarded); - } - } + let cmpPosition = Engine.QueryInterface(this.promotedUnitEntity, IID_Position); + let cmpUnitAI = Engine.QueryInterface(this.promotedUnitEntity, IID_UnitAI); - let cmpCurrentUnitGuard = Engine.QueryInterface(this.entity, IID_Guard); - let cmpPromotedUnitGuard = Engine.QueryInterface(promotedUnitEntity, IID_Guard); - if (cmpCurrentUnitGuard && cmpPromotedUnitGuard) - { - let entities = cmpCurrentUnitGuard.GetEntities(); - if (entities.length) - { - cmpPromotedUnitGuard.SetEntities(entities); - for (let ent of entities) - { - let cmpUnitAI = Engine.QueryInterface(ent, IID_UnitAI); - if (cmpUnitAI) - cmpUnitAI.SetGuardOf(promotedUnitEntity); - } - } - } - - Engine.PostMessage(this.entity, MT_EntityRenamed, { "entity": this.entity, "newentity": promotedUnitEntity }); - - // Destroy current entity - if (cmpCurrentUnitPosition && cmpCurrentUnitPosition.IsInWorld()) - cmpCurrentUnitPosition.MoveOutOfWorld(); - Engine.DestroyEntity(this.entity); - // save the entity id - this.promotedUnitEntity = promotedUnitEntity; + if (cmpPosition && cmpPosition.IsInWorld() && cmpUnitAI) + cmpUnitAI.Cheer(); }; Promotion.prototype.IncreaseXp = function(amount) @@ -136,7 +51,7 @@ // transfer the gained xp to the promoted unit if applicable if (this.promotedUnitEntity) { - var cmpPromotion = Engine.QueryInterface(this.promotedUnitEntity, IID_Promotion); + let cmpPromotion = Engine.QueryInterface(this.promotedUnitEntity, IID_Promotion); if (cmpPromotion) cmpPromotion.IncreaseXp(amount); return; @@ -165,6 +80,9 @@ 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, {}); Index: ps/trunk/binaries/data/mods/public/simulation/components/tests/test_Pack.js =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/components/tests/test_Pack.js +++ ps/trunk/binaries/data/mods/public/simulation/components/tests/test_Pack.js @@ -10,6 +10,8 @@ Engine.LoadComponentScript("interfaces/Health.js"); Engine.LoadComponentScript("interfaces/Pack.js"); Engine.LoadComponentScript("interfaces/Player.js"); +Engine.LoadComponentScript("interfaces/Promotion.js"); +Engine.LoadComponentScript("interfaces/ResourceGatherer.js"); Engine.LoadComponentScript("interfaces/Timer.js"); Engine.LoadComponentScript("interfaces/UnitAI.js"); Engine.LoadComponentScript("Pack.js"); Index: ps/trunk/binaries/data/mods/public/simulation/components/tests/test_Promotion.js =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/components/tests/test_Promotion.js +++ ps/trunk/binaries/data/mods/public/simulation/components/tests/test_Promotion.js @@ -1,69 +1,66 @@ -Engine.LoadComponentScript("interfaces/Guard.js"); Engine.LoadComponentScript("interfaces/Health.js"); Engine.LoadComponentScript("interfaces/Promotion.js"); -Engine.LoadComponentScript("interfaces/ResourceGatherer.js"); Engine.LoadComponentScript("interfaces/UnitAI.js"); Engine.LoadComponentScript("Promotion.js"); -Engine.RegisterGlobal("MT_EntityRenamed", "entityRenamed"); -// Test Promote - -let cmpPromotion = ConstructComponent(60, "Promotion", { - "Entity": "infantry_melee_spearman_a", - "RequiredXP": 1000 -}); - -// Health, Position, Ownership, UnitAI are mandatory in the Promotion code -AddMock(60, IID_Health, { - "GetHitpoints": () => 102, - "GetMaxHitpoints": () => 102, -}); +(function testMultipleXPIncrease() +{ +let ApplyValueModificationsToEntity = (_, val) => val; +Engine.RegisterGlobal("ApplyValueModificationsToEntity", ApplyValueModificationsToEntity); +Engine.RegisterGlobal("ApplyValueModificationsToTemplate", ApplyValueModificationsToEntity); + +let QueryOwnerInterface = () => ({ "GetPlayerID": () => 2 }); +Engine.RegisterGlobal("QueryOwnerInterface", QueryOwnerInterface); + +const ENT_ID = 60; + +let entTemplates = { + "60": "template_b", + "61": "template_f", + "62": "end", +}; -AddMock(60, IID_Position, { - "GetPosition2D": () => new Vector2D(1, 0, 0), - "GetRotation": () => new Vector3D(3, 4, 5), - "GetHeightOffset": () => {}, - "IsInWorld": () => true, - "MoveOutOfWorld": () => {} -}); +let promote = { + "template_b": "template_c", + "template_c": "template_d", + "template_d": "template_e", + "template_e": "template_f", +}; -AddMock(60, IID_Ownership, { - "GetOwner": () => 1, +AddMock(SYSTEM_ENTITY, IID_TemplateManager, { + "GetTemplate": (t) => ({ + "Promotion": { + "Entity": promote[t], + "RequiredXp": 1000 + }, + }), }); -AddMock(60, IID_UnitAI, { - "GetHeldPosition": () => {}, - "GetStanceName": () => {}, - "GetOrders": () => {}, - "IsGarrisoned": () => {}, - "GetWorkOrders": () => {}, - "IsGuardOf": () => {}, +let cmpPromotion = ConstructComponent(ENT_ID, "Promotion", { + "Entity": "template_b", + "RequiredXp": 1000 }); -Engine.AddEntity = function(name) +let ChangeEntityTemplate = function(ent, template) { - if (name != "infantry_melee_spearman_a") - return undefined; - AddMock(61, IID_Health, { - "GetMaxHitpoints": () => 102 * 1.2, - "SetHitpoints": hp => TS_ASSERT_EQUALS(hp, 102 * 1.2) - }); - AddMock(61, IID_Position, { - "JumpTo": () => {}, - "SetYRotation": () => {}, - "SetXZRotation": () => {}, - "SetHeightOffset": () => {}, - "IsInWorld": () => true, - }); - AddMock(61, IID_Ownership, { - "SetOwner": id => TS_ASSERT_EQUALS(id, 1), - }); - AddMock(61, IID_UnitAI, { - "Cheer": () => {}, - "AddOrders": () => {}, - "SetWorkOrders": () => {}, + cmpPromotion = ConstructComponent(ent + 1, "Promotion", { + "Entity": entTemplates[ent + 1], + "RequiredXp": 1000 }); - return 61; + return ent + 1; }; +Engine.RegisterGlobal("ChangeEntityTemplate", ChangeEntityTemplate); -cmpPromotion.Promote("infantry_melee_spearman_a"); +TS_ASSERT_EQUALS(cmpPromotion.GetCurrentXp(), 0); +cmpPromotion.IncreaseXp(200); +TS_ASSERT_EQUALS(cmpPromotion.GetCurrentXp(), 200); +cmpPromotion.IncreaseXp(800); + +TS_ASSERT_EQUALS(cmpPromotion.entity, 61); +TS_ASSERT_EQUALS(cmpPromotion.GetCurrentXp(), 0); +TS_ASSERT_EQUALS(cmpPromotion.GetRequiredXp(), 1000); +cmpPromotion.IncreaseXp(4200); +TS_ASSERT_EQUALS(cmpPromotion.entity, 62); +TS_ASSERT_EQUALS(cmpPromotion.template.Entity, "end"); +TS_ASSERT_EQUALS(cmpPromotion.GetCurrentXp(), 200); +})(); Index: ps/trunk/binaries/data/mods/public/simulation/helpers/Transform.js =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/helpers/Transform.js +++ ps/trunk/binaries/data/mods/public/simulation/helpers/Transform.js @@ -75,6 +75,20 @@ } } + let cmpPromotion = Engine.QueryInterface(oldEnt, IID_Promotion); + let cmpNewPromotion = Engine.QueryInterface(newEnt, IID_Promotion); + if (cmpPromotion && cmpNewPromotion) + cmpNewPromotion.IncreaseXp(cmpPromotion.GetCurrentXp()); + + let cmpResGatherer = Engine.QueryInterface(oldEnt, IID_ResourceGatherer); + let cmpNewResGatherer = Engine.QueryInterface(newEnt, IID_ResourceGatherer); + if (cmpResGatherer && cmpNewResGatherer) + { + let carriedResources = cmpResGatherer.GetCarryingStatus(); + cmpNewResGatherer.GiveResources(carriedResources); + } + + // Maintain the list of guards let cmpGuard = Engine.QueryInterface(oldEnt, IID_Guard); let cmpNewGuard = Engine.QueryInterface(newEnt, IID_Guard);