Ticket #3286: easy_switch_animations.diff

File easy_switch_animations.diff, 18.3 KB (added by sanderd17, 9 years ago)
  • 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="units/variants/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="units/variants/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="units/variants/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="units/variants/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/actors/units/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>
  • source/graphics/ObjectBase.cpp

     
    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                    {
     151                        anim.m_AnimName = ae.Value;
     152                    }
     153                    else if (ae.Name == at_file)
     154                    {
     155                        anim.m_FileName = VfsPath("art/animation") / ae.Value.FromUTF8();
     156                    }
     157                    else if (ae.Name == at_speed)
     158                    {
     159                        anim.m_Speed = ae.Value.ToInt() / 100.f;
     160                        if (anim.m_Speed <= 0.0) anim.m_Speed = 1.0f;
     161                    }
     162                    else if (ae.Name == at_event)
     163                    {
     164                        float pos = ae.Value.ToFloat();
     165                        anim.m_ActionPos = clamp(pos, 0.f, 1.f);
     166                    }
     167                    else if (ae.Name == at_load)
     168                    {
     169                        float pos = ae.Value.ToFloat();
     170                        anim.m_ActionPos2 = clamp(pos, 0.f, 1.f);
     171                    }
     172                    else if (ae.Name == at_sound)
     173                    {
     174                        float pos = ae.Value.ToFloat();
     175                        anim.m_SoundPos = clamp(pos, 0.f, 1.f);
     176                    }
     177                }
     178                currentVariant.m_Anims.push_back(anim);
     179            }
     180
     181        }
     182        else if (option_name == el_props)
     183        {
     184            XERO_ITER_EL(option, prop_element)
     185            {
     186                ENSURE(prop_element.GetNodeName() == el_prop);
     187
     188                Prop prop;
     189                XERO_ITER_ATTR(prop_element, pe)
     190                {
     191                    if (pe.Name == at_attachpoint)
     192                        prop.m_PropPointName = pe.Value;
     193                    else if (pe.Name == at_actor)
     194                        prop.m_ModelName = pe.Value.FromUTF8();
     195                    else if (pe.Name == at_minheight)
     196                        prop.m_minHeight = pe.Value.ToFloat();
     197                    else if (pe.Name == at_maxheight)
     198                        prop.m_maxHeight = pe.Value.ToFloat();
     199                    else if (pe.Name == at_selectable)
     200                        prop.m_selectable = pe.Value != "false";
     201                }
     202                currentVariant.m_Props.push_back(prop);
     203            }
     204        }
     205    }
     206}
     207
    41208bool CObjectBase::Load(const VfsPath& pathname)
    42209{
    43210    m_UsedFiles.clear();
     
    53220    EL(actor);
    54221    EL(castshadow);
    55222    EL(float);
     223    EL(group);
    56224    EL(material);
    57     EL(group);
    58225    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);
    69226    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);
    86227    #undef AT
    87228    #undef EL
    88229
     
    94235        return false;
    95236    }
    96237
    97 
    98238    m_VariantGroups.clear();
    99239
    100240    m_Pathname = pathname;
     
    135275                ENSURE(variant.GetNodeName() == el_variant);
    136276                XERO_ITER_ATTR(variant, attr)
    137277                {
    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)
     278                    if (attr.Name == at_file)
    150279                    {
    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)
     280                        // Open up an external file to load.
     281                        // Don't crash hard when failures happen, but log them and continue
     282                        m_UsedFiles.insert(attr.Value);
     283                        CXeromyces XeroVariant;
     284                        if (XeroVariant.Load(g_VFS, "art/actors/" + attr.Value) == PSRETURN_OK)
    156285                        {
    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);
     286                            XMBElement variantRoot = XeroVariant.GetRoot();
     287                            LoadVariant(XeroVariant, variantRoot, *currentVariant);
    168288                        }
     289                        else
     290                            LOGERROR("Could not open path %s", attr.Value);
    169291                    }
    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                     }
    260292                }
    261293
     294                // Always expand the contents of this node, even if a file has
     295                // been loaded to allow for extra definitions
     296                LoadVariant(XeroFile, variant, *currentVariant);
    262297                ++currentVariant;
    263298            }
    264299
    265300            if (currentGroup->size() == 0)
    266             {
    267301                LOGERROR("Actor group has zero variants ('%s')", pathname.string8());
    268             }
    269302
    270303            ++currentGroup;
    271304        }
    272305        else if (child_name == el_castshadow)
    273         {
    274306            m_Properties.m_CastShadows = true;
    275         }
    276307        else if (child_name == el_float)
    277         {
    278308            m_Properties.m_FloatOnWater = true;
    279         }
    280309        else if (child_name == el_material)
    281         {
    282310            m_Material = VfsPath("art/materials") / child.GetText().FromUTF8();
    283         }
    284311    }
    285312
    286313    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