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,15 @@ "" + "" + "" + - "" + + "" + + "" + + "tokens" + + "" + + "" + + "" + + "" + + "" + + "" + "" + "" + "" + @@ -95,14 +103,21 @@ { this.classesList = GetIdentityClasses(this.template); this.visibleClassesList = GetVisibleIdentityClasses(this.template); + this.SetPhenotype(); }; -Identity.prototype.Deserialize = function () +Identity.prototype.Deserialize = function(data) { this.Init(); + this.phenotype = data.phenotype; }; -Identity.prototype.Serialize = null; // we have no dynamic state to save +Identity.prototype.Serialize = function() +{ + return { + "phenotype": this.phenotype + }; +}; Identity.prototype.GetCiv = function() { @@ -114,9 +129,25 @@ return this.template.Lang || "greek"; // ugly default }; -Identity.prototype.GetGender = function() +Identity.prototype.GetPossiblePhenotypes = function() +{ + return !!this.template.PossiblePhenotypes ? this.template.PossiblePhenotypes._string.split(/\s+/) : ["none"]; +}; + +Identity.prototype.SetPhenotype = function(newPhenotype = "none") +{ + if (newPhenotype == this.phenotype) + return; + + if (!this.template.Phenotype) + this.phenotype = "male"; // ugly default + else + this.phenotype = this.template.Phenotype == "random" ? pickRandom(this.GetPossiblePhenotypes()) : this.template.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": "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": "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"]); 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 @@ -1,4 +1,4 @@ -/* Copyright (C) 2018 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 @@ -23,6 +23,7 @@ #include "simulation2/MessageTypes.h" #include "ICmpFootprint.h" +#include "ICmpIdentity.h" #include "ICmpUnitRenderer.h" #include "ICmpOwnership.h" #include "ICmpPosition.h" @@ -35,6 +36,7 @@ #include "simulation2/serialization/SerializeTemplates.h" +#include #include "graphics/Decal.h" #include "graphics/Frustum.h" #include "graphics/Model.h" @@ -202,7 +204,17 @@ if (m_IsFoundationActor) m_BaseActorName = m_ActorName = paramNode.GetChild("FoundationActor").ToString(); else - m_BaseActorName = m_ActorName = paramNode.GetChild("Actor").ToString(); + { + std::wstring baseActorString = paramNode.GetChild("Actor").ToString(); + + CmpPtr cmpIdentity(GetEntityHandle()); + const std::wstring pattern = L"{phenotype}"; + auto patternPos = baseActorString.find(pattern); + if (patternPos != std::wstring::npos) + boost::replace_all(baseActorString , pattern, cmpIdentity->GetPhenotype()); + + m_BaseActorName = m_ActorName = baseActorString; + } m_VisibleInAtlasOnly = paramNode.GetChild("VisibleInAtlasOnly").ToBool(); m_IsActorOnly = paramNode.GetChild("ActorOnly").IsOk(); 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)