Ticket #3286: easy_switch_animations.2.diff

File easy_switch_animations.2.diff, 27.3 KB (added by sanderd17, 9 years ago)
  • binaries/data/mods/public/art/actors/actor.rnc

     
    99    element group {
    1010        element variant {
    1111            attribute name { text }? &
     12            attribute file { text }? &
    1213            attribute frequency { xsd:nonNegativeInteger }? &
    1314            element mesh {
    1415                text
  • binaries/data/mods/public/art/actors/actor.rng

     
    1919                <attribute name="name"/>
    2020              </optional>
    2121              <optional>
     22                <attribute name="file"/>
     23              </optional>
     24              <optional>
    2225                <attribute name="frequency">
    2326                  <data type="nonNegativeInteger"/>
    2427                </attribute>
  • binaries/data/mods/public/art/actors/units/athenians/infantry_archer_b.xml

     
    66      <animations>
    77        <animation file="biped/inf_sword_ready_a.dae" name="Idle" speed="100"/>
    88        <animation file="biped/inf_sword_ready_a.dae" name="Idle" speed="97"/>
    9         <animation event="0.4" file="infantry/sword/attack/isw_s_def_01.psa" name="attack_capture" speed="100"/>
    10         <animation event="0.4" file="infantry/sword/attack/isw_s_def_06.psa" name="attack_capture" speed="100"/>
    11         <animation event="0.2" file="infantry/sword/attack/isw_s_em_04.psa" name="attack_capture" speed="100"/>
    129        <animation event="0.5" file="infantry/sword/attack/isw_s_off_05.psa" name="attack_slaughter" speed="100"/>
    1310        <animation event="0.84" file="biped/inf_arch_atk_a.psa" load="0.16" name="attack_ranged" speed="90"/>
    1411        <animation file="infantry/general/dude/dudewalk.psa" name="Walk" speed="100"/>
     
    4441  </group>
    4542  <group>
    4643    <variant frequency="100" name="Idle"/>
    47     <variant name="attack_capture">
    48       <props>
    49         <prop actor="props/units/tools/pitchfork.xml" attachpoint="r_hand"/>
    50       </props>
    51     </variant>
     44    <variant file="biped/attack_capture.xml"/>
    5245    <variant name="attack_ranged">
    5346      <props>
    5447        <prop actor="props/units/weapons/bow_short.xml" attachpoint="l_hand"/>
  • binaries/data/mods/public/art/actors/units/athenians/infantry_javelinist_b.xml

     
    55    <variant frequency="100" name="Base">
    66      <animations>
    77        <animation file="infantry/general/dude/dudeidle.psa" name="Idle" speed="100"/>
    8         <animation event="0.4" file="infantry/sword/attack/isw_s_def_01.psa" name="attack_capture" speed="100"/>
    9         <animation event="0.4" file="infantry/sword/attack/isw_s_def_06.psa" name="attack_capture" speed="100"/>
    10         <animation event="0.2" file="infantry/sword/attack/isw_s_em_04.psa" name="attack_capture" speed="100"/>
    118        <animation event="0.5" file="infantry/javelin/attack/ijv_off_01.psa" load="0" name="attack_ranged" speed="75"/>
    129        <animation event="0.5" file="infantry/sword/attack/isw_s_off_05.psa" name="attack_slaughter" speed="100"/>
    1310        <animation file="biped/walk_spearshield.psa" name="Walk" speed="120"/>
     
    4845  </group>
    4946  <group>
    5047    <variant frequency="100" name="Idle"/>
    51     <variant name="attack_capture">
    52       <props>
    53         <prop actor="props/units/tools/pitchfork.xml" attachpoint="r_hand"/>
    54       </props>
    55     </variant>
     48    <variant file="biped/attack_capture.xml"/>
    5649    <variant name="attack_ranged">
    5750      <props>
    5851        <prop attachpoint="r_hand"/>
  • binaries/data/mods/public/art/actors/units/athenians/infantry_slinger_b.xml

     
    1111        <animation file="biped/walk_spearshield.psa" name="carry_wood" speed="120"/>
    1212        <animation file="biped/walk_spearshield.psa" name="carry_stone" speed="120"/>
    1313        <animation file="biped/walk_spearshield.psa" name="carry_metal" speed="120"/>
    14         <animation event="0.4" file="infantry/sword/attack/isw_s_def_01.psa" name="attack_capture" speed="100"/>
    15         <animation event="0.4" file="infantry/sword/attack/isw_s_def_06.psa" name="attack_capture" speed="100"/>
    16         <animation event="0.2" file="infantry/sword/attack/isw_s_em_04.psa" name="attack_capture" speed="100"/>
    1714
    1815        <animation event="0.5" file="biped/inf_sling_atk_a.psa" name="attack_ranged" speed="30"/>
    1916        <animation event="0.5" file="infantry/sword/attack/isw_s_off_05.psa" name="attack_slaughter" speed="100"/>
     
    4643  </group>
    4744  <group>
    4845    <variant frequency="1" name="Idle"/>
    49     <variant name="attack_capture">
    50       <props>
    51         <prop actor="props/units/tools/pitchfork.xml" attachpoint="r_hand"/>
    52       </props>
    53     </variant>
     46    <variant file="biped/attack_capture.xml"/>
    5447    <variant name="attack_slaughter">
    5548      <props>
    5649        <prop actor="props/units/weapons/knife.xml" attachpoint="r_hand"/>
  • binaries/data/mods/public/art/actors/units/athenians/infantry_spearman_b.xml

     
    1212        <animation file="biped/walk_spearshield.psa" name="carry_wood" speed="120"/>
    1313        <animation file="biped/walk_spearshield.psa" name="carry_stone" speed="120"/>
    1414        <animation file="biped/walk_spearshield.psa" name="carry_metal" speed="120"/>
    15         <animation event="0.4" file="infantry/sword/attack/isw_s_def_01.psa" name="attack_capture" speed="100"/>
    16         <animation event="0.4" file="infantry/sword/attack/isw_s_def_06.psa" name="attack_capture" speed="100"/>
    17         <animation event="0.2" file="infantry/sword/attack/isw_s_em_04.psa" name="attack_capture" speed="100"/>
    1815        <animation event="0.5" file="biped/inf_hoplite_atk_a.psa" name="attack_melee" speed="200"/>
    1916        <animation event="0.5" file="biped/inf_hoplite_atk_a.psa" name="attack_slaughter" speed="200"/>
    2017        <animation event="0.23" file="infantry/general/chop.psa" name="gather_tree" speed="250"/>
     
    5552  </group>
    5653  <group>
    5754    <variant frequency="1" name="Idle"/>
    58     <variant name="attack_capture">
    59       <props>
    60         <prop actor="props/units/tools/pitchfork.xml" attachpoint="r_hand"/>
    61       </props>
    62     </variant>
     55    <variant file="biped/attack_capture.xml"/>
    6356    <variant name="attack_melee">
    6457      <props>
    6558        <prop actor="props/units/weapons/spear_hoplite.xml" attachpoint="r_hand"/>
  • binaries/data/mods/public/art/variants/biped/attack_capture.xml

     
     1<variant name="attack_capture">
     2  <animations>
     3    <animation event="0.4" file="infantry/sword/attack/isw_s_def_01.psa" name="attack_capture" speed="100"/>
     4    <animation event="0.4" file="infantry/sword/attack/isw_s_def_06.psa" name="attack_capture" speed="100"/>
     5    <animation event="0.2" file="infantry/sword/attack/isw_s_em_04.psa" name="attack_capture" speed="100"/>
     6  </animations>
     7  <props>
     8    <prop actor="props/units/tools/pitchfork.xml" attachpoint="r_hand"/>
     9  </props>
     10</variant>
  • binaries/data/mods/public/art/variants/variant.rnc

     
     1namespace a = "http://relaxng.org/ns/compatibility/annotations/1.0"
     2##
     3# NOTE: To modify this Relax NG grammar, edit the Relax NG Compact (.rnc) file
     4#   and use a converter tool like trang to generate the Relax NG XML (.rng) file
     5##
     6
     7element variant {
     8    attribute name { text }? &
     9    attribute frequency { xsd:nonNegativeInteger }? &
     10    element mesh {
     11        text
     12    }? &
     13    element textures {
     14        element texture {
     15            attribute file { text }? &
     16            attribute name { text }
     17        }*
     18    }? &
     19    element decal {
     20        attribute width { xsd:float } &  # X
     21        attribute depth { xsd:float } &  # Z
     22        attribute angle { xsd:float } &
     23        attribute offsetx { xsd:float } &
     24        attribute offsetz { xsd:float }
     25    }? &
     26    element particles {
     27        attribute file { text }
     28    }? &
     29    element color { list {
     30        xsd:nonNegativeInteger, # R
     31        xsd:nonNegativeInteger, # G
     32        xsd:nonNegativeInteger # B
     33    } }? &
     34    element animations {
     35        element animation {
     36            attribute name { text } &
     37            attribute file { text }? &
     38            attribute speed { xsd:nonNegativeInteger } &
     39            attribute event { xsd:decimal { minInclusive = "0" maxInclusive = "1" } }? &
     40            attribute load { xsd:decimal { minInclusive = "0" maxInclusive = "1" } }? &
     41            attribute sound { xsd:decimal { minInclusive = "0" maxInclusive = "1" } }?
     42        }*
     43    }? &
     44    element props {
     45        element prop {
     46            (attribute actor { text }? &
     47            attribute attachpoint { text } &
     48            attribute minheight { xsd:float }? &
     49            attribute maxheight { xsd:float }? &
     50            attribute selectable { "true" | "false" }?)
     51        }*
     52    }?
     53}
     54
  • binaries/data/mods/public/art/variants/variant.rng

     
     1<?xml version="1.0" encoding="UTF-8"?>
     2<element name="variant" xmlns:a="http://relaxng.org/ns/compatibility/annotations/1.0" xmlns="http://relaxng.org/ns/structure/1.0" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
     3<a:documentation/>
     4<!--
     5NOTE: To modify this Relax NG grammar, edit the Relax NG Compact (.rnc) file
     6  and use a converter tool like trang to generate the Relax NG XML (.rng) file
     7-->
     8<a:documentation/>
     9<interleave>
     10  <optional>
     11    <attribute name="name"/>
     12  </optional>
     13  <optional>
     14    <attribute name="frequency">
     15      <data type="nonNegativeInteger"/>
     16    </attribute>
     17  </optional>
     18  <optional>
     19    <element name="mesh">
     20      <text/>
     21    </element>
     22  </optional>
     23  <optional>
     24    <element name="textures">
     25      <zeroOrMore>
     26        <element name="texture">
     27          <interleave>
     28            <optional>
     29              <attribute name="file"/>
     30            </optional>
     31            <attribute name="name"/>
     32          </interleave>
     33        </element>
     34      </zeroOrMore>
     35    </element>
     36  </optional>
     37  <optional>
     38    <element name="decal">
     39      <interleave>
     40        <attribute name="width">
     41          <data type="float"/>
     42        </attribute>
     43        <!-- X -->
     44        <attribute name="depth">
     45          <data type="float"/>
     46        </attribute>
     47        <!-- Z -->
     48        <attribute name="angle">
     49          <data type="float"/>
     50        </attribute>
     51        <attribute name="offsetx">
     52          <data type="float"/>
     53        </attribute>
     54        <attribute name="offsetz">
     55          <data type="float"/>
     56        </attribute>
     57      </interleave>
     58    </element>
     59  </optional>
     60  <optional>
     61    <element name="particles">
     62      <attribute name="file"/>
     63    </element>
     64  </optional>
     65  <optional>
     66    <element name="color">
     67      <list>
     68        <group>
     69          <data type="nonNegativeInteger"/>
     70          <!-- R -->
     71          <data type="nonNegativeInteger"/>
     72          <!-- G -->
     73          <data type="nonNegativeInteger"/>
     74        </group>
     75        <!-- B -->
     76      </list>
     77    </element>
     78  </optional>
     79  <optional>
     80    <element name="animations">
     81      <zeroOrMore>
     82        <element name="animation">
     83          <interleave>
     84            <attribute name="name"/>
     85            <optional>
     86              <attribute name="file"/>
     87            </optional>
     88            <attribute name="speed">
     89              <data type="nonNegativeInteger"/>
     90            </attribute>
     91            <optional>
     92              <attribute name="event">
     93                <data type="decimal">
     94                  <param name="minInclusive">0</param>
     95                  <param name="maxInclusive">1</param>
     96                </data>
     97              </attribute>
     98            </optional>
     99            <optional>
     100              <attribute name="load">
     101                <data type="decimal">
     102                  <param name="minInclusive">0</param>
     103                  <param name="maxInclusive">1</param>
     104                </data>
     105              </attribute>
     106            </optional>
     107            <optional>
     108              <attribute name="sound">
     109                <data type="decimal">
     110                  <param name="minInclusive">0</param>
     111                  <param name="maxInclusive">1</param>
     112                </data>
     113              </attribute>
     114            </optional>
     115          </interleave>
     116        </element>
     117      </zeroOrMore>
     118    </element>
     119  </optional>
     120  <optional>
     121    <element name="props">
     122      <zeroOrMore>
     123        <element name="prop">
     124          <interleave>
     125            <optional>
     126              <attribute name="actor"/>
     127            </optional>
     128            <attribute name="attachpoint"/>
     129            <optional>
     130              <attribute name="minheight">
     131                <data type="float"/>
     132              </attribute>
     133            </optional>
     134            <optional>
     135              <attribute name="maxheight">
     136                <data type="float"/>
     137              </attribute>
     138            </optional>
     139            <optional>
     140              <attribute name="selectable">
     141                <choice>
     142                  <value>true</value>
     143                  <value>false</value>
     144                </choice>
     145              </attribute>
     146            </optional>
     147          </interleave>
     148        </element>
     149      </zeroOrMore>
     150    </element>
     151  </optional>
     152</interleave>
     153</element>
  • source/graphics/ObjectBase.cpp

    Property changes on: binaries/data/mods/public/art/variants/variant.rng
    ___________________________________________________________________
    Added: svn:mime-type
    ## -0,0 +1 ##
    +text/xml
    \ No newline at end of property
     
    3838    m_Properties.m_FloatOnWater = false;
    3939}
    4040
     41void CObjectBase::LoadVariant(const CXeromyces& XeroFile, const XMBElement& variant, Variant& currentVariant)
     42{
     43    #define EL(x) int el_##x = XeroFile.GetElementID(#x)
     44    #define AT(x) int at_##x = XeroFile.GetAttributeID(#x)
     45    EL(animation);
     46    EL(animations);
     47    EL(color);
     48    EL(decal);
     49    EL(mesh);
     50    EL(particles);
     51    EL(prop);
     52    EL(props);
     53    EL(texture);
     54    EL(textures);
     55    EL(variant);
     56    AT(actor);
     57    AT(angle);
     58    AT(attachpoint);
     59    AT(depth);
     60    AT(event);
     61    AT(file);
     62    AT(frequency);
     63    AT(load);
     64    AT(maxheight);
     65    AT(minheight);
     66    AT(name);
     67    AT(offsetx);
     68    AT(offsetz);
     69    AT(selectable);
     70    AT(sound);
     71    AT(speed);
     72    AT(width);
     73    #undef AT
     74    #undef EL
     75
     76    if (variant.GetNodeName() != el_variant)
     77    {
     78        LOGERROR("Invalid variant format in (unrecognised root element '%s')", XeroFile.GetElementString(variant.GetNodeName()).c_str());
     79        return;
     80    }
     81
     82    XERO_ITER_ATTR(variant, attr)
     83    {
     84        if (attr.Name == at_name)
     85            currentVariant.m_VariantName = attr.Value.LowerCase();
     86        else if (attr.Name == at_frequency)
     87            currentVariant.m_Frequency = attr.Value.ToInt();
     88    }
     89
     90    XERO_ITER_EL(variant, option)
     91    {
     92        int option_name = option.GetNodeName();
     93
     94        if (option_name == el_mesh)
     95        {
     96            currentVariant.m_ModelFilename = VfsPath("art/meshes") / option.GetText().FromUTF8();
     97        }
     98        else if (option_name == el_textures)
     99        {
     100            XERO_ITER_EL(option, textures_element)
     101            {
     102                ENSURE(textures_element.GetNodeName() == el_texture);
     103               
     104                Samp samp;
     105                XERO_ITER_ATTR(textures_element, se)
     106                {
     107                    if (se.Name == at_file)
     108                        samp.m_SamplerFile = VfsPath("art/textures/skins") / se.Value.FromUTF8();
     109                    else if (se.Name == at_name)
     110                        samp.m_SamplerName = CStrIntern(se.Value);
     111                }
     112                currentVariant.m_Samplers.push_back(samp);
     113            }
     114        }
     115        else if (option_name == el_decal)
     116        {
     117            XMBAttributeList attrs = option.GetAttributes();
     118            Decal decal;
     119            decal.m_SizeX = attrs.GetNamedItem(at_width).ToFloat();
     120            decal.m_SizeZ = attrs.GetNamedItem(at_depth).ToFloat();
     121            decal.m_Angle = DEGTORAD(attrs.GetNamedItem(at_angle).ToFloat());
     122            decal.m_OffsetX = attrs.GetNamedItem(at_offsetx).ToFloat();
     123            decal.m_OffsetZ = attrs.GetNamedItem(at_offsetz).ToFloat();
     124            currentVariant.m_Decal = decal;
     125        }
     126        else if (option_name == el_particles)
     127        {
     128            XMBAttributeList attrs = option.GetAttributes();
     129            VfsPath file = VfsPath("art/particles") / attrs.GetNamedItem(at_file).FromUTF8();
     130            currentVariant.m_Particles = file;
     131
     132            // For particle hotloading, it's easiest to reload the entire actor,
     133            // so remember the relevant particle file as a dependency for this actor
     134            m_UsedFiles.insert(file);
     135        }
     136        else if (option_name == el_color)
     137        {
     138            currentVariant.m_Color = option.GetText();
     139        }
     140        else if (option_name == el_animations)
     141        {
     142            XERO_ITER_EL(option, anim_element)
     143            {
     144                ENSURE(anim_element.GetNodeName() == el_animation);
     145
     146                Anim anim;
     147                XERO_ITER_ATTR(anim_element, ae)
     148                {
     149                    if (ae.Name == at_name)
     150                        anim.m_AnimName = ae.Value;
     151                    else if (ae.Name == at_file)
     152                        anim.m_FileName = VfsPath("art/animation") / ae.Value.FromUTF8();
     153                    else if (ae.Name == at_speed)
     154                        anim.m_Speed = ae.Value.ToInt() > 0 ? ae.Value.ToInt() / 100.f : 1.f;
     155                    else if (ae.Name == at_event)
     156                        anim.m_ActionPos = clamp(ae.Value.ToFloat(), 0.f, 1.f);
     157                    else if (ae.Name == at_load)
     158                        anim.m_ActionPos2 = clamp(ae.Value.ToFloat(), 0.f, 1.f);
     159                    else if (ae.Name == at_sound)
     160                        anim.m_SoundPos = clamp(ae.Value.ToFloat(), 0.f, 1.f);
     161                }
     162                currentVariant.m_Anims.push_back(anim);
     163            }
     164
     165        }
     166        else if (option_name == el_props)
     167        {
     168            XERO_ITER_EL(option, prop_element)
     169            {
     170                ENSURE(prop_element.GetNodeName() == el_prop);
     171
     172                Prop prop;
     173                XERO_ITER_ATTR(prop_element, pe)
     174                {
     175                    if (pe.Name == at_attachpoint)
     176                        prop.m_PropPointName = pe.Value;
     177                    else if (pe.Name == at_actor)
     178                        prop.m_ModelName = pe.Value.FromUTF8();
     179                    else if (pe.Name == at_minheight)
     180                        prop.m_minHeight = pe.Value.ToFloat();
     181                    else if (pe.Name == at_maxheight)
     182                        prop.m_maxHeight = pe.Value.ToFloat();
     183                    else if (pe.Name == at_selectable)
     184                        prop.m_selectable = pe.Value != "false";
     185                }
     186                currentVariant.m_Props.push_back(prop);
     187            }
     188        }
     189    }
     190}
     191
    41192bool CObjectBase::Load(const VfsPath& pathname)
    42193{
    43194    m_UsedFiles.clear();
     
    53204    EL(actor);
    54205    EL(castshadow);
    55206    EL(float);
     207    EL(group);
    56208    EL(material);
    57     EL(group);
    58209    EL(variant);
    59     EL(animations);
    60     EL(animation);
    61     EL(props);
    62     EL(prop);
    63     EL(mesh);
    64     EL(texture);
    65     EL(textures);
    66     EL(color);
    67     EL(decal);
    68     EL(particles);
    69210    AT(file);
    70     AT(name);
    71     AT(speed);
    72     AT(event);
    73     AT(load);
    74     AT(sound);
    75     AT(attachpoint);
    76     AT(actor);
    77     AT(frequency);
    78     AT(width);
    79     AT(depth);
    80     AT(angle);
    81     AT(offsetx);
    82     AT(offsetz);
    83     AT(minheight);
    84     AT(maxheight);
    85     AT(selectable);
    86211    #undef AT
    87212    #undef EL
    88213
     
    94219        return false;
    95220    }
    96221
    97 
    98222    m_VariantGroups.clear();
    99223
    100224    m_Pathname = pathname;
     
    135259                ENSURE(variant.GetNodeName() == el_variant);
    136260                XERO_ITER_ATTR(variant, attr)
    137261                {
    138                     if (attr.Name == at_name)
    139                         currentVariant->m_VariantName = attr.Value.LowerCase();
    140 
    141                     else if (attr.Name == at_frequency)
    142                         currentVariant->m_Frequency = attr.Value.ToInt();
    143                 }
    144 
    145                 XERO_ITER_EL(variant, option)
    146                 {
    147                     int option_name = option.GetNodeName();
    148 
    149                     if (option_name == el_mesh)
     262                    if (attr.Name == at_file)
    150263                    {
    151                         currentVariant->m_ModelFilename = VfsPath("art/meshes") / option.GetText().FromUTF8();
    152                     }
    153                     else if (option_name == el_textures)
    154                     {
    155                         XERO_ITER_EL(option, textures_element)
     264                        // Open up an external file to load.
     265                        // Don't crash hard when failures happen, but log them and continue
     266                        m_UsedFiles.insert(attr.Value);
     267                        CXeromyces XeroVariant;
     268                        if (XeroVariant.Load(g_VFS, "art/variants/" + attr.Value) == PSRETURN_OK)
    156269                        {
    157                             ENSURE(textures_element.GetNodeName() == el_texture);
    158                            
    159                             Samp samp;
    160                             XERO_ITER_ATTR(textures_element, se)
    161                             {
    162                                 if (se.Name == at_file)
    163                                     samp.m_SamplerFile = VfsPath("art/textures/skins") / se.Value.FromUTF8();
    164                                 else if (se.Name == at_name)
    165                                     samp.m_SamplerName = CStrIntern(se.Value);
    166                             }
    167                             currentVariant->m_Samplers.push_back(samp);
     270                            XMBElement variantRoot = XeroVariant.GetRoot();
     271                            LoadVariant(XeroVariant, variantRoot, *currentVariant);
    168272                        }
     273                        else
     274                            LOGERROR("Could not open path %s", attr.Value);
    169275                    }
    170                     else if (option_name == el_decal)
    171                     {
    172                         XMBAttributeList attrs = option.GetAttributes();
    173                         Decal decal;
    174                         decal.m_SizeX = attrs.GetNamedItem(at_width).ToFloat();
    175                         decal.m_SizeZ = attrs.GetNamedItem(at_depth).ToFloat();
    176                         decal.m_Angle = DEGTORAD(attrs.GetNamedItem(at_angle).ToFloat());
    177                         decal.m_OffsetX = attrs.GetNamedItem(at_offsetx).ToFloat();
    178                         decal.m_OffsetZ = attrs.GetNamedItem(at_offsetz).ToFloat();
    179                         currentVariant->m_Decal = decal;
    180                     }
    181                     else if (option_name == el_particles)
    182                     {
    183                         XMBAttributeList attrs = option.GetAttributes();
    184                         VfsPath file = VfsPath("art/particles") / attrs.GetNamedItem(at_file).FromUTF8();
    185                         currentVariant->m_Particles = file;
    186 
    187                         // For particle hotloading, it's easiest to reload the entire actor,
    188                         // so remember the relevant particle file as a dependency for this actor
    189                         m_UsedFiles.insert(file);
    190                     }
    191                     else if (option_name == el_color)
    192                     {
    193                         currentVariant->m_Color = option.GetText();
    194                     }
    195                     else if (option_name == el_animations)
    196                     {
    197                         XERO_ITER_EL(option, anim_element)
    198                         {
    199                             ENSURE(anim_element.GetNodeName() == el_animation);
    200 
    201                             Anim anim;
    202                             XERO_ITER_ATTR(anim_element, ae)
    203                             {
    204                                 if (ae.Name == at_name)
    205                                 {
    206                                     anim.m_AnimName = ae.Value;
    207                                 }
    208                                 else if (ae.Name == at_file)
    209                                 {
    210                                     anim.m_FileName = VfsPath("art/animation") / ae.Value.FromUTF8();
    211                                 }
    212                                 else if (ae.Name == at_speed)
    213                                 {
    214                                     anim.m_Speed = ae.Value.ToInt() / 100.f;
    215                                     if (anim.m_Speed <= 0.0) anim.m_Speed = 1.0f;
    216                                 }
    217                                 else if (ae.Name == at_event)
    218                                 {
    219                                     float pos = ae.Value.ToFloat();
    220                                     anim.m_ActionPos = clamp(pos, 0.f, 1.f);
    221                                 }
    222                                 else if (ae.Name == at_load)
    223                                 {
    224                                     float pos = ae.Value.ToFloat();
    225                                     anim.m_ActionPos2 = clamp(pos, 0.f, 1.f);
    226                                 }
    227                                 else if (ae.Name == at_sound)
    228                                 {
    229                                     float pos = ae.Value.ToFloat();
    230                                     anim.m_SoundPos = clamp(pos, 0.f, 1.f);
    231                                 }
    232                             }
    233                             currentVariant->m_Anims.push_back(anim);
    234                         }
    235 
    236                     }
    237                     else if (option_name == el_props)
    238                     {
    239                         XERO_ITER_EL(option, prop_element)
    240                         {
    241                             ENSURE(prop_element.GetNodeName() == el_prop);
    242 
    243                             Prop prop;
    244                             XERO_ITER_ATTR(prop_element, pe)
    245                             {
    246                                 if (pe.Name == at_attachpoint)
    247                                     prop.m_PropPointName = pe.Value;
    248                                 else if (pe.Name == at_actor)
    249                                     prop.m_ModelName = pe.Value.FromUTF8();
    250                                 else if (pe.Name == at_minheight)
    251                                     prop.m_minHeight = pe.Value.ToFloat();
    252                                 else if (pe.Name == at_maxheight)
    253                                     prop.m_maxHeight = pe.Value.ToFloat();
    254                                 else if (pe.Name == at_selectable)
    255                                     prop.m_selectable = pe.Value != "false";
    256                             }
    257                             currentVariant->m_Props.push_back(prop);
    258                         }
    259                     }
    260276                }
    261277
     278                // Always expand the contents of this node, even if a file has
     279                // been loaded to allow for extra definitions
     280                LoadVariant(XeroFile, variant, *currentVariant);
    262281                ++currentVariant;
    263282            }
    264283
    265284            if (currentGroup->size() == 0)
    266             {
    267285                LOGERROR("Actor group has zero variants ('%s')", pathname.string8());
    268             }
    269286
    270287            ++currentGroup;
    271288        }
    272289        else if (child_name == el_castshadow)
    273         {
    274290            m_Properties.m_CastShadows = true;
    275         }
    276291        else if (child_name == el_float)
    277         {
    278292            m_Properties.m_FloatOnWater = true;
    279         }
    280293        else if (child_name == el_material)
    281         {
    282294            m_Material = VfsPath("art/materials") / child.GetText().FromUTF8();
    283         }
    284295    }
    285296
    286297    if (m_Material.empty())
  • source/graphics/ObjectBase.h

     
    2929#include "lib/file/vfs/vfs_path.h"
    3030#include "ps/CStr.h"
    3131#include "ps/CStrIntern.h"
     32#include "ps/XML/Xeromyces.h"
    3233
    3334#include <boost/random/mersenne_twister.hpp>
    3435
     
    187188    CObjectManager& m_ObjectManager;
    188189
    189190    boost::unordered_set<VfsPath> m_UsedFiles;
     191
     192    void LoadVariant(const CXeromyces& XeroFile, const XMBElement& variant, Variant& currentVariant);
    190193};
    191194
    192195#endif
  • source/tools/atlas/AtlasUI/ActorEditor/ActorEditorListCtrl.cpp

     
    4646
    4747    #undef COLOR
    4848
    49     AddColumnType(_("Variant"),     90,  "@name",       new FieldEditCtrl_Text());
    50     AddColumnType(_("Ratio"),       50,  "@frequency",  new FieldEditCtrl_Text());
    51     AddColumnType(_("Model"),       140, "mesh",        new FieldEditCtrl_File(_T("art/meshes/"), _("Mesh files (*.pmd, *.dae)|*.pmd;*.dae|All files (*.*)|*.*")));
    52     AddColumnType(_("Textures"),        250, "textures",    new FieldEditCtrl_Dialog(&TexListEditor::Create));
    53     AddColumnType(_("Animations"),      250, "animations",  new FieldEditCtrl_Dialog(&AnimListEditor::Create));
    54     AddColumnType(_("Props"),       220, "props",       new FieldEditCtrl_Dialog(&PropListEditor::Create));
    55     AddColumnType(_("Color"),       80,  "color",       new FieldEditCtrl_Color());
     49    AddColumnType(_("Variant"),     90,  "@name",      new FieldEditCtrl_Text());
     50    AddColumnType(_("Base File"),   90,  "@file",      new FieldEditCtrl_Text());
     51    AddColumnType(_("Ratio"),       50,  "@frequency", new FieldEditCtrl_Text());
     52    AddColumnType(_("Model"),       140, "mesh",       new FieldEditCtrl_File(_T("art/meshes/"), _("Mesh files (*.pmd, *.dae)|*.pmd;*.dae|All files (*.*)|*.*")));
     53    AddColumnType(_("Textures"),    250, "textures",   new FieldEditCtrl_Dialog(&TexListEditor::Create));
     54    AddColumnType(_("Animations"),  250, "animations", new FieldEditCtrl_Dialog(&AnimListEditor::Create));
     55    AddColumnType(_("Props"),       220, "props",      new FieldEditCtrl_Dialog(&PropListEditor::Create));
     56    AddColumnType(_("Color"),       80,  "color",      new FieldEditCtrl_Color());
    5657}
    5758
    5859void ActorEditorListCtrl::DoImport(AtObj& in)
  • source/tools/xmlvalidator/validate.pl

     
    8080    validate('actor', \@files, 'art/actors/actor.rng');
    8181}
    8282
     83sub validate_variants
     84{
     85    my @files = find_files('art/variants', 'xml');
     86    validate('variant', \@files, 'art/variants/variant.rng');
     87}
     88
    8389sub validate_guis
    8490{
    8591    # there are two different gui XML schemas depending on path
     
    167173}
    168174
    169175validate_actors();
     176validate_variants();
    170177validate_guis();
    171178validate_maps();
    172179validate_materials();