Index: binaries/data/mods/public/simulation/components/Builder.js =================================================================== --- binaries/data/mods/public/simulation/components/Builder.js +++ binaries/data/mods/public/simulation/components/Builder.js @@ -95,6 +95,17 @@ if (!this.CanRepair(target)) return false; + // check if it's a rebuildable foundation and can be payed for (and do so). + const cmpFoundation = Engine.QueryInterface(target, IID_Foundation); + if (cmpFoundation && cmpFoundation.IsRebuildable() && !cmpFoundation.IsRebuildPayed()) + { + const cmpPlayer = QueryOwnerInterface(target, IID_Player); + if (cmpPlayer.TrySubtractResources(cmpFoundation.GetRebuildCost())) + cmpFoundation.SetRebuildPayed(); + else + return false; + } + let cmpBuilderList = QueryBuilderListInterface(target); if (cmpBuilderList) cmpBuilderList.AddBuilder(this.entity); Index: binaries/data/mods/public/simulation/components/Foundation.js =================================================================== --- binaries/data/mods/public/simulation/components/Foundation.js +++ binaries/data/mods/public/simulation/components/Foundation.js @@ -21,6 +21,8 @@ this.buildTimeModifier = +this.template.BuildTimeModifier; this.previewEntity = INVALID_ENTITY; + + this.rebuildFoundation; }; Foundation.prototype.Serialize = function() @@ -59,6 +61,59 @@ }; /** + * This mainly concerns engine spawned entities, because they aren't payed for. + * @param {number} ent - Use an alive entity to grab some info from it. + * @returns + */ +Foundation.prototype.SetRebuildableFromEnt = function(ent) +{ + const cmpTemplateManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_TemplateManager); + const cmpCost = Engine.QueryInterface(ent, IID_Cost); + if (!cmpCost) + { + warn('invalid entity, has no cmpCost'); + return; + } + + this.rebuildFoundation = + { + "Rebuildable": true, + "Template": cmpTemplateManager.GetCurrentTemplateName(ent), + "Cost": cmpCost.GetResourceCosts(), + "Payed": false + }; +}; + +Foundation.prototype.IsRebuildable = function() +{ + if (this.rebuildFoundation) + return this.rebuildFoundation.Rebuildable; + + return false; +}; + +Foundation.prototype.GetRebuildCost = function() +{ + return this.rebuildFoundation.Cost; +}; + +Foundation.prototype.GetRebuildTemplate = function() +{ + return this.rebuildFoundation.Template; +}; + +Foundation.prototype.SetRebuildPayed = function() +{ + this.rebuildFoundation.Payed = true; + this.InitialiseConstruction(this.GetRebuildTemplate()); // only initialise if we payed, otherwise we are getting free resources if we destroy it. +}; + +Foundation.prototype.IsRebuildPayed = function() +{ + return this.rebuildFoundation.Payed; +}; + +/** * Moving the revelation logic from Build to here makes the building sink if * it is attacked. */ Index: binaries/data/mods/public/simulation/components/Health.js =================================================================== --- binaries/data/mods/public/simulation/components/Health.js +++ binaries/data/mods/public/simulation/components/Health.js @@ -284,8 +284,12 @@ PlaySound("death", this.entity); if (this.template.SpawnEntityOnDeath) - this.CreateDeathSpawnedEntity(); + this.CreateEntitiesOnLocation([this.template.SpawnEntityOnDeath]); + const cmpRepairable = Engine.QueryInterface(this.entity, IID_Repairable); + if (cmpRepairable && cmpRepairable.template.Rebuildable === 'true') + this.CreateEntitiesOnLocation(["foundation|" + Engine.QueryInterface(SYSTEM_ENTITY, IID_TemplateManager).GetCurrentTemplateName(this.entity)]); + switch (this.template.DeathType) { case "corpse": @@ -401,7 +405,12 @@ }); }; -Health.prototype.CreateDeathSpawnedEntity = function() +/** + * Create entities on the position and at the rotation of this.entity. + * @param {array} templates - The templates to spawn + * @returns {array} spawnedEntities - Containing the array of the created entity id's. + */ +Health.prototype.CreateEntitiesOnLocation = function(templates) { // If the unit died while not in the world, don't spawn a death entity for it // since there's nowhere for it to be placed @@ -409,23 +418,39 @@ if (!cmpPosition.IsInWorld()) return INVALID_ENTITY; - // Create SpawnEntityOnDeath entity - let spawnedEntity = Engine.AddLocalEntity(this.template.SpawnEntityOnDeath); + const spawnedEntities = []; + for (const template of templates) + { + const spawnedEntity = template.includes('decay') ? Engine.AddLocalEntity(template) : Engine.AddEntity(template); - // Move to same position - let cmpSpawnedPosition = Engine.QueryInterface(spawnedEntity, IID_Position); - let pos = cmpPosition.GetPosition(); - cmpSpawnedPosition.JumpTo(pos.x, pos.z); - let rot = cmpPosition.GetRotation(); - cmpSpawnedPosition.SetYRotation(rot.y); - cmpSpawnedPosition.SetXZRotation(rot.x, rot.z); + /** + * Initialize some info of the rebuildable foundation. + * Engine spawned foundations aren't payed for, this handles that. + */ + if (template.includes('foundation')) + { + const cmpFoundation = Engine.QueryInterface(spawnedEntity, IID_Foundation); + cmpFoundation.SetRebuildableFromEnt(this.entity); // use the still alive entity to fill in some information to be able to rebuild it. + } - let cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership); - let cmpSpawnedOwnership = Engine.QueryInterface(spawnedEntity, IID_Ownership); - if (cmpOwnership && cmpSpawnedOwnership) - cmpSpawnedOwnership.SetOwner(cmpOwnership.GetOwner()); + // Move to same position + let cmpSpawnedPosition = Engine.QueryInterface(spawnedEntity, IID_Position); + let pos = cmpPosition.GetPosition(); + cmpSpawnedPosition.JumpTo(pos.x, pos.z); + let rot = cmpPosition.GetRotation(); + cmpSpawnedPosition.SetYRotation(rot.y); + cmpSpawnedPosition.SetXZRotation(rot.x, rot.z); - return spawnedEntity; + let cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership); + let cmpSpawnedOwnership = Engine.QueryInterface(spawnedEntity, IID_Ownership); + if (cmpOwnership && cmpSpawnedOwnership) + cmpSpawnedOwnership.SetOwner(cmpOwnership.GetOwner()); + + spawnedEntities.push(spawnedEntity); + } + + return spawnedEntities; + }; Health.prototype.UpdateActor = function() Index: binaries/data/mods/public/simulation/components/Repairable.js =================================================================== --- binaries/data/mods/public/simulation/components/Repairable.js +++ binaries/data/mods/public/simulation/components/Repairable.js @@ -4,10 +4,16 @@ "Deals with repairable structures and units." + "" + "2.0" + + "true" + "" + "" + "" + - ""; + "" + + "" + + "" + + "" + + "" + + ""; Repairable.prototype.Init = function() { Index: binaries/data/mods/public/simulation/components/tests/test_Health.js =================================================================== --- binaries/data/mods/public/simulation/components/tests/test_Health.js +++ binaries/data/mods/public/simulation/components/tests/test_Health.js @@ -9,6 +9,8 @@ Engine.LoadComponentScript("interfaces/Health.js"); Engine.LoadComponentScript("Health.js"); +Engine.LoadComponentScript("interfaces/Repairable.js"); + const entity_id = 5; const corpse_id = entity_id + 1; Index: binaries/data/mods/public/simulation/templates/template_structure.xml =================================================================== --- binaries/data/mods/public/simulation/templates/template_structure.xml +++ binaries/data/mods/public/simulation/templates/template_structure.xml @@ -92,6 +92,7 @@ 2.0 + true