Index: binaries/data/mods/public/simulation/components/Identity.js =================================================================== --- binaries/data/mods/public/simulation/components/Identity.js +++ binaries/data/mods/public/simulation/components/Identity.js @@ -17,7 +17,10 @@ "" + "" + "" + - "" + + "" + + "" + + "tokens" + + "" + "" + "" + "" + @@ -95,15 +98,12 @@ { this.classesList = GetIdentityClasses(this.template); this.visibleClassesList = GetVisibleIdentityClasses(this.template); + if (this.template.Phenotype) + this.phenotype = pickRandom(this.GetPossiblePhenotypes()); + else + this.phenotype = "default"; }; -Identity.prototype.Deserialize = function () -{ - this.Init(); -}; - -Identity.prototype.Serialize = null; // we have no dynamic state to save - Identity.prototype.GetCiv = function() { return this.template.Civ; @@ -114,9 +114,22 @@ return this.template.Lang || "greek"; // ugly default }; -Identity.prototype.GetGender = function() +/** + * Get a list of possible Phenotypes. + * @return {string[]} A list of possible phenotypes. + */ +Identity.prototype.GetPossiblePhenotypes = function() +{ + return this.template.Phenotype._string.split(/\s+/); +}; + +/** + * Get the current Phenotype. + * @return {string} The current phenotype. + */ +Identity.prototype.GetPhenotype = function() { - return this.template.Gender || "male"; // ugly default + return this.phenotype; }; Identity.prototype.GetRank = function() Index: binaries/data/mods/public/simulation/components/Sound.js =================================================================== --- binaries/data/mods/public/simulation/components/Sound.js +++ binaries/data/mods/public/simulation/components/Sound.js @@ -35,16 +35,16 @@ if (name in this.template.SoundGroups) { // Replace the "{lang}" codes with this entity's civ ID - var cmpIdentity = Engine.QueryInterface(this.entity, IID_Identity); + let cmpIdentity = Engine.QueryInterface(this.entity, IID_Identity); if (!cmpIdentity) return; - var lang = cmpIdentity.GetLang(); - // Replace the "{gender}" codes with this entity's gender ID - var gender = cmpIdentity.GetGender(); - - var soundName = this.template.SoundGroups[name].replace(/\{lang\}/g, lang) - .replace(/\{gender\}/g, gender); - var cmpSoundManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_SoundManager); + let lang = cmpIdentity.GetLang(); + // Replace the "{phenotype}" codes with this entity's phenotype ID + let phenotype = cmpIdentity.GetPhenotype(); + + let soundName = this.template.SoundGroups[name].replace(/\{lang\}/g, lang) + .replace(/\{phenotype\}/g, phenotype); + let cmpSoundManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_SoundManager); if (cmpSoundManager) cmpSoundManager.PlaySoundGroup(soundName, this.entity); } Index: binaries/data/mods/public/simulation/components/tests/test_Identity.js =================================================================== --- binaries/data/mods/public/simulation/components/tests/test_Identity.js +++ binaries/data/mods/public/simulation/components/tests/test_Identity.js @@ -2,12 +2,13 @@ let cmpIdentity = ConstructComponent(5, "Identity", { "Civ": "iber", - "GenericName": "Iberian Skirmisher" + "GenericName": "Iberian Skirmisher", + "Phenotype": { "_string": "male" }, }); TS_ASSERT_EQUALS(cmpIdentity.GetCiv(), "iber"); TS_ASSERT_EQUALS(cmpIdentity.GetLang(), "greek"); -TS_ASSERT_EQUALS(cmpIdentity.GetGender(), "male"); +TS_ASSERT_EQUALS(cmpIdentity.GetPhenotype(), "male"); TS_ASSERT_EQUALS(cmpIdentity.GetRank(), ""); TS_ASSERT_UNEVAL_EQUALS(cmpIdentity.GetClassesList(), []); TS_ASSERT_UNEVAL_EQUALS(cmpIdentity.GetVisibleClassesList(), []); @@ -20,7 +21,7 @@ cmpIdentity = ConstructComponent(6, "Identity", { "Civ": "iber", "Lang": "iberian", - "Gender": "female", + "Phenotype": { "_string": "female" }, "GenericName": "Iberian Skirmisher", "SpecificName": "Lusitano Ezpatari", "SelectionGroupName": "units/iber_infantry_javelinist_b", @@ -39,7 +40,7 @@ TS_ASSERT_EQUALS(cmpIdentity.GetCiv(), "iber"); TS_ASSERT_EQUALS(cmpIdentity.GetLang(), "iberian"); -TS_ASSERT_EQUALS(cmpIdentity.GetGender(), "female"); +TS_ASSERT_EQUALS(cmpIdentity.GetPhenotype(), "female"); TS_ASSERT_EQUALS(cmpIdentity.GetRank(), "Basic"); TS_ASSERT_UNEVAL_EQUALS(cmpIdentity.GetClassesList(), ["CitizenSoldier", "Human", "Organic", "Javelin", "Basic"]); TS_ASSERT_UNEVAL_EQUALS(cmpIdentity.GetVisibleClassesList(), ["Javelin"]); @@ -50,3 +51,12 @@ TS_ASSERT_EQUALS(cmpIdentity.CanUseFormation("special/formations/line"), false); TS_ASSERT_EQUALS(cmpIdentity.GetSelectionGroupName(), "units/iber_infantry_javelinist_b"); TS_ASSERT_EQUALS(cmpIdentity.GetGenericName(), "Iberian Skirmisher"); + +cmpIdentity = ConstructComponent(7, "Identity", { + "Phenotype": { "_string": "First Second" }, +}); +TS_ASSERT_UNEVAL_EQUALS(cmpIdentity.GetPossiblePhenotypes(), ["First", "Second"]); +TS_ASSERT(["First", "Second"].indexOf(cmpIdentity.GetPhenotype()) !== -1); + +cmpIdentity = ConstructComponent(8, "Identity", {}); +TS_ASSERT_EQUALS(cmpIdentity.GetPhenotype(), "default"); Index: binaries/data/mods/public/simulation/templates/template_unit.xml =================================================================== --- binaries/data/mods/public/simulation/templates/template_unit.xml +++ binaries/data/mods/public/simulation/templates/template_unit.xml @@ -51,6 +51,7 @@ special/formations/flank special/formations/battle_line + male false Index: binaries/data/mods/public/simulation/templates/template_unit_cavalry.xml =================================================================== --- binaries/data/mods/public/simulation/templates/template_unit_cavalry.xml +++ binaries/data/mods/public/simulation/templates/template_unit_cavalry.xml @@ -80,11 +80,11 @@ - - voice/{lang}/civ/civ_{gender}_walk.xml - voice/{lang}/civ/civ_{gender}_attack.xml - voice/{lang}/civ/civ_{gender}_gather.xml - voice/{lang}/civ/civ_{gender}_garrison.xml + + voice/{lang}/civ/civ_{phenotype}_walk.xml + voice/{lang}/civ/civ_{phenotype}_attack.xml + voice/{lang}/civ/civ_{phenotype}_gather.xml + voice/{lang}/civ/civ_{phenotype}_garrison.xml actor/mounted/movement/walk.xml actor/mounted/movement/walk.xml attack/impact/arrow_metal.xml Index: binaries/data/mods/public/simulation/templates/template_unit_champion_cavalry.xml =================================================================== --- binaries/data/mods/public/simulation/templates/template_unit_champion_cavalry.xml +++ binaries/data/mods/public/simulation/templates/template_unit_champion_cavalry.xml @@ -42,11 +42,11 @@ - - voice/{lang}/civ/civ_{gender}_walk.xml - voice/{lang}/civ/civ_{gender}_attack.xml - voice/{lang}/civ/civ_{gender}_gather.xml - voice/{lang}/civ/civ_{gender}_garrison.xml + + voice/{lang}/civ/civ_{phenotype}_walk.xml + voice/{lang}/civ/civ_{phenotype}_attack.xml + voice/{lang}/civ/civ_{phenotype}_gather.xml + voice/{lang}/civ/civ_{phenotype}_garrison.xml actor/mounted/movement/walk.xml actor/mounted/movement/walk.xml attack/weapon/sword.xml Index: binaries/data/mods/public/simulation/templates/template_unit_champion_infantry.xml =================================================================== --- binaries/data/mods/public/simulation/templates/template_unit_champion_infantry.xml +++ binaries/data/mods/public/simulation/templates/template_unit_champion_infantry.xml @@ -32,16 +32,16 @@ interface/alarm/alarm_create_infantry.xml - - voice/{lang}/civ/civ_{gender}_walk.xml - voice/{lang}/civ/civ_{gender}_attack.xml - voice/{lang}/civ/civ_{gender}_gather.xml - voice/{lang}/civ/civ_{gender}_repair.xml - voice/{lang}/civ/civ_{gender}_garrison.xml + + voice/{lang}/civ/civ_{phenotype}_walk.xml + voice/{lang}/civ/civ_{phenotype}_attack.xml + voice/{lang}/civ/civ_{phenotype}_gather.xml + voice/{lang}/civ/civ_{phenotype}_repair.xml + voice/{lang}/civ/civ_{phenotype}_garrison.xml actor/human/movement/walk.xml actor/human/movement/walk.xml attack/weapon/sword.xml - actor/human/death/{gender}_death.xml + actor/human/death/{phenotype}_death.xml Index: binaries/data/mods/public/simulation/templates/template_unit_hero.xml =================================================================== --- binaries/data/mods/public/simulation/templates/template_unit_hero.xml +++ binaries/data/mods/public/simulation/templates/template_unit_hero.xml @@ -54,20 +54,20 @@ - + interface/alarm/alarm_create_infantry.xml - voice/{lang}/civ/civ_{gender}_heal.xml - voice/{lang}/civ/civ_{gender}_walk.xml - voice/{lang}/civ/civ_{gender}_attack.xml - voice/{lang}/civ/civ_{gender}_gather.xml - voice/{lang}/civ/civ_{gender}_repair.xml - voice/{lang}/civ/civ_{gender}_garrison.xml + voice/{lang}/civ/civ_{phenotype}_heal.xml + voice/{lang}/civ/civ_{phenotype}_walk.xml + voice/{lang}/civ/civ_{phenotype}_attack.xml + voice/{lang}/civ/civ_{phenotype}_gather.xml + voice/{lang}/civ/civ_{phenotype}_repair.xml + voice/{lang}/civ/civ_{phenotype}_garrison.xml attack/weapon/sword.xml attack/impact/arrow_metal.xml attack/weapon/arrowfly.xml actor/human/movement/walk.xml actor/human/movement/walk.xml - actor/human/death/{gender}_death.xml + actor/human/death/{phenotype}_death.xml Index: binaries/data/mods/public/simulation/templates/template_unit_infantry.xml =================================================================== --- binaries/data/mods/public/simulation/templates/template_unit_infantry.xml +++ binaries/data/mods/public/simulation/templates/template_unit_infantry.xml @@ -100,18 +100,18 @@ - - voice/{lang}/civ/civ_{gender}_walk.xml - voice/{lang}/civ/civ_{gender}_attack.xml - voice/{lang}/civ/civ_{gender}_gather.xml - voice/{lang}/civ/civ_{gender}_repair.xml - voice/{lang}/civ/civ_{gender}_garrison.xml + + voice/{lang}/civ/civ_{phenotype}_walk.xml + voice/{lang}/civ/civ_{phenotype}_attack.xml + voice/{lang}/civ/civ_{phenotype}_gather.xml + voice/{lang}/civ/civ_{phenotype}_repair.xml + voice/{lang}/civ/civ_{phenotype}_garrison.xml actor/human/movement/walk.xml actor/human/movement/run.xml attack/impact/arrow_metal.xml attack/weapon/sword.xml attack/weapon/arrowfly.xml - actor/human/death/{gender}_death.xml + actor/human/death/{phenotype}_death.xml resource/construction/con_wood.xml resource/foraging/forage_leaves.xml resource/farming/farm.xml Index: binaries/data/mods/public/simulation/templates/template_unit_support_female_citizen.xml =================================================================== --- binaries/data/mods/public/simulation/templates/template_unit_support_female_citizen.xml +++ binaries/data/mods/public/simulation/templates/template_unit_support_female_citizen.xml @@ -48,7 +48,7 @@ Female Citizen - female + female FemaleCitizen Citizen Worker @@ -70,15 +70,15 @@ interface/alarm/alarm_create_female.xml - - voice/{lang}/civ/civ_{gender}_walk.xml - voice/{lang}/civ/civ_{gender}_attack.xml - voice/{lang}/civ/civ_{gender}_build.xml - voice/{lang}/civ/civ_{gender}_gather.xml - voice/{lang}/civ/civ_{gender}_repair.xml - voice/{lang}/civ/civ_{gender}_garrison.xml + + voice/{lang}/civ/civ_{phenotype}_walk.xml + voice/{lang}/civ/civ_{phenotype}_attack.xml + voice/{lang}/civ/civ_{phenotype}_build.xml + voice/{lang}/civ/civ_{phenotype}_gather.xml + voice/{lang}/civ/civ_{phenotype}_repair.xml + voice/{lang}/civ/civ_{phenotype}_garrison.xml attack/weapon/sword.xml - actor/human/death/{gender}_death.xml + actor/human/death/{phenotype}_death.xml resource/construction/con_wood.xml resource/foraging/forage_leaves.xml resource/farming/farm.xml Index: binaries/data/mods/public/simulation/templates/template_unit_support_healer.xml =================================================================== --- binaries/data/mods/public/simulation/templates/template_unit_support_healer.xml +++ binaries/data/mods/public/simulation/templates/template_unit_support_healer.xml @@ -42,16 +42,16 @@ interface/alarm/alarm_create_infantry.xml - - voice/{lang}/civ/civ_{gender}_walk.xml - voice/{lang}/civ/civ_{gender}_attack.xml - voice/{lang}/civ/civ_{gender}_gather.xml - voice/{lang}/civ/civ_{gender}_repair.xml - voice/{lang}/civ/civ_{gender}_heal.xml - voice/{lang}/civ/civ_{gender}_garrison.xml + + voice/{lang}/civ/civ_{phenotype}_walk.xml + voice/{lang}/civ/civ_{phenotype}_attack.xml + voice/{lang}/civ/civ_{phenotype}_gather.xml + voice/{lang}/civ/civ_{phenotype}_repair.xml + voice/{lang}/civ/civ_{phenotype}_heal.xml + voice/{lang}/civ/civ_{phenotype}_garrison.xml actor/human/movement/walk.xml actor/human/movement/run.xml - actor/human/death/{gender}_death.xml + actor/human/death/{phenotype}_death.xml Index: binaries/data/mods/public/simulation/templates/template_unit_support_slave.xml =================================================================== --- binaries/data/mods/public/simulation/templates/template_unit_support_slave.xml +++ binaries/data/mods/public/simulation/templates/template_unit_support_slave.xml @@ -65,14 +65,14 @@ - - voice/{lang}/civ/civ_{gender}_walk.xml - voice/{lang}/civ/civ_{gender}_gather.xml - voice/{lang}/civ/civ_{gender}_repair.xml - voice/{lang}/civ/civ_{gender}_garrison.xml + + voice/{lang}/civ/civ_{phenotype}_walk.xml + voice/{lang}/civ/civ_{phenotype}_gather.xml + voice/{lang}/civ/civ_{phenotype}_repair.xml + voice/{lang}/civ/civ_{phenotype}_garrison.xml actor/human/movement/walk.xml actor/human/movement/run.xml - actor/human/death/{gender}_death.xml + actor/human/death/{phenotype}_death.xml resource/construction/con_wood.xml resource/foraging/forage_leaves.xml resource/farming/farm.xml Index: binaries/data/mods/public/simulation/templates/template_unit_support_trader.xml =================================================================== --- binaries/data/mods/public/simulation/templates/template_unit_support_trader.xml +++ binaries/data/mods/public/simulation/templates/template_unit_support_trader.xml @@ -19,16 +19,16 @@ - - voice/{lang}/civ/civ_{gender}_trade.xml - voice/{lang}/civ/civ_{gender}_walk.xml - voice/{lang}/civ/civ_{gender}_attack.xml - voice/{lang}/civ/civ_{gender}_gather.xml - voice/{lang}/civ/civ_{gender}_repair.xml + + voice/{lang}/civ/civ_{phenotype}_trade.xml + voice/{lang}/civ/civ_{phenotype}_walk.xml + voice/{lang}/civ/civ_{phenotype}_attack.xml + voice/{lang}/civ/civ_{phenotype}_gather.xml + voice/{lang}/civ/civ_{phenotype}_repair.xml actor/human/movement/walk.xml actor/human/movement/run.xml attack/weapon/sword.xml - actor/human/death/{gender}_death.xml + actor/human/death/{phenotype}_death.xml resource/construction/con_wood.xml resource/foraging/forage_leaves.xml resource/farming/farm.xml Index: binaries/data/mods/public/simulation/templates/units/brit_hero_boudicca.xml =================================================================== --- binaries/data/mods/public/simulation/templates/units/brit_hero_boudicca.xml +++ binaries/data/mods/public/simulation/templates/units/brit_hero_boudicca.xml @@ -12,7 +12,7 @@ Chariot Boudicca (Chariot) Boadicea - female + female units/brit_hero_boudicca.png Index: binaries/data/mods/public/simulation/templates/units/brit_hero_boudicca_cavalry_javelinist.xml =================================================================== --- binaries/data/mods/public/simulation/templates/units/brit_hero_boudicca_cavalry_javelinist.xml +++ binaries/data/mods/public/simulation/templates/units/brit_hero_boudicca_cavalry_javelinist.xml @@ -7,7 +7,7 @@ brit Boudicca (Sword) Boadicea - female + female units/brit_hero_boudicca.png Index: binaries/data/mods/public/simulation/templates/units/brit_hero_boudicca_sword.xml =================================================================== --- binaries/data/mods/public/simulation/templates/units/brit_hero_boudicca_sword.xml +++ binaries/data/mods/public/simulation/templates/units/brit_hero_boudicca_sword.xml @@ -7,7 +7,7 @@ brit Boudicca (Sword) Boadicea - female + female units/brit_hero_boudicca.png Index: binaries/data/mods/public/simulation/templates/units/cart_support_healer_b.xml =================================================================== --- binaries/data/mods/public/simulation/templates/units/cart_support_healer_b.xml +++ binaries/data/mods/public/simulation/templates/units/cart_support_healer_b.xml @@ -2,7 +2,7 @@ cart - female + female units/cart_support_healer_b Kehinit units/cart_support_healer.png Index: binaries/data/mods/public/simulation/templates/units/iber_support_healer_b.xml =================================================================== --- binaries/data/mods/public/simulation/templates/units/iber_support_healer_b.xml +++ binaries/data/mods/public/simulation/templates/units/iber_support_healer_b.xml @@ -2,7 +2,7 @@ iber - female + female units/iber_support_healer_b Priestess of Ataekina Emakumezko Apaiz de Ataekina Index: binaries/data/mods/public/simulation/templates/units/kush_hero_amanirenas.xml =================================================================== --- binaries/data/mods/public/simulation/templates/units/kush_hero_amanirenas.xml +++ binaries/data/mods/public/simulation/templates/units/kush_hero_amanirenas.xml @@ -7,7 +7,7 @@ kush Amanirenas Amnirense qore li kdwe li - female + female units/kush_hero_amanirenas.png Index: binaries/data/mods/public/simulation/templates/units/kush_hero_amanirenas_chariot.xml =================================================================== --- binaries/data/mods/public/simulation/templates/units/kush_hero_amanirenas_chariot.xml +++ binaries/data/mods/public/simulation/templates/units/kush_hero_amanirenas_chariot.xml @@ -7,7 +7,7 @@ kush Amanirenas Amnirense qore li kdwe li - female + female units/kush_hero_amanirenas.png Index: binaries/data/mods/public/simulation/templates/units/maur_champion_maiden.xml =================================================================== --- binaries/data/mods/public/simulation/templates/units/maur_champion_maiden.xml +++ binaries/data/mods/public/simulation/templates/units/maur_champion_maiden.xml @@ -2,7 +2,7 @@ maur - female + female Maiden Guard Visha Kanya units/maur_champion_maiden Index: binaries/data/mods/public/simulation/templates/units/maur_champion_maiden_archer.xml =================================================================== --- binaries/data/mods/public/simulation/templates/units/maur_champion_maiden_archer.xml +++ binaries/data/mods/public/simulation/templates/units/maur_champion_maiden_archer.xml @@ -2,7 +2,7 @@ maur - female + female Maiden Guard Archer Visha Kanya units/maur_champion_maiden_archer.png Index: binaries/data/mods/public/simulation/templates/units/ptol_hero_cleopatra.xml =================================================================== --- binaries/data/mods/public/simulation/templates/units/ptol_hero_cleopatra.xml +++ binaries/data/mods/public/simulation/templates/units/ptol_hero_cleopatra.xml @@ -7,7 +7,7 @@ ptol - female + female Cleopatra VII Kleopatra H' Philopator units/ptol_hero_cleopatra.png Index: source/simulation2/components/CCmpVisualActor.cpp =================================================================== --- source/simulation2/components/CCmpVisualActor.cpp +++ source/simulation2/components/CCmpVisualActor.cpp @@ -23,6 +23,7 @@ #include "simulation2/MessageTypes.h" #include "ICmpFootprint.h" +#include "ICmpIdentity.h" #include "ICmpUnitRenderer.h" #include "ICmpOwnership.h" #include "ICmpPosition.h" @@ -59,6 +60,7 @@ componentManager.SubscribeToMessageType(MT_OwnershipChanged); componentManager.SubscribeToMessageType(MT_ValueModification); componentManager.SubscribeToMessageType(MT_TerrainChanged); + componentManager.SubscribeToMessageType(MT_Create); componentManager.SubscribeToMessageType(MT_Destroy); } @@ -70,6 +72,7 @@ // Not initialized in non-visual mode CUnit* m_Unit; + CModelAbstract::CustomSelectionShape* m_ShapeDescriptor = nullptr; fixed m_R, m_G, m_B; // shading color @@ -91,6 +94,10 @@ bool m_VisibleInAtlasOnly; bool m_IsActorOnly; // an in-world entity should not have this or it might not be rendered. + bool m_SilhouetteDisplay; + bool m_SilhouetteOccluder; + bool m_DisableShadows; + ICmpUnitRenderer::tag_t m_ModelTag; public: @@ -195,17 +202,23 @@ m_Seed = GetEntityId(); m_IsFoundationActor = paramNode.GetChild("Foundation").IsOk() && paramNode.GetChild("FoundationActor").IsOk(); - if (m_IsFoundationActor) - m_BaseActorName = m_ActorName = paramNode.GetChild("FoundationActor").ToString(); - else - m_BaseActorName = m_ActorName = paramNode.GetChild("Actor").ToString(); + + m_BaseActorName = paramNode.GetChild(m_IsFoundationActor ? "FoundationActor" : "Actor").ToString(); + ParseActorName(m_BaseActorName); m_VisibleInAtlasOnly = paramNode.GetChild("VisibleInAtlasOnly").ToBool(); m_IsActorOnly = paramNode.GetChild("ActorOnly").IsOk(); - InitModel(paramNode); - - SelectAnimation("idle"); + m_SilhouetteDisplay = paramNode.GetChild("SilhouetteDisplay").ToBool(); + m_SilhouetteOccluder = paramNode.GetChild("SilhouetteOccluder").ToBool(); + m_DisableShadows = paramNode.GetChild("DisableShadows").ToBool(); + + // Initialize the model's selection shape descriptor. This currently relies on the component initialization order; the + // Footprint component must be initialized before this component (VisualActor) to support the ability to use the footprint + // shape for the selection box (instead of the default recursive bounding box). See TypeList.h for the order in + // which components are initialized; if for whatever reason you need to get rid of this dependency, you can always just + // initialize the selection shape descriptor on-demand. + InitSelectionShapeDescriptor(paramNode); } virtual void Deinit() @@ -260,6 +273,9 @@ SerializeCommon(deserialize); + InitModel(); + SelectAnimation("idle"); + // If we serialized a different seed or different actor, reload actor if (oldSeed != GetActorSeed() || m_BaseActorName != m_ActorName) ReloadActor(); @@ -309,7 +325,7 @@ newActorName = cmpValueModificationManager->ApplyModifications(L"VisualActor/Actor", m_BaseActorName, GetEntityId()); if (newActorName != m_ActorName) { - m_ActorName = newActorName; + ParseActorName(newActorName); ReloadActor(); } break; @@ -324,6 +340,13 @@ } break; } + case MT_Create: + { + InitModel(); + + SelectAnimation("idle"); + break; + } case MT_Destroy: { if (m_ModelTag.valid()) @@ -523,8 +546,11 @@ } private: + // Replace {phenotype} with the correct value in m_ActorName + void ParseActorName(std::wstring base); + /// Helper function shared by component init and actor reloading - void InitModel(const CParamNode& paramNode); + void InitModel(); /// Helper method; initializes the model selection shape descriptor from XML. Factored out for readability of @ref Init. void InitSelectionShapeDescriptor(const CParamNode& paramNode); @@ -540,7 +566,24 @@ // ------------------------------------------------------------------------------------------------------------------ -void CCmpVisualActor::InitModel(const CParamNode& paramNode) +void CCmpVisualActor::ParseActorName(std::wstring base) +{ + CmpPtr cmpIdentity(GetEntityHandle()); + const std::wstring pattern = L"{phenotype}"; + if (cmpIdentity) + { + size_t pos = base.find(pattern); + while (pos != std::string::npos) + { + base.replace(pos, pattern.size(), cmpIdentity->GetPhenotype()); + pos = base.find(pattern, pos + pattern.size()); + } + } + + m_ActorName = base; +} + +void CCmpVisualActor::InitModel() { if (!GetSimContext().HasUnitManager()) return; @@ -558,10 +601,10 @@ { u32 modelFlags = 0; - if (paramNode.GetChild("SilhouetteDisplay").ToBool()) + if (m_SilhouetteDisplay) modelFlags |= MODELFLAG_SILHOUETTE_DISPLAY; - if (paramNode.GetChild("SilhouetteOccluder").ToBool()) + if (m_SilhouetteOccluder) modelFlags |= MODELFLAG_SILHOUETTE_OCCLUDER; CmpPtr cmpVisibility(GetEntityHandle()); @@ -571,7 +614,7 @@ model.ToCModel()->AddFlagsRec(modelFlags); } - if (paramNode.GetChild("DisableShadows").IsOk()) + if (m_DisableShadows) { if (model.ToCModel()) model.ToCModel()->RemoveShadowsRec(); @@ -579,13 +622,6 @@ model.ToCModelDecal()->RemoveShadows(); } - // Initialize the model's selection shape descriptor. This currently relies on the component initialization order; the - // Footprint component must be initialized before this component (VisualActor) to support the ability to use the footprint - // shape for the selection box (instead of the default recursive bounding box). See TypeList.h for the order in - // which components are initialized; if for whatever reason you need to get rid of this dependency, you can always just - // initialize the selection shape descriptor on-demand. - InitSelectionShapeDescriptor(paramNode); - m_Unit->SetID(GetEntityId()); bool floating = m_Unit->GetObject().m_Base->m_Properties.m_FloatOnWater; @@ -612,12 +648,16 @@ m_ModelTag = cmpModelRenderer->AddUnit(GetEntityHandle(), m_Unit, boundSphere, flags); } } + + // the model is now responsible for cleaning up the descriptor + if (m_ShapeDescriptor != nullptr) + m_Unit->GetModel().SetCustomSelectionShape(m_ShapeDescriptor); } void CCmpVisualActor::InitSelectionShapeDescriptor(const CParamNode& paramNode) { // by default, we don't need a custom selection shape and we can just keep the default behaviour - CModelAbstract::CustomSelectionShape* shapeDescriptor = NULL; + m_ShapeDescriptor = nullptr; const CParamNode& shapeNode = paramNode.GetChild("SelectionShape"); if (shapeNode.IsOk()) @@ -649,11 +689,11 @@ size1 *= 2; } - shapeDescriptor = new CModelAbstract::CustomSelectionShape; - shapeDescriptor->m_Type = CModelAbstract::CustomSelectionShape::BOX; - shapeDescriptor->m_Size0 = size0; - shapeDescriptor->m_Size1 = size1; - shapeDescriptor->m_Height = fpHeight.ToFloat(); + m_ShapeDescriptor = new CModelAbstract::CustomSelectionShape; + m_ShapeDescriptor->m_Type = CModelAbstract::CustomSelectionShape::BOX; + m_ShapeDescriptor->m_Size0 = size0; + m_ShapeDescriptor->m_Size1 = size1; + m_ShapeDescriptor->m_Height = fpHeight.ToFloat(); } else { @@ -663,11 +703,11 @@ else if (shapeNode.GetChild("Box").IsOk()) { // TODO: we might need to support the ability to specify a different box center in the future - shapeDescriptor = new CModelAbstract::CustomSelectionShape; - shapeDescriptor->m_Type = CModelAbstract::CustomSelectionShape::BOX; - shapeDescriptor->m_Size0 = shapeNode.GetChild("Box").GetChild("@width").ToFixed().ToFloat(); - shapeDescriptor->m_Size1 = shapeNode.GetChild("Box").GetChild("@depth").ToFixed().ToFloat(); - shapeDescriptor->m_Height = shapeNode.GetChild("Box").GetChild("@height").ToFixed().ToFloat(); + m_ShapeDescriptor = new CModelAbstract::CustomSelectionShape; + m_ShapeDescriptor->m_Type = CModelAbstract::CustomSelectionShape::BOX; + m_ShapeDescriptor->m_Size0 = shapeNode.GetChild("Box").GetChild("@width").ToFixed().ToFloat(); + m_ShapeDescriptor->m_Size1 = shapeNode.GetChild("Box").GetChild("@depth").ToFixed().ToFloat(); + m_ShapeDescriptor->m_Height = shapeNode.GetChild("Box").GetChild("@height").ToFixed().ToFloat(); } else if (shapeNode.GetChild("Cylinder").IsOk()) { @@ -679,10 +719,6 @@ LOGERROR("[VisualActor] No selection shape specified"); } } - - ENSURE(m_Unit); - // the model is now responsible for cleaning up the descriptor - m_Unit->GetModel().SetCustomSelectionShape(shapeDescriptor); } void CCmpVisualActor::ReloadActor() @@ -703,7 +739,9 @@ const CParamNode* node = cmpTemplateManager->LoadLatestTemplate(GetEntityId()); ENSURE(node && node->GetChild("VisualActor").IsOk()); - InitModel(node->GetChild("VisualActor")); + InitSelectionShapeDescriptor(node->GetChild("VisualActor")); + + InitModel(); ReloadUnitAnimation(); Index: source/simulation2/components/ICmpIdentity.h =================================================================== --- source/simulation2/components/ICmpIdentity.h +++ source/simulation2/components/ICmpIdentity.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2011 Wildfire Games. +/* Copyright (C) 2019 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -29,6 +29,8 @@ public: virtual std::string GetSelectionGroupName() = 0; + virtual std::wstring GetPhenotype() = 0; + DECLARE_INTERFACE_TYPE(Identity) }; Index: source/simulation2/components/ICmpIdentity.cpp =================================================================== --- source/simulation2/components/ICmpIdentity.cpp +++ source/simulation2/components/ICmpIdentity.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2011 Wildfire Games. +/* Copyright (C) 2019 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -35,6 +35,11 @@ { return m_Script.Call("GetSelectionGroupName"); } + + virtual std::wstring GetPhenotype() + { + return m_Script.Call("GetPhenotype"); + } }; REGISTER_COMPONENT_SCRIPT_WRAPPER(IdentityScripted)