Ticket #2936: RelativeTemplates.patch

File RelativeTemplates.patch, 16.0 KB (added by wraitii, 8 years ago)
  • source/simulation2/components/CCmpVisualActor.cpp

     
    146146                        "</element>"
    147147                        "<element name='Box' a:help='Sets the selection shape to a box of specified dimensions'>"
    148148                            "<attribute name='width'>"
    149                                 "<ref name='positiveDecimal' />"
     149                                "<data type='decimal'>"
     150                                    "<param name='minExclusive'>0.0</param>"
     151                                "</data>"
    150152                            "</attribute>"
    151153                            "<attribute name='height'>"
    152                                 "<ref name='positiveDecimal' />"
     154                                "<data type='decimal'>"
     155                                    "<param name='minExclusive'>0.0</param>"
     156                                "</data>"
    153157                            "</attribute>"
    154158                            "<attribute name='depth'>"
    155                                 "<ref name='positiveDecimal' />"
     159                                "<data type='decimal'>"
     160                                    "<param name='minExclusive'>0.0</param>"
     161                                "</data>"
    156162                            "</attribute>"
    157163                        "</element>"
    158164                        "<element name='Cylinder' a:help='Sets the selection shape to a cylinder of specified dimensions'>"
    159165                            "<attribute name='radius'>"
    160                                 "<ref name='positiveDecimal' />"
     166                                "<data type='decimal'>"
     167                                    "<param name='minExclusive'>0.0</param>"
     168                                "</data>"
    161169                            "</attribute>"
    162170                            "<attribute name='height'>"
    163                                 "<ref name='positiveDecimal' />"
     171                                "<data type='decimal'>"
     172                                    "<param name='minExclusive'>0.0</param>"
     173                                "</data>"
    164174                            "</attribute>"
    165175                        "</element>"
    166176                    "</choice>"
  • source/simulation2/components/CCmpFootprint.cpp

     
    5959            "<choice>"
    6060                "<element name='Square' a:help='Set the footprint to a square of the given size'>"
    6161                    "<attribute name='width' a:help='Size of the footprint along the left/right direction (in metres)'>"
    62                         "<ref name='positiveDecimal'/>"
     62                        "<data type='decimal'>"
     63                            "<param name='minExclusive'>0.0</param>"
     64                        "</data>"
    6365                    "</attribute>"
    6466                    "<attribute name='depth' a:help='Size of the footprint along the front/back direction (in metres)'>"
    65                         "<ref name='positiveDecimal'/>"
     67                        "<data type='decimal'>"
     68                            "<param name='minExclusive'>0.0</param>"
     69                        "</data>"
    6670                    "</attribute>"
    6771                "</element>"
    6872                "<element name='Circle' a:help='Set the footprint to a circle of the given size'>"
    6973                    "<attribute name='radius' a:help='Radius of the footprint (in metres)'>"
    70                         "<ref name='positiveDecimal'/>"
     74                        "<data type='decimal'>"
     75                            "<param name='minExclusive'>0.0</param>"
     76                        "</data>"
    7177                    "</attribute>"
    7278                "</element>"
    7379            "</choice>"
  • source/simulation2/docs/SimulationDocs.h

     
    298298- <code>&lt;text/></code>
    299299- <code>&lt;data type='boolean'/></code>
    300300- <code>&lt;data type='decimal'/></code>
     301- <code>&lt;data type='integer'/></code>
    301302- <code>&lt;data type='nonNegativeInteger'/></code>
    302303- <code>&lt;data type='positiveInteger'/></code>
     304- <code>&lt;ref name='decimal'/></code>
    303305- <code>&lt;ref name='nonNegativeDecimal'/></code>
    304306- <code>&lt;ref name='positiveDecimal'/></code>
    305307
    306 (The last two are slightly different since they're not standard data types.)
    307308
     309The <code>&lt;data&gt;</code> elements are native elements, while the <code>&lt;ref&gt;</code> elements are elements added for our engine. These non-native elements allow the definition of an operation that depends on the parent template. Possible operations are "add" and "mul", and can be applied as the example below.
     310
     311Say the parent template is
     312@code
     313<Entity>
     314  <Example>
     315    <Name>Semi-Humanoids</Name>
     316    <Height>9000</Height>
     317    <Eyes/>
     318  </Example>
     319  <!-- ... other components ... -->
     320</Entity>
     321@endcode
     322and the child template appears like
     323@code
     324<Entity>
     325  <Example>
     326    <Name>Barney</Name>
     327    <Height op="add">5</Height>
     328    <Eyes/>
     329  </Example>
     330  <!-- ... other components ... -->
     331</Entity>
     332@endcode
     333then Barney would have a height of 9005.
     334
    308335Elements can be wrapped in <code>&lt;optional></code>.
    309336Groups of elements can be wrapped in <code>&lt;choice></code> to allow only one of them.
    310337The content of an <code>&lt;element></code> can be further nested elements, but note that
  • source/simulation2/system/ParamNode.cpp

     
    7676    // Look for special attributes
    7777    int at_disable = xmb.GetAttributeID("disable");
    7878    int at_replace = xmb.GetAttributeID("replace");
     79    int at_op = xmb.GetAttributeID("op");
    7980    int at_datatype = xmb.GetAttributeID("datatype");
     81    enum op {
     82        INVALID,
     83        ADD,
     84        MUL
     85    } op = INVALID;
    8086    bool replacing = false;
    8187    {
    8288        XERO_ITER_ATTR(element, attr)
     
    9197                m_Childs.erase(name);
    9298                replacing = true;
    9399            }
     100            else if (attr.Name == at_op)
     101            {
     102                if (std::wstring(attr.Value.begin(), attr.Value.end()) == L"add")
     103                    op = ADD;
     104                else if (std::wstring(attr.Value.begin(), attr.Value.end()) == L"mul")
     105                    op = MUL;
     106                else
     107                    LOGWARNING("Invalid op '%ls'", attr.Value);
     108            }
    94109        }
    95110    }
    96111    {
     
    137152
    138153    // Add this element as a child node
    139154    CParamNode& node = m_Childs[name];
     155    if (op != INVALID)
     156    {
     157        // TODO: Support parsing of data types other than fixed; log warnings in other cases
     158        fixed oldval = node.ToFixed();
     159        fixed mod = fixed::FromString(CStrW(value));
     160        switch (op)
     161        {
     162        case ADD:
     163            node.m_Value = (oldval + mod).ToString().FromUTF8();
     164            break;
     165        case MUL:
     166            node.m_Value = (oldval.Multiply(mod)).ToString().FromUTF8();
     167            break;
     168        }
     169        hasSetValue = true;
     170    }
    140171    if (!hasSetValue)
    141172        node.m_Value = value;
    142173
     
    150181    XERO_ITER_ATTR(element, attr)
    151182    {
    152183        // Skip special attributes
    153         if (attr.Name == at_replace) continue;
     184        if (attr.Name == at_replace || attr.Name == at_op)
     185            continue;
    154186        // Add any others
    155187        std::string attrName = xmb.GetAttributeString(attr.Name);
    156188        node.m_Childs["@" + attrName].m_Value = attr.Value.FromUTF8();
  • source/simulation2/system/ComponentManager.cpp

     
    10921092
    10931093std::string CComponentManager::GenerateSchema()
    10941094{
     1095    std::string numericOperation =
     1096        "<optional>"
     1097            "<attribute name='op'>"
     1098                "<choice>"
     1099                    "<value>add</value>"
     1100                    "<value>mul</value>"
     1101                "</choice>"
     1102            "</attribute>"
     1103        "</optional>";
    10951104    std::string schema =
    10961105        "<grammar xmlns='http://relaxng.org/ns/structure/1.0' xmlns:a='http://ns.wildfiregames.com/entity' datatypeLibrary='http://www.w3.org/2001/XMLSchema-datatypes'>"
     1106            "<define name='decimal'>"
     1107                "<data type='decimal'/>"
     1108                + numericOperation +
     1109            "</define>"
    10971110            "<define name='nonNegativeDecimal'>"
    10981111                "<data type='decimal'><param name='minInclusive'>0</param></data>"
     1112                + numericOperation +
    10991113            "</define>"
    11001114            "<define name='positiveDecimal'>"
    11011115                "<data type='decimal'><param name='minExclusive'>0</param></data>"
     1116                + numericOperation +
    11021117            "</define>"
    11031118            "<define name='anything'>"
    11041119                "<zeroOrMore>"
  • source/tools/entity/Entity.pm

     
    8383            }
    8484        }
    8585        $base->{' content'} = join ' ', @t;
     86    } elsif ($new->{'@op'}) {
     87        my $op = $new->{'@op'}{' content'};
     88        my $op1 = $base->{' content'};
     89        my $op2 = $new->{' content'};
     90        if ($op eq 'add') {
     91            $base->{' content'} = $op1 + $op2;
     92        }
     93        elsif ($op eq 'mul') {
     94            $base->{' content'} = $op1 * $op2;
     95        }
     96        else {
     97            die "Invalid operator '$op'";
     98        }
    8699    } else {
    87100        $base->{' content'} = $new->{' content'};
    88101    }
  • source/tools/templatesanalyzer/unitTables.py

     
     1# Copyright (c) 2015 Wildfire Games
     2#
     3# Permission is hereby granted, free of charge, to any person obtaining a copy
     4# of this software and associated documentation files (the "Software"), to deal
     5# in the Software without restriction, including without limitation the rights
     6# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     7# copies of the Software, and to permit persons to whom the Software is
     8# furnished to do so, subject to the following conditions:
     9#
     10# The above copyright notice and this permission notice shall be included in
     11# all copies or substantial portions of the Software.
     12#
     13# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     14# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     15# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
     16# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     17# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     18# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
     19# THE SOFTWARE.
     20
    121import xml.etree.ElementTree as ET
    222import os
    323import glob
    424
    5 # What data to use
    625AttackTypes = ["Hack","Pierce","Crush"]
    726Resources = ["food", "wood", "stone", "metal"]
    827
     
    1736Civs = ["athen", "mace", "spart", "sele", "cart", "rome", "pers", "maur", "brit", "gaul", "iber"]
    1837
    1938# Remote Civ templates with those strings in their name.
    20 FilterOut = ["marian"]
     39FilterOut = ["marian", "thureophoros", "thorakites", "kardakes"]
    2140
    2241# Sorting parameters for the "roster variety" table
    2342ComparativeSortByCav = True
     
    5877
    5978    return False
    6079
     80def NumericStatProcess(unitValue, templateValue):
     81    if not "op" in templateValue.attrib:
     82        return float(templateValue.text)
     83    if (templateValue.attrib["op"] == "add"):
     84        unitValue += float(templateValue.text)
     85    elif (templateValue.attrib["op"] == "sub"):
     86        unitValue -= float(templateValue.text)
     87    elif (templateValue.attrib["op"] == "mul"):
     88        unitValue *= float(templateValue.text)
     89    elif (templateValue.attrib["op"] == "div"):
     90        unitValue /= float(templateValue.text)
     91    return unitValue
     92
     93
    6194# This function parses the entity values manually.
    6295def CalcUnit(UnitName, existingUnit = None):
    6396    unit = { 'HP' : "0", "BuildTime" : "0", "Cost" : { 'food' : "0", "wood" : "0", "stone" : "0", "metal" : "0", "population" : "0"},
    6497    'Attack' : { "Melee" : { "Hack" : 0, "Pierce" : 0, "Crush" : 0 }, "Ranged" : { "Hack" : 0, "Pierce" : 0, "Crush" : 0 } },
    65     'RepeatRate' : {"Melee" : "0", "Ranged" : "0"},'PrepRate' : {"Melee" : "0", "Ranged" : "0"}, "Armour" : {},
    66     "Ranged" : False, "Classes" : [], "AttackBonuses" : {}, "Restricted" : [],
     98    'RepeatRate' : {"Melee" : "0", "Ranged" : "0"},'PrepRate' : {"Melee" : "0", "Ranged" : "0"}, "Armour" : { "Hack" : 0, "Pierce" : 0, "Crush" : 0},
     99    "Ranged" : False, "Classes" : [], "AttackBonuses" : {}, "Restricted" : [], "WalkSpeed" : 0, "Range" : 0, "Spread" : 0,
    67100    "Civ" : None }
    68101   
    69102    if (existingUnit != None):
     
    80113        unit['Civ'] = Template.find("./Identity/Civ").text
    81114
    82115    if (Template.find("./Health/Max") != None):
    83         unit['HP'] = Template.find("./Health/Max").text
     116        unit['HP'] = NumericStatProcess(unit['HP'], Template.find("./Health/Max"))
    84117
    85118    if (Template.find("./Cost/BuildTime") != None):
    86         unit['BuildTime'] = Template.find("./Cost/BuildTime").text
     119        unit['BuildTime'] = NumericStatProcess(unit['BuildTime'], Template.find("./Cost/BuildTime"))
    87120   
    88121    if (Template.find("./Cost/Resources") != None):
    89122        for type in list(Template.find("./Cost/Resources")):
    90             unit['Cost'][type.tag] = type.text
     123            unit['Cost'][type.tag] = NumericStatProcess(unit['Cost'][type.tag], type)
    91124
    92125    if (Template.find("./Cost/Population") != None):
    93         unit['Cost']["population"] = Template.find("./Cost/Population").text
     126        unit['Cost']["population"] = NumericStatProcess(unit['Cost']["population"], Template.find("./Cost/Population"))
    94127
    95128    if (Template.find("./Attack/Melee") != None):
    96129        if (Template.find("./Attack/Melee/RepeatTime") != None):
    97             unit['RepeatRate']["Melee"] = Template.find("./Attack/Melee/RepeatTime").text
     130            unit['RepeatRate']["Melee"] = NumericStatProcess(unit['RepeatRate']["Melee"], Template.find("./Attack/Melee/RepeatTime"))
    98131        if (Template.find("./Attack/Melee/PrepareTime") != None):
    99             unit['PrepRate']["Melee"] = Template.find("./Attack/Melee/PrepareTime").text
     132            unit['PrepRate']["Melee"] = NumericStatProcess(unit['PrepRate']["Melee"], Template.find("./Attack/Melee/PrepareTime"))
    100133        for atttype in AttackTypes:
    101134            if (Template.find("./Attack/Melee/"+atttype) != None):
    102                 unit['Attack']['Melee'][atttype] = Template.find("./Attack/Melee/"+atttype).text
     135                unit['Attack']['Melee'][atttype] = NumericStatProcess(unit['Attack']['Melee'][atttype], Template.find("./Attack/Melee/"+atttype))
    103136        if (Template.find("./Attack/Melee/Bonuses") != None):
    104137            for Bonus in Template.find("./Attack/Melee/Bonuses"):
    105138                Against = []
     
    123156    if (Template.find("./Attack/Ranged") != None):
    124157        unit['Ranged'] = True
    125158        if (Template.find("./Attack/Ranged/MaxRange") != None):
    126             unit['Range'] = Template.find("./Attack/Ranged/MaxRange").text
     159            unit['Range'] = NumericStatProcess(unit['Range'], Template.find("./Attack/Ranged/MaxRange"))
    127160        if (Template.find("./Attack/Ranged/Spread") != None):
    128             unit['Spread'] = Template.find("./Attack/Ranged/Spread").text
     161            unit['Spread'] = NumericStatProcess(unit['Spread'], Template.find("./Attack/Ranged/Spread"))
    129162        if (Template.find("./Attack/Ranged/RepeatTime") != None):
    130             unit['RepeatRate']["Ranged"] = Template.find("./Attack/Ranged/RepeatTime").text
     163            unit['RepeatRate']["Ranged"] = NumericStatProcess(unit['RepeatRate']["Ranged"], Template.find("./Attack/Ranged/RepeatTime"))
    131164        if (Template.find("./Attack/Ranged/PrepareTime") != None):
    132             unit['PrepRate']["Ranged"] = Template.find("./Attack/Ranged/PrepareTime").text
     165            unit['PrepRate']["Ranged"] = NumericStatProcess(unit['PrepRate']["Ranged"], Template.find("./Attack/Ranged/PrepareTime"))
    133166        for atttype in AttackTypes:
    134167            if (Template.find("./Attack/Ranged/"+atttype) != None):
    135                 unit['Attack']['Ranged'][atttype] = Template.find("./Attack/Ranged/"+atttype).text
     168                unit['Attack']['Ranged'][atttype] = NumericStatProcess(unit['Attack']['Ranged'][atttype], Template.find("./Attack/Ranged/"+atttype))
    136169        if (Template.find("./Attack/Ranged/Bonuses") != None):
    137170            for Bonus in Template.find("./Attack/Ranged/Bonuses"):
    138171                Against = []
     
    155188    if (Template.find("./Armour") != None):
    156189        for atttype in AttackTypes:
    157190            if (Template.find("./Armour/"+atttype) != None):
    158                 unit['Armour'][atttype] = Template.find("./Armour/"+atttype).text
     191                unit['Armour'][atttype] = NumericStatProcess(unit['Armour'][atttype], Template.find("./Armour/"+atttype))
    159192
    160193    if (Template.find("./UnitMotion") != None):
    161194        if (Template.find("./UnitMotion/WalkSpeed") != None):
    162                 unit['WalkSpeed'] = Template.find("./UnitMotion/WalkSpeed").text
     195                unit['WalkSpeed'] = NumericStatProcess(unit['WalkSpeed'], Template.find("./UnitMotion/WalkSpeed"))
    163196
    164197    if (Template.find("./Identity/VisibleClasses") != None):
    165198        newClasses = Template.find("./Identity/VisibleClasses").text.split(" ")
     
    209242            ret += "<td> - </td>"
    210243        ret += "<td> - </td>"
    211244
    212     if UnitDict["Ranged"] == True:
     245    if UnitDict["Ranged"] == True and UnitDict["Range"] > 0:
    213246        ret += "<td>" + str("%.1f" % float(UnitDict["Range"])) + "</td>"
    214247        spread = (float(UnitDict["Spread"]) / float(UnitDict["Range"]))*100.0
    215248        ret += "<td>" + str("%.1f" % spread) + "</td>"