Index: binaries/data/mods/public/art/actors/structures/hellenes/siege_tower.xml
===================================================================
--- binaries/data/mods/public/art/actors/structures/hellenes/siege_tower.xml	(revision 18123)
+++ binaries/data/mods/public/art/actors/structures/hellenes/siege_tower.xml	(working copy)
@@ -17,12 +17,15 @@
     </variant>
   </group>
   <group>
-    <variant frequency="100" name="Idle"/>
+    <variant frequency="1" name="ungarrisoned"/>
     <variant name="garrisoned">
       <props>
         <prop actor="props/special/common/waypoint_flag_0ad.xml" attachpoint="garrisoned"/>
       </props>
     </variant>
+  </group>
+  <group>
+    <variant frequency="1" name="alive"/>
     <variant name="death">
       <props>
         <prop attachpoint="garrisoned"/>
Index: binaries/data/mods/public/simulation/components/GarrisonHolder.js
===================================================================
--- binaries/data/mods/public/simulation/components/GarrisonHolder.js	(revision 18123)
+++ binaries/data/mods/public/simulation/components/GarrisonHolder.js	(working copy)
@@ -566,16 +566,18 @@
 
 GarrisonHolder.prototype.UpdateGarrisonFlag = function()
 {
-	var cmpVisual = Engine.QueryInterface(this.entity, IID_Visual);
+	let cmpVisual = Engine.QueryInterface(this.entity, IID_Visual);
 	if (!cmpVisual)
 		return;
-	cmpVisual.SelectAnimation("garrisoned", true, 0, "");
-	// TODO: ought to extend ICmpVisual to let us just select variant
-	// keywords without changing the animation too
+	let oldVariant = "garrisoned";
+	let newVariant = "garrisoned";
 	if (this.entities.length)
-		cmpVisual.SelectAnimation("garrisoned", false, 1.0, "");
+		oldVariant = "ungarrisoned";
 	else
-		cmpVisual.SelectAnimation("idle", false, 1.0, "");
+		newVariant = "ungarrisoned";
+
+	let selections = cmpVisual.GetVariantSelections();
+	cmpVisual.SetVariantSelections(selections.map(s => s == oldVariant ? newVariant : s))
 };
 
 /**
Index: source/simulation2/components/CCmpVisualActor.cpp
===================================================================
--- source/simulation2/components/CCmpVisualActor.cpp	(revision 18123)
+++ source/simulation2/components/CCmpVisualActor.cpp	(working copy)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2014 Wildfire Games.
+/* Copyright (C) 2016 Wildfire Games.
  * This file is part of 0 A.D.
  *
  * 0 A.D. is free software: you can redistribute it and/or modify
@@ -32,6 +32,8 @@
 #include "ICmpValueModificationManager.h"
 #include "ICmpVisibility.h"
 
+#include "simulation2/serialization/SerializeTemplates.h"
+
 #include "graphics/Decal.h"
 #include "graphics/Frustum.h"
 #include "graphics/Model.h"
@@ -230,7 +232,6 @@
 		serialize.NumberFixed_Unbounded("anim sync repeat time", m_AnimSyncRepeatTime);
 
 		serialize.NumberU32_Unbounded("seed", m_Seed);
-		// TODO: variation/selection strings
 		serialize.String("actor", m_ActorName, 0, 256);
 
 		// TODO: store actor variables?
@@ -246,6 +247,9 @@
 		}
 
 		SerializeCommon(serialize);
+
+		std::vector<std::string> variantSelections = GetVariantSelections();
+		SerializeVector<SerializeString>()(serialize, "variantSeletions", variantSelections);
 	}
 
 	virtual void Deserialize(const CParamNode& paramNode, IDeserializer& deserialize)
@@ -269,6 +273,10 @@
 
 		SetAnimationSyncRepeat(repeattime);
 
+		std::vector<std::string> variantSelections;
+		SerializeVector<SerializeString>()(deserialize, "variantSeletions", variantSelections);
+		SetVariantSelections(variantSelections);
+
 		if (m_Unit)
 		{
 			CmpPtr<ICmpOwnership> cmpOwnership(GetEntityHandle());
@@ -410,6 +418,24 @@
 		return CVector3D();
 	}
 
+	virtual std::vector<std::string> GetVariantSelections()
+	{
+		std::vector<std::string> result;
+		if (!m_Unit)
+			return result;
+		std::set<CStr> selections = m_Unit->GetActorSelections();
+		std::copy(selections.begin(), selections.end(), std::back_inserter(result));
+		return result;
+	}
+
+	virtual void SetVariantSelections(const std::vector<std::string>& selections)
+	{
+		if (!m_Unit)
+			return;
+		std::set<CStr> result(selections.begin(), selections.end());
+		m_Unit->SetActorSelections(result);
+	}
+
 	virtual void SelectAnimation(const std::string& name, bool once, fixed speed, const std::wstring& soundgroup)
 	{
 		m_AnimRunThreshold = fixed::Zero();
Index: source/simulation2/components/ICmpVisual.cpp
===================================================================
--- source/simulation2/components/ICmpVisual.cpp	(revision 18123)
+++ source/simulation2/components/ICmpVisual.cpp	(working copy)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2013 Wildfire Games.
+/* Copyright (C) 2016 Wildfire Games.
  * This file is part of 0 A.D.
  *
  * 0 A.D. is free software: you can redistribute it and/or modify
@@ -22,6 +22,8 @@
 #include "simulation2/system/InterfaceScripted.h"
 
 BEGIN_INTERFACE_WRAPPER(Visual)
+DEFINE_INTERFACE_METHOD_0("GetVariantSelections", std::vector<std::string>, ICmpVisual, GetVariantSelections)
+DEFINE_INTERFACE_METHOD_1("SetVariantSelections", void, ICmpVisual, SetVariantSelections, std::vector<std::string>)
 DEFINE_INTERFACE_METHOD_4("SelectAnimation", void, ICmpVisual, SelectAnimation, std::string, bool, fixed, std::wstring)
 DEFINE_INTERFACE_METHOD_1("SelectMovementAnimation", void, ICmpVisual, SelectMovementAnimation, fixed)
 DEFINE_INTERFACE_METHOD_1("ResetMoveAnimation", void, ICmpVisual, ResetMoveAnimation, std::string)
Index: source/simulation2/components/ICmpVisual.h
===================================================================
--- source/simulation2/components/ICmpVisual.h	(revision 18123)
+++ source/simulation2/components/ICmpVisual.h	(working copy)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2013 Wildfire Games.
+/* Copyright (C) 2016 Wildfire Games.
  * This file is part of 0 A.D.
  *
  * 0 A.D. is free software: you can redistribute it and/or modify
@@ -80,6 +80,16 @@
 	virtual CUnit* GetUnit() = 0;
 
 	/**
+	 * Get the variant selections of the actor
+	 */
+	virtual std::vector<std::string> GetVariantSelections() = 0;
+
+	/**
+	 * Set the variant selections of the actor
+	 */
+	virtual void SetVariantSelections(const std::vector<std::string>& selections) = 0;
+
+	/**
 	 * Start playing the given animation. If there are multiple possible animations then it will
 	 * pick one at random (not network-synchronised).
 	 * If @p soundgroup is specified, then the sound will be played at each 'event' point in the
