Index: binaries/data/mods/public/maps/scenario.rnc =================================================================== --- binaries/data/mods/public/maps/scenario.rnc +++ binaries/data/mods/public/maps/scenario.rnc @@ -108,6 +108,12 @@ attribute uid { xsd:positiveInteger } & } & } & + element Turrets { + element Turret { + attribute turret { text } & + attribute uid { xsd:positiveInteger } & + } & + } & element Actor { attribute seed { xsd:integer } }? Index: binaries/data/mods/public/maps/scenario.rng =================================================================== --- binaries/data/mods/public/maps/scenario.rng +++ binaries/data/mods/public/maps/scenario.rng @@ -268,6 +268,20 @@ + + + + + + + + + + + + + + Index: binaries/data/mods/public/simulation/components/TurretHolder.js =================================================================== --- binaries/data/mods/public/simulation/components/TurretHolder.js +++ binaries/data/mods/public/simulation/components/TurretHolder.js @@ -189,6 +189,36 @@ } /** + * @return {map[String, number]} - The currently occupied turret points with their entities. + */ + GetTurrets() + { + let turrets = new Map(); + for (let turretPoint in this.turretPoints) + if (turretPoint.entity) + turrets.set(turretPoint, turretPoint.entity); + + return turrets; + } + + /** + * Sets an init turret, present from game start. (E.g. set in Atlas.) + * @param {String} turret - The turret point to be used. + * @param {number} entity - The entity-ID to be placed. + */ + SetInitEntity(turret, entity) + { + if (!this.initTurrets) + this.initTurrets = new Map(); + + if (this.initTurrets.has(turret)) + error("The turret position " + turret + " of entity " + + this.entity + " is already set! Overwriting."); + + this.initTurrets.set(turret, entity); + } + + /** * We process EntityRenamed here because we need to be sure that we receive * it after it is processed by GarrisonHolder.js. * ToDo: Make this not needed by fully separating TurretHolder from GarrisonHolder. @@ -221,6 +251,22 @@ for (let entity of msg.added) this.OccupyTurret(entity); } + + /** + * Initialise the turreted units. + */ + OnGlobalInitGame(msg) + { + if (!this.initTurrets) + return; + + for (let [turretPoint, entity] of this.initTurrets) + if (!this.OccupyTurret(entity, this.turretPoints[turretPoint])) + error("Entity " + entity + " could not occupy the turret point " + + turretPoint + " of turret holder " + this.entity + "."); + + delete this.initGarrison; + } } TurretHolder.prototype.Schema = Index: binaries/data/mods/public/simulation/components/interfaces/TurretHolder.js =================================================================== --- binaries/data/mods/public/simulation/components/interfaces/TurretHolder.js +++ binaries/data/mods/public/simulation/components/interfaces/TurretHolder.js @@ -1,5 +1,3 @@ -Engine.RegisterInterface("TurretHolder"); - /** * Message of the form { "added": number[], "removed": number[] } * sent from the TurretHolder component to the current entity whenever the turrets change. Index: source/graphics/MapReader.cpp =================================================================== --- source/graphics/MapReader.cpp +++ source/graphics/MapReader.cpp @@ -48,6 +48,7 @@ #include "simulation2/components/ICmpPlayerManager.h" #include "simulation2/components/ICmpPosition.h" #include "simulation2/components/ICmpTerrain.h" +#include "simulation2/components/ICmpTurretHolder.h" #include "simulation2/components/ICmpVisual.h" #include "simulation2/components/ICmpWaterManager.h" @@ -418,12 +419,14 @@ int el_template, el_player; int el_position, el_orientation, el_obstruction; int el_garrison; + int el_turrets; int el_actor; int at_x, at_y, at_z; int at_group, at_group2; int at_angle; int at_uid; int at_seed; + int at_turret; XMBElementList nodes; // children of root @@ -468,6 +471,7 @@ EL(player); EL(position); EL(garrison); + EL(turrets); EL(orientation); EL(obstruction); EL(actor); @@ -476,6 +480,7 @@ AT(angle); AT(uid); AT(seed); + AT(turret); #undef AT #undef EL @@ -950,6 +955,7 @@ CStrW TemplateName; int PlayerID = 0; std::vector Garrison; + std::vector > Turrets; CFixedVector3D Position; CFixedVector3D Orientation; long Seed = -1; @@ -1009,6 +1015,20 @@ Garrison.push_back(attrs.GetNamedItem(at_uid).ToInt()); } } + // + else if (element_name == el_turrets) + { + XMBElementList turrets = setting.GetChildNodes(); + Turrets.reserve(turrets.size()); + for (const XMBElement& turretPoint : turrets) + { + XMBAttributeList attrs = turretPoint.GetAttributes(); + Turrets.push_back(std::make_pair( + attrs.GetNamedItem(at_turret), + attrs.GetNamedItem(at_uid).ToInt() + )); + } + } // else if (element_name == el_actor) { Index: source/graphics/MapWriter.cpp =================================================================== --- source/graphics/MapWriter.cpp +++ source/graphics/MapWriter.cpp @@ -44,6 +44,7 @@ #include "simulation2/components/ICmpOwnership.h" #include "simulation2/components/ICmpPosition.h" #include "simulation2/components/ICmpTemplateManager.h" +#include "simulation2/components/ICmpTurretHolder.h" #include "simulation2/components/ICmpVisual.h" #include "simulation2/components/ICmpWaterManager.h" @@ -353,7 +354,22 @@ { XMLWriter_Element garrisonedEntityTag(xmlMapFile, "GarrisonedEntity"); garrisonedEntityTag.Attribute("uid", static_cast(garr_ent_id)); - // ToDo: We can store turret position as well. + } + } + } + + CmpPtr cmpTurretHolder(sim, ent); + if (cmpTurretHolder) + { + std::vector > turrets = cmpTurretHolder->GetTurrets(); + if (!turrets.empty()) + { + XMLWriter_Element turretTag(xmlMapFile, "Turrets"); + for (const std::pair turret : turrets) + { + XMLWriter_Element turretedEntityTag(xmlMapFile, "Turret"); + turretedEntityTag.Attribute("turret", turret.first); + turretedEntityTag.Attribute("uid", static_cast(turret.second)); } } } Index: source/simulation2/TypeList.h =================================================================== --- source/simulation2/TypeList.h +++ source/simulation2/TypeList.h @@ -189,6 +189,9 @@ INTERFACE(TerritoryManager) COMPONENT(TerritoryManager) +INTERFACE(TurretHolder) +COMPONENT(TurretHolderScripted) + INTERFACE(UnitMotion) COMPONENT(UnitMotion) // must be after Obstruction COMPONENT(UnitMotionScripted) Index: source/simulation2/components/ICmpTurretHolder.h =================================================================== --- /dev/null +++ source/simulation2/components/ICmpTurretHolder.h @@ -0,0 +1,35 @@ +/* Copyright (C) 2020 Wildfire Games. +* This file is part of 0 A.D. +* +* 0 A.D. is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 2 of the License, or +* (at your option) any later version. +* +* 0 A.D. is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with 0 A.D. If not, see . +*/ + +#ifndef INCLUDED_ICMPTURRETHOLDER +#define INCLUDED_ICMPTURRETHOLDER + +#include "simulation2/system/Interface.h" + +#include + +class ICmpTurretHolder : public IComponent +{ +public: + virtual std::vector > GetTurrets() const = 0; + + virtual void SetInitEntities(const std::vector > entities) = 0; + + DECLARE_INTERFACE_TYPE(TurretHolder) +}; + +#endif // INCLUDED_ICMPTURRETHOLDER Index: source/simulation2/components/ICmpTurretHolder.cpp =================================================================== --- /dev/null +++ source/simulation2/components/ICmpTurretHolder.cpp @@ -0,0 +1,46 @@ +/* Copyright (C) 2020 Wildfire Games. +* This file is part of 0 A.D. +* +* 0 A.D. is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 2 of the License, or +* (at your option) any later version. +* +* 0 A.D. is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with 0 A.D. If not, see . +*/ + +#include "precompiled.h" + +#include "ICmpTurretHolder.h" + +#include "simulation2/scripting/ScriptComponent.h" +#include "simulation2/system/InterfaceScripted.h" + +BEGIN_INTERFACE_WRAPPER(TurretHolder) +END_INTERFACE_WRAPPER(TurretHolder) + +class CCmpTurretHolderScripted : public ICmpTurretHolder +{ +public: + DEFAULT_SCRIPT_WRAPPER(TurretHolderScripted) + + virtual std::vector > GetTurrets() const + { + // This does not exist. + return m_Script.Call > >("GetTurrets"); + } + + virtual void SetInitEntities(std::vector > entities) + { + for (const std::pair p : entities) + m_Script.CallVoid("SetInitEntity", p.first, p.second); + } +}; + +REGISTER_COMPONENT_SCRIPT_WRAPPER(TurretHolderScripted)