diff --git a/binaries/data/mods/public/maps/scenario.rnc b/binaries/data/mods/public/maps/scenario.rnc
index f4abc6c8f5..dd5f6b9ef4 100644
--- a/binaries/data/mods/public/maps/scenario.rnc
+++ b/binaries/data/mods/public/maps/scenario.rnc
@@ -103,6 +103,11 @@ Scenario = element Scenario {
attribute group { xsd:positiveInteger },
attribute group2 { xsd:positiveInteger }?
}? &
+ element Garrison {
+ element GarrisonedEntity {
+ attribute uid { xsd:positiveInteger } &
+ } &
+ } &
element Actor {
attribute seed { xsd:integer }
}?
diff --git a/binaries/data/mods/public/maps/scenario.rng b/binaries/data/mods/public/maps/scenario.rng
index 947f019b14..4d80f3a9be 100644
--- a/binaries/data/mods/public/maps/scenario.rng
+++ b/binaries/data/mods/public/maps/scenario.rng
@@ -256,6 +256,17 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/binaries/data/mods/public/maps/skirmishes/Sicilia_Nomad.xml b/binaries/data/mods/public/maps/skirmishes/Sicilia_Nomad.xml
index 0c3e92a81e..5cc8f25cbf 100644
--- a/binaries/data/mods/public/maps/skirmishes/Sicilia_Nomad.xml
+++ b/binaries/data/mods/public/maps/skirmishes/Sicilia_Nomad.xml
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:bc402fc30beea8e2aaf1c3ab1c3d94edbb4e6690623d4d2566fbc320f7a9cc47
-size 519678
+oid sha256:b7c9e45798b8cff82e56a25c3860e7764cb2ae702cd81e8913f33cd50382f867
+size 520558
diff --git a/binaries/data/mods/public/simulation/components/GarrisonHolder.js b/binaries/data/mods/public/simulation/components/GarrisonHolder.js
index ef587b4586..7586b90569 100644
--- a/binaries/data/mods/public/simulation/components/GarrisonHolder.js
+++ b/binaries/data/mods/public/simulation/components/GarrisonHolder.js
@@ -690,6 +690,16 @@ GarrisonHolder.prototype.IsEjectable = function(entity)
return MatchesClassList(entityClasses, ejectableClasses);
};
+/**
+ * Sets the intitGarrison to the specified entities. Used by the mapreader.
+ *
+ * @param {number[]} entities - The entity IDs to garrison on init.
+ */
+GarrisonHolder.prototype.SetInitGarrison = function(entities)
+{
+ this.initGarrison = clone(entities);
+};
+
/**
* Initialise the garrisoned units.
*/
diff --git a/binaries/data/mods/public/simulation/components/interfaces/GarrisonHolder.js b/binaries/data/mods/public/simulation/components/interfaces/GarrisonHolder.js
index b32488a15e..5ef3827feb 100644
--- a/binaries/data/mods/public/simulation/components/interfaces/GarrisonHolder.js
+++ b/binaries/data/mods/public/simulation/components/interfaces/GarrisonHolder.js
@@ -1,5 +1,3 @@
-Engine.RegisterInterface("GarrisonHolder");
-
/**
* Message of the form { "added": number[], "removed": number[] }
* sent from the GarrisonHolder component to the current entity whenever the garrisoned units change.
diff --git a/binaries/data/mods/public/simulation/helpers/Setup.js b/binaries/data/mods/public/simulation/helpers/Setup.js
index 530b2900a6..ce5c49cf15 100644
--- a/binaries/data/mods/public/simulation/helpers/Setup.js
+++ b/binaries/data/mods/public/simulation/helpers/Setup.js
@@ -64,16 +64,6 @@ function LoadMapSettings(settings)
if (settings.LockTeams && settings.LastManStanding)
warn("Last man standing is only available in games with unlocked teams!");
- if (settings.Garrison)
- for (let holder in settings.Garrison)
- {
- let cmpGarrisonHolder = Engine.QueryInterface(+holder, IID_GarrisonHolder);
- if (!cmpGarrisonHolder)
- warn("Map error in Setup.js: entity " + holder + " can not garrison units");
- else
- cmpGarrisonHolder.initGarrison = settings.Garrison[holder];
- }
-
let cmpCeasefireManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_CeasefireManager);
if (settings.Ceasefire)
cmpCeasefireManager.StartCeasefire(settings.Ceasefire * 60 * 1000);
diff --git a/source/graphics/MapReader.cpp b/source/graphics/MapReader.cpp
index 98bd89178b..df3abf3ab7 100644
--- a/source/graphics/MapReader.cpp
+++ b/source/graphics/MapReader.cpp
@@ -1,4 +1,4 @@
-/* Copyright (C) 2019 Wildfire Games.
+/* 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
@@ -41,6 +41,7 @@
#include "renderer/WaterManager.h"
#include "simulation2/Simulation2.h"
#include "simulation2/components/ICmpCinemaManager.h"
+#include "simulation2/components/ICmpGarrisonHolder.h"
#include "simulation2/components/ICmpObstruction.h"
#include "simulation2/components/ICmpOwnership.h"
#include "simulation2/components/ICmpPlayer.h"
@@ -416,6 +417,7 @@ private:
int el_tracks;
int el_template, el_player;
int el_position, el_orientation, el_obstruction;
+ int el_garrison;
int el_actor;
int at_x, at_y, at_z;
int at_group, at_group2;
@@ -465,6 +467,7 @@ void CXMLReader::Init(const VfsPath& xml_filename)
EL(template);
EL(player);
EL(position);
+ EL(garrison);
EL(orientation);
EL(obstruction);
EL(actor);
@@ -946,6 +949,7 @@ int CXMLReader::ReadEntities(XMBElement parent, double end_time)
CStrW TemplateName;
int PlayerID = 0;
+ std::vector Garrison;
CFixedVector3D Position;
CFixedVector3D Orientation;
long Seed = -1;
@@ -994,6 +998,17 @@ int CXMLReader::ReadEntities(XMBElement parent, double end_time)
ControlGroup = attrs.GetNamedItem(at_group).ToInt();
ControlGroup2 = attrs.GetNamedItem(at_group2).ToInt();
}
+ //
+ else if (element_name == el_garrison)
+ {
+ XMBElementList garrison = setting.GetChildNodes();
+ Garrison.reserve(garrison.size());
+ for (const XMBElement& garr_ent : garrison)
+ {
+ XMBAttributeList attrs = garr_ent.GetAttributes();
+ Garrison.push_back(attrs.GetNamedItem(at_uid).ToInt());
+ }
+ }
//
else if (element_name == el_actor)
{
@@ -1029,6 +1044,16 @@ int CXMLReader::ReadEntities(XMBElement parent, double end_time)
if (cmpOwnership)
cmpOwnership->SetOwner(PlayerID);
+ if (!Garrison.empty())
+ {
+ CmpPtr cmpGarrisonHolder(sim, ent);
+ if (cmpGarrisonHolder)
+ cmpGarrisonHolder->SetInitEntities(Garrison);
+ else
+ LOGERROR("CXMLMapReader::ReadEntities() entity '%d' of player '%d' has no GarrisonHolder component and thus cannot garrison units.", ent, PlayerID);
+ Garrison.clear();
+ }
+
CmpPtr cmpObstruction(sim, ent);
if (cmpObstruction)
{
diff --git a/source/graphics/MapWriter.cpp b/source/graphics/MapWriter.cpp
index fe2593b4b1..3eb35e04a8 100644
--- a/source/graphics/MapWriter.cpp
+++ b/source/graphics/MapWriter.cpp
@@ -1,4 +1,4 @@
-/* Copyright (C) 2019 Wildfire Games.
+/* 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
@@ -39,6 +39,7 @@
#include "renderer/WaterManager.h"
#include "simulation2/Simulation2.h"
#include "simulation2/components/ICmpCinemaManager.h"
+#include "simulation2/components/ICmpGarrisonHolder.h"
#include "simulation2/components/ICmpObstruction.h"
#include "simulation2/components/ICmpOwnership.h"
#include "simulation2/components/ICmpPosition.h"
@@ -341,6 +342,19 @@ void CMapWriter::WriteXML(const VfsPath& filename,
if (cmpOwnership)
entityTag.Setting("Player", static_cast(cmpOwnership->GetOwner()));
+ CmpPtr cmpGarrisonHolder(sim, ent);
+ if (cmpGarrisonHolder)
+ {
+ XMLWriter_Element garrisonTag(xmlMapFile, "Garrison");
+ std::vector garrison = cmpGarrisonHolder->GetEntities();
+ for (const entity_id_t garr_ent_id : garrison)
+ {
+ XMLWriter_Element garrisonedEntityTag(xmlMapFile, "GarrisonedEntity");
+ garrisonedEntityTag.Attribute("uid", static_cast(garr_ent_id));
+ // ToDo: We can store turret position as well.
+ }
+ }
+
CmpPtr cmpPosition(sim, ent);
if (cmpPosition)
{
diff --git a/source/simulation2/TypeList.h b/source/simulation2/TypeList.h
index eff05ed289..6f157b8314 100644
--- a/source/simulation2/TypeList.h
+++ b/source/simulation2/TypeList.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2019 Wildfire Games.
+/* 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
@@ -98,6 +98,9 @@ COMPONENT(FoggingScripted)
INTERFACE(Footprint)
COMPONENT(Footprint)
+INTERFACE(GarrisonHolder)
+COMPONENT(GarrisonHolderScripted)
+
INTERFACE(GuiInterface)
COMPONENT(GuiInterfaceScripted)
diff --git a/source/simulation2/components/ICmpGarrisonHolder.cpp b/source/simulation2/components/ICmpGarrisonHolder.cpp
new file mode 100644
index 0000000000..de3cbc1117
--- /dev/null
+++ b/source/simulation2/components/ICmpGarrisonHolder.cpp
@@ -0,0 +1,44 @@
+/* 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 "ICmpGarrisonHolder.h"
+
+#include "simulation2/scripting/ScriptComponent.h"
+#include "simulation2/system/InterfaceScripted.h"
+
+BEGIN_INTERFACE_WRAPPER(GarrisonHolder)
+END_INTERFACE_WRAPPER(GarrisonHolder)
+
+class CCmpGarrisonHolderScripted : public ICmpGarrisonHolder
+{
+public:
+ DEFAULT_SCRIPT_WRAPPER(GarrisonHolderScripted)
+
+ virtual std::vector GetEntities() const
+ {
+ return m_Script.Call >("GetEntities");
+ }
+
+ virtual void SetInitEntities(std::vector entities)
+ {
+ m_Script.CallVoid("SetInitGarrison", entities);
+ }
+};
+
+REGISTER_COMPONENT_SCRIPT_WRAPPER(GarrisonHolderScripted)
diff --git a/source/simulation2/components/ICmpGarrisonHolder.h b/source/simulation2/components/ICmpGarrisonHolder.h
new file mode 100644
index 0000000000..b89908f717
--- /dev/null
+++ b/source/simulation2/components/ICmpGarrisonHolder.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_ICMPGARRISONHOLDER
+#define INCLUDED_ICMPGARRISONHOLDER
+
+#include "simulation2/system/Interface.h"
+
+#include
+
+class ICmpGarrisonHolder : public IComponent
+{
+public:
+ virtual std::vector GetEntities() const = 0;
+
+ virtual void SetInitEntities(const std::vector entities) = 0;
+
+ DECLARE_INTERFACE_TYPE(GarrisonHolder)
+};
+
+#endif // INCLUDED_ICMPGARRISONHOLDER