Ticket #3: technology_19-04-12.diff

File technology_19-04-12.diff, 156.3 KB (added by Jonathan Waller, 12 years ago)
  • source/simulation2/system/ComponentManager.h

     
    233233    static int Script_AddLocalEntity(void* cbdata, std::string templateName);
    234234    static void Script_DestroyEntity(void* cbdata, int ent);
    235235    static CScriptVal Script_ReadJSONFile(void* cbdata, std::wstring fileName);
     236    static std::vector<std::string> Script_FindAllTechnologyTemplates(void* cbdata);
    236237
    237238    CMessage* ConstructMessage(int mtid, CScriptVal data);
    238239    void SendGlobalMessage(entity_id_t ent, const CMessage& msg) const;
  • source/simulation2/system/ComponentManager.cpp

     
    8181        m_ScriptInterface.RegisterFunction<int, std::string, CComponentManager::Script_AddLocalEntity> ("AddLocalEntity");
    8282        m_ScriptInterface.RegisterFunction<void, int, CComponentManager::Script_DestroyEntity> ("DestroyEntity");
    8383        m_ScriptInterface.RegisterFunction<CScriptVal, std::wstring, CComponentManager::Script_ReadJSONFile> ("ReadJSONFile");
     84        m_ScriptInterface.RegisterFunction<std::vector<std::string>, CComponentManager::Script_FindAllTechnologyTemplates> ("FindAllTechnologyTemplates");
    8485    }
    8586
    8687    // Define MT_*, IID_* as script globals, and store their names
     
    944945
    945946    return componentManager->GetScriptInterface().ReadJSONFile(path).get();
    946947}
     948
     949static Status AddToTechnologyTemplates(const VfsPath& pathname, const FileInfo& UNUSED(fileInfo), const uintptr_t cbData)
     950{
     951    std::vector<std::string>& templates = *(std::vector<std::string>*)cbData;
     952
     953    // Strip the .json extension
     954    VfsPath pathstem = pathname.ChangeExtension(L"");
     955    // Strip the root from the path
     956    std::wstring name = pathstem.string().substr(ARRAY_SIZE("simulation/data/technologies/")-1);
     957
     958    templates.push_back(std::string(name.begin(), name.end()));
     959    return INFO::OK;
     960}
     961
     962std::vector<std::string> CComponentManager::Script_FindAllTechnologyTemplates(void* cbdata)
     963{
     964    std::vector<std::string> templates;
     965
     966    Status ok;
     967
     968    // Find all the technology template files
     969    ok = vfs::ForEachFile(g_VFS, "simulation/data/technologies/", AddToTechnologyTemplates, (uintptr_t)&templates, L"*.json", vfs::DIR_RECURSIVE);
     970    WARN_IF_ERR(ok);
     971
     972    return templates;
     973}
  • source/simulation2/Simulation2.cpp

     
    125125            LOAD_SCRIPTED_COMPONENT("GuiInterface");
    126126            LOAD_SCRIPTED_COMPONENT("PlayerManager");
    127127            LOAD_SCRIPTED_COMPONENT("Timer");
     128            LOAD_SCRIPTED_COMPONENT("TechnologyTemplateManager");
    128129
    129130#undef LOAD_SCRIPTED_COMPONENT
    130131        }
  • binaries/data/mods/internal/simulation/templates/campaigns/campaign_religious_test.xml

     
    2020    <Radius>100</Radius>
    2121    <Weight>65536</Weight>
    2222  </TerritoryInfluence>
    23   <TrainingQueue disable=""/>
     23  <ProductionQueue disable=""/>
    2424  <VisualActor>
    2525    <Actor>structures/hellenes/temple_new.xml</Actor>
    2626  </VisualActor>
  • binaries/data/mods/internal/simulation/templates/campaigns/campaign_city_test.xml

     
    3535    <Radius>300</Radius>
    3636    <Weight>35000</Weight>
    3737  </TerritoryInfluence>
    38   <TrainingQueue>
     38  <ProductionQueue>
    3939    <Entities datatype="tokens">
    4040      -units/{civ}_support_female_citizen
    4141      campaigns/army_mace_hero_alexander
    4242      campaigns/army_mace_standard
    4343      units/{civ}_support_trader
    4444    </Entities>
    45   </TrainingQueue>
     45  </ProductionQueue>
    4646  <VisualActor>
    4747    <Actor>campaigns/structures/hellenes/settlement_curtainwall.xml</Actor>
    4848  </VisualActor>
  • binaries/data/mods/internal/simulation/templates/campaigns/campaign_city_minor_test.xml

     
    3535    <Radius>150</Radius>
    3636    <Weight>35000</Weight>
    3737  </TerritoryInfluence>
    38   <TrainingQueue>
     38  <ProductionQueue>
    3939    <Entities datatype="tokens">
    4040      -units/{civ}_support_female_citizen
    4141      campaigns/army_mace_hero_alexander
    4242      campaigns/army_mace_standard
    4343    </Entities>
    44   </TrainingQueue>
     44  </ProductionQueue>
    4545  <VisualActor>
    4646    <Actor>campaigns/structures/hellenes/settlement_curtainwall.xml</Actor>
    4747  </VisualActor>
  • binaries/data/mods/internal/simulation/templates/structures/mace_corral.xml

     
    1818  <Obstruction>
    1919    <Static width="14.0" depth="14.0"/>
    2020  </Obstruction>
    21   <TrainingQueue>
     21  <ProductionQueue>
    2222    <Entities datatype="tokens">
    2323      gaia/fauna_goat
    2424    </Entities>
    25   </TrainingQueue>
     25  </ProductionQueue>
    2626  <VisualActor>
    2727    <Actor>structures/hellenes/corral.xml</Actor>
    2828    <FoundationActor>structures/fndn_3x3.xml</FoundationActor>
  • binaries/data/mods/internal/simulation/templates/structures/mace_barracks.xml

     
    1515    <SpecificName>Stratēgeîon</SpecificName>
    1616    <History>The Stratigeion was the main military headquarters, where important decisions were taken and plans for battles discussed by the Hellene Generals, or "Strategoi".</History>
    1717  </Identity>
    18   <TrainingQueue>
     18  <ProductionQueue>
    1919    <Entities datatype="tokens">
    2020      units/mace_infantry_spearman_b
    2121      units/mace_infantry_javelinist_b
     
    2424      units/mace_cavalry_spearman_b
    2525      units/mace_cavalry_javelinist_b
    2626    </Entities>
    27   </TrainingQueue>
     27  </ProductionQueue>
    2828  <VisualActor>
    2929    <Actor>structures/hellenes/barracks.xml</Actor>
    3030  </VisualActor>
  • binaries/data/mods/internal/simulation/templates/structures/spart_corral.xml

     
    1818  <Obstruction>
    1919    <Static width="14.0" depth="14.0"/>
    2020  </Obstruction>
    21   <TrainingQueue>
     21  <ProductionQueue>
    2222    <Entities datatype="tokens">
    2323      gaia/fauna_goat
    2424    </Entities>
    25   </TrainingQueue>
     25  </ProductionQueue>
    2626  <VisualActor>
    2727    <Actor>structures/hellenes/corral.xml</Actor>
    2828    <FoundationActor>structures/fndn_3x3.xml</FoundationActor>
  • binaries/data/mods/internal/simulation/templates/structures/mace_fortress.xml

     
    1919  <Obstruction>
    2020    <Static width="24.0" depth="26.0"/>
    2121  </Obstruction>
    22   <TrainingQueue>
     22  <ProductionQueue>
    2323    <Entities datatype="tokens">
    2424      units/mace_hero_philip
    2525      units/mace_hero_alexander
     
    3030      units/mace_mechanical_siege_lithobolos
    3131      units/mace_mechanical_siege_tower
    3232    </Entities>
    33   </TrainingQueue>
     33  </ProductionQueue>
    3434  <VisualActor>
    3535    <Actor>structures/hellenes/fortress_new.xml</Actor>
    3636  </VisualActor>
  • binaries/data/mods/internal/simulation/templates/structures/spart_barracks.xml

     
    1515    <SpecificName>Stratēgeîon</SpecificName>
    1616    <History>The Stratigeion was the main military headquarters, where important decisions were taken and plans for battles discussed by the Hellene Generals, or "Strategoi".</History>
    1717  </Identity>
    18   <TrainingQueue>
     18  <ProductionQueue>
    1919    <Entities datatype="tokens">
    2020      units/spart_infantry_spearman_b
    2121      units/spart_champion_infantry_sword
    2222      units/spart_infantry_javelinist_b
    2323      units/spart_cavalry_javelinist_b
    2424    </Entities>
    25   </TrainingQueue>
     25  </ProductionQueue>
    2626  <VisualActor>
    2727    <Actor>structures/hellenes/barracks.xml</Actor>
    2828  </VisualActor>
  • binaries/data/mods/internal/simulation/templates/structures/spart_syssiton.xml

     
    3333      <death>attack/destruction/building_collapse_large.xml</death>
    3434    </SoundGroups>
    3535  </Sound>
    36   <TrainingQueue>
     36  <ProductionQueue>
    3737    <Entities datatype="tokens">
    3838      units/hele_hero_leonidas
    3939      units/spart_champion_infantry_spear
    4040    </Entities>
    41   </TrainingQueue>
     41  </ProductionQueue>
    4242  <VisualActor>
    4343    <Actor>structures/hellenes/gymnasion.xml</Actor>
    4444    <FoundationActor>structures/fndn_6x6.xml</FoundationActor>
  • binaries/data/mods/internal/simulation/templates/structures/spart_fortress.xml

     
    1919  <Obstruction>
    2020    <Static width="24.0" depth="26.0"/>
    2121  </Obstruction>
    22   <TrainingQueue>
     22  <ProductionQueue>
    2323    <Entities datatype="tokens">
    2424      units/spart_mechanical_siege_ram
    2525    </Entities>
    26   </TrainingQueue>
     26  </ProductionQueue>
    2727  <VisualActor>
    2828    <Actor>structures/hellenes/fortress_new.xml</Actor>
    2929  </VisualActor>
  • binaries/data/mods/internal/simulation/templates/structures/mace_civil_centre.xml

     
    1111    <SpecificName>Agorā́</SpecificName>
    1212    <History>The most important place in most Classical Greek poleis, the Agora served many purposes; it was a place for public speeches and was the stage for civic life and commercial interests.</History>
    1313  </Identity>
    14   <TrainingQueue>
     14  <ProductionQueue>
    1515    <Entities datatype="tokens">
    1616      units/mace_infantry_spearman_b
    1717      units/mace_infantry_javelinist_b
    1818      units/mace_cavalry_spearman_b
    1919    </Entities>
    20   </TrainingQueue>
     20  </ProductionQueue>
    2121  <VisualActor>
    2222    <Actor>structures/hellenes/civic_centre_new.xml</Actor>
    2323  </VisualActor>
  • binaries/data/mods/internal/simulation/templates/structures/mace_dock.xml

     
    1111    <SpecificName>Limḗn</SpecificName>
    1212    <History>Greece is a sea country, which is why some of the greatest Hellenic and Hellenistic cities like Ephesus, Corinth, Alexandria and Antioch were built by the sea. It should also be noted that all colonies during the Great Colonisation were thriving port centres, which traded with the local population.</History>
    1313  </Identity>
    14   <TrainingQueue>
     14  <ProductionQueue>
    1515    <Entities datatype="tokens">
    1616      units/hele_ship_bireme
    1717      units/hele_ship_trireme
    1818    </Entities>
    19   </TrainingQueue>
     19  </ProductionQueue>
    2020  <VisualActor>
    2121    <Actor>structures/hellenes/dock.xml</Actor>
    2222  </VisualActor>
  • binaries/data/mods/internal/simulation/templates/structures/spart_civil_centre.xml

     
    1111    <SpecificName>Agorā́</SpecificName>
    1212    <History>The most important place in most Classical Greek poleis, the Agora served many purposes; it was a place for public speeches and was the stage for civic life and commercial interests.</History>
    1313  </Identity>
    14   <TrainingQueue>
     14  <ProductionQueue>
    1515    <Entities datatype="tokens">
    1616      units/spart_infantry_spearman_b
    1717      units/spart_infantry_javelinist_b
    1818      units/spart_cavalry_javelinist_b
    1919    </Entities>
    20   </TrainingQueue>
     20  </ProductionQueue>
    2121  <VisualActor>
    2222    <Actor>structures/hellenes/civic_centre_new.xml</Actor>
    2323  </VisualActor>
  • binaries/data/mods/internal/simulation/templates/structures/spart_gerousia.xml

     
    3434      <death>attack/destruction/building_collapse_large.xml</death>
    3535    </SoundGroups>
    3636  </Sound>
    37   <TrainingQueue>
     37  <ProductionQueue>
    3838    <Entities datatype="tokens">
    3939      units/hele_hero_leonidas
    4040    </Entities>
    41   </TrainingQueue>
     41  </ProductionQueue>
    4242  <VisualActor>
    4343    <Actor>structures/hellenes/tholos.xml</Actor>
    4444  </VisualActor>
  • binaries/data/mods/internal/simulation/templates/structures/spart_dock.xml

     
    1111    <SpecificName>Limḗn</SpecificName>
    1212    <History>Greece is a sea country, which is why some of the greatest Hellenic and Hellenistic cities like Ephesus, Corinth, Alexandria and Antioch were built by the sea. It should also be noted that all colonies during the Great Colonisation were thriving port centres, which traded with the local population.</History>
    1313  </Identity>
    14   <TrainingQueue>
     14  <ProductionQueue>
    1515    <Entities datatype="tokens">
    1616      units/spart_ship_bireme
    1717      units/spart_ship_trireme
    1818    </Entities>
    19   </TrainingQueue>
     19  </ProductionQueue>
    2020  <VisualActor>
    2121    <Actor>structures/hellenes/dock.xml</Actor>
    2222  </VisualActor>
  • binaries/data/mods/public/gui/session/session.xml

     
    727727                </object>
    728728
    729729                <object name="unitResearchPanel"
    730                     style="TranslucentPanelThinBorder"
    731                     size="0 100%-56 100% 100%"
    732                     type="text"
     730                    size="14 100%-56 100% 100%"
    733731                >
    734 
     732                    <object size="0 0 100% 100%">
     733                        <repeat count="8">
     734                            <object name="unitResearchButton[n]" hidden="true" style="iconButton" type="button" size="0 0 46 46" tooltip_style="sessionToolTipBottom">
     735                                <object name="unitResearchIcon[n]" type="image" ghost="true" size="3 3 43 43"/>
     736                            </object>
     737                        </repeat>
     738                    </object>
    735739                    [research commands]
    736740                </object>
    737741
  • binaries/data/mods/public/gui/session/input.js

     
    764764        case "hotkeyup":
    765765            if (ev.hotkey == "session.batchtrain")
    766766            {
    767                 flushTrainingQueueBatch();
     767                flushTrainingBatch();
    768768                inputState = INPUT_NORMAL;
    769769            }
    770770            break;
     
    12021202var batchTrainingCount;
    12031203const batchIncrementSize = 5;
    12041204
    1205 function flushTrainingQueueBatch()
     1205function flushTrainingBatch()
    12061206{
    12071207    Engine.PostNetworkCommand({"type": "train", "entity": batchTrainingEntity, "template": batchTrainingType, "count": batchTrainingCount});
    12081208}
    12091209
    12101210// Called by GUI when user clicks training button
    1211 function addToTrainingQueue(entity, trainEntType)
     1211function addTrainingToQueue(entity, trainEntType)
    12121212{
    12131213    if (Engine.HotkeyIsPressed("session.batchtrain"))
    12141214    {
     
    12231223            // Otherwise start a new one
    12241224            else
    12251225            {
    1226                 flushTrainingQueueBatch();
     1226                flushTrainingBatch();
    12271227                // fall through to create the new batch
    12281228            }
    12291229        }
     
    12391239    }
    12401240}
    12411241
     1242// Called by GUI when user clicks training button
     1243function addResearchToQueue(entity, trainEntType)
     1244{
     1245    Engine.PostNetworkCommand({"type": "research", "entity": entity, "template": trainEntType});
     1246}
     1247
    12421248// Returns the number of units that will be present in a batch if the user clicks
    12431249// the training button with shift down
    1244 function getTrainingQueueBatchStatus(entity, trainEntType)
     1250function getTrainingBatchStatus(entity, trainEntType)
    12451251{
    12461252    if (inputState == INPUT_BATCHTRAINING && batchTrainingEntity == entity && batchTrainingType == trainEntType)
    12471253        return [batchTrainingCount, batchIncrementSize];
     
    12501256}
    12511257
    12521258// Called by GUI when user clicks production queue item
    1253 function removeFromTrainingQueue(entity, id)
     1259function removeFromProductionQueue(entity, id)
    12541260{
    1255     Engine.PostNetworkCommand({"type": "stop-train", "entity": entity, "id": id});
     1261    Engine.PostNetworkCommand({"type": "stop-production", "entity": entity, "id": id});
    12561262}
    12571263
    12581264// Called by unit selection buttons
  • binaries/data/mods/public/gui/session/unit_commands.js

     
    44const GARRISON = "Garrison";
    55const FORMATION = "Formation";
    66const TRAINING = "Training";
     7const RESEARCH = "Research";
    78const CONSTRUCTION = "Construction";
    89const COMMAND = "Command";
    910const STANCE = "Stance";
     
    2324const BARTER_ACTIONS = ["Sell", "Buy"];
    2425
    2526// The number of currently visible buttons (used to optimise showing/hiding)
    26 var g_unitPanelButtons = {"Selection": 0, "Queue": 0, "Formation": 0, "Garrison": 0, "Training": 0, "Barter": 0, "Trading": 0, "Construction": 0, "Command": 0, "Stance": 0};
     27var g_unitPanelButtons = {"Selection": 0, "Queue": 0, "Formation": 0, "Garrison": 0, "Training": 0, "Research": 0, "Barter": 0, "Trading": 0, "Construction": 0, "Command": 0, "Stance": 0};
    2728
    2829// Unit panels are panels with row(s) of buttons
    2930var g_unitPanels = ["Selection", "Queue", "Formation", "Garrison", "Training", "Barter", "Trading", "Construction", "Research", "Stance", "Command"];
     
    163164            if (numberOfItems > 24)
    164165                numberOfItems =  24;
    165166            break;
     167       
     168        case RESEARCH:
     169            if (numberOfItems > 8)
     170                numberOfItems =  8;
     171            break;
    166172
    167173        case CONSTRUCTION:
    168174            if (numberOfItems > 24)
     
    183189    for (i = 0; i < numberOfItems; i++)
    184190    {
    185191        var item = items[i];
    186         var entType = ((guiName == "Queue")? item.template : item);
     192       
     193        // If a tech has been researched it leaves an empty slot
     194        if (guiName == RESEARCH && !item)
     195        {
     196            getGUIObjectByName("unit"+guiName+"Button["+i+"]").hidden = true;
     197            continue;
     198        }
     199       
     200        // Get the entity type and load the template for that type if necessary
     201        var entType;
    187202        var template;
    188         if (guiName != "Formation" && guiName != "Command" && guiName != "Stance")
     203        switch (guiName)
    189204        {
    190             template = GetTemplateData(entType);
    191             if (!template)
    192                 continue; // ignore attempts to use invalid templates (an error should have been reported already)
     205            case QUEUE:
     206                // The queue can hold both technologies and units so we need to use the correct code for
     207                // loading the templates
     208                if (item.unitTemplate)
     209                {
     210                    entType = item.unitTemplate;
     211                    template = GetTemplateData(entType);
     212                }
     213                else if (item.technologyTemplate)
     214                {
     215                    entType = item.technologyTemplate;
     216                    template = GetTechnologyData(entType);
     217                }
     218           
     219                if (!template)
     220                    continue; // ignore attempts to use invalid templates (an error should have been
     221                              // reported already)
     222                break;
     223            case RESEARCH:
     224                entType = item;
     225                template = GetTechnologyData(entType);
     226                if (!template)
     227                    continue; // ignore attempts to use invalid templates (an error should have been
     228                              // reported already)
     229                break;
     230            case SELECTION:
     231            case GARRISON:
     232            case TRAINING:
     233            case CONSTRUCTION:
     234                entType = item;
     235                template = GetTemplateData(entType);
     236                if (!template)
     237                    continue; // ignore attempts to use invalid templates (an error should have been
     238                              // reported already)
     239                break;
    193240        }
    194241
    195242        switch (guiName)
     
    233280                if (template.tooltip)
    234281                    tooltip += "\n[font=\"serif-13\"]" + template.tooltip + "[/font]";
    235282
    236                 var [batchSize, batchIncrement] = getTrainingQueueBatchStatus(unitEntState.id, entType);
     283                var [batchSize, batchIncrement] = getTrainingBatchStatus(unitEntState.id, entType);
    237284                var trainNum = batchSize ? batchSize+batchIncrement : batchIncrement;
    238285
    239286                tooltip += "\n" + getEntityCost(template);
     
    250297                tooltip += "\n\n[font=\"serif-bold-13\"]Shift-click[/font][font=\"serif-13\"] to train " + trainNum + ".[/font]";
    251298
    252299                break;
     300               
     301            case RESEARCH:
     302                var tooltip = getEntityNameWithGenericType(template);
    253303
     304                if (template.tooltip)
     305                    tooltip += "\n[font=\"serif-13\"]" + template.tooltip + "[/font]";
     306
     307                tooltip += "\n" + getEntityCost(template);
     308                break;
     309
    254310            case CONSTRUCTION:
    255311                var tooltip = getEntityNameWithGenericType(template);
    256312                if (template.tooltip)
     
    352408        }
    353409        else if (template.icon)
    354410        {
    355             icon.sprite = "stretched:session/portraits/" + template.icon;
     411            var grayscale = "";
     412            button.enabled = true;
     413           
     414            if (template.requiredTechnology && !Engine.GuiInterfaceCall("IsTechnologyResearched", template.requiredTechnology))
     415            {
     416                button.enabled = false;
     417                var techName = getEntityName(GetTechnologyData(template.requiredTechnology));
     418                button.tooltip += "\nRequires " + techName;
     419                grayscale = "grayscale:";
     420            }
     421           
     422            if (guiName == RESEARCH && !Engine.GuiInterfaceCall("CheckTechnologyRequirements", entType))
     423            {
     424                button.enabled = false;
     425                button.tooltip += "\n" + GetTechnologyData(entType).requirementsTooltip;
     426                grayscale = "grayscale:";
     427            }
     428           
     429            icon.sprite = "stretched:" + grayscale + "session/portraits/" + template.icon;
    356430        }
    357431        else
    358432        {
     
    537611        {
    538612            setupUnitPanel("Construction", usedPanels, entState, entState.buildEntities, startBuildingPlacement);
    539613        }
    540 
    541         if (entState.training && entState.training.entities.length)
     614       
     615        if (entState.production && entState.production.entities.length)
    542616        {
    543             setupUnitPanel("Training", usedPanels, entState, entState.training.entities,
    544                 function (trainEntType) { addToTrainingQueue(entState.id, trainEntType); } );
     617            setupUnitPanel("Training", usedPanels, entState, entState.production.entities,
     618                function (trainEntType) { addTrainingToQueue(entState.id, trainEntType); } );
    545619        }
     620       
     621        if (entState.production && entState.production.technologies.length)
     622        {
     623            setupUnitPanel("Research", usedPanels, entState, entState.production.technologies,
     624                function (researchType) { addResearchToQueue(entState.id, researchType); } );
     625        }
    546626
    547         if (entState.training && entState.training.queue.length)
    548             setupUnitPanel("Queue", usedPanels, entState, entState.training.queue,
    549                 function (item) { removeFromTrainingQueue(entState.id, item.id); } );
     627        if (entState.production && entState.production.queue.length)
     628            setupUnitPanel("Queue", usedPanels, entState, entState.production.queue,
     629                function (item) { removeFromProductionQueue(entState.id, item.id); } );
    550630
    551631        if (entState.trader)
    552632        {
  • binaries/data/mods/public/gui/session/session.js

     
    1515
    1616// Indicate when one of the current player's training queues is blocked
    1717// (this is used to support population counter blinking)
    18 var g_IsTrainingQueueBlocked = false;
     18var g_IsTrainingBlocked = false;
    1919
    2020// Cache EntityStates
    2121var g_EntityStates = {}; // {id:entState}
     
    5353    return g_TemplateData[templateName];
    5454}
    5555
     56// Cache TechnologyData
     57var g_TechnologyData = {}; // {id:template}
     58
     59function GetTechnologyData(technologyName)
     60{
     61    if (!(technologyName in g_TechnologyData))
     62    {
     63        var template = Engine.GuiInterfaceCall("GetTechnologyData", technologyName);
     64        g_TechnologyData[technologyName] = template;
     65    }
     66
     67    return g_TechnologyData[technologyName];
     68}
     69
    5670// Init
    5771function init(initData, hotloadData)
    5872{
     
    206220    global.music.updateTimer();
    207221
    208222    // When training is blocked, flash population (alternates colour every 500msec)
    209     if (g_IsTrainingQueueBlocked && (Date.now() % 1000) < 500)
     223    if (g_IsTrainingBlocked && (Date.now() % 1000) < 500)
    210224        getGUIObjectByName("resourcePop").textcolor = POPULATION_ALERT_COLOR;
    211225    else
    212226        getGUIObjectByName("resourcePop").textcolor = DEFAULT_POPULATION_COLOR;
     
    257271    g_Selection.dirty = false;
    258272    g_EntityStates = {};
    259273    g_TemplateData = {};
     274    g_TechnologyData = {};
    260275
    261276    var simState = Engine.GuiInterfaceCall("GetSimulationState");
    262277
     
    345360    getGUIObjectByName("resourceMetal").caption = playerState.resourceCounts.metal;
    346361    getGUIObjectByName("resourcePop").caption = playerState.popCount + "/" + playerState.popLimit;
    347362
    348     g_IsTrainingQueueBlocked = playerState.trainingQueueBlocked;
     363    g_IsTrainingBlocked = playerState.trainingBlocked;
    349364}
    350365
    351366function updateTimeElapsedCounter(simState)
  • binaries/data/mods/public/simulation/helpers/Commands.js

     
    135135        // Verify that the building can be controlled by the player
    136136        if (CanControlUnit(cmd.entity, player, controlAllUnits))
    137137        {
    138             var queue = Engine.QueryInterface(cmd.entity, IID_TrainingQueue);
    139             if (queue)
    140                 queue.AddBatch(cmd.template, +cmd.count, cmd.metadata);
     138            var cmpTechMan = QueryOwnerInterface(cmd.entity, IID_TechnologyManager);
     139            // TODO: Enable this check once the AI gets technology support
     140            if (cmpTechMan.CanProduce(cmd.template) || true)
     141            {
     142                var queue = Engine.QueryInterface(cmd.entity, IID_ProductionQueue);
     143                if (queue)
     144                    queue.AddBatch(cmd.template, "unit", +cmd.count, cmd.metadata);
     145            }
     146            else if (g_DebugCommands)
     147            {
     148                warn("Invalid command: training requires unresearched technology: " + uneval(cmd));
     149            }
    141150        }
    142151        else if (g_DebugCommands)
    143152        {
     
    145154        }
    146155        break;
    147156
    148     case "stop-train":
     157    case "research":
    149158        // Verify that the building can be controlled by the player
    150159        if (CanControlUnit(cmd.entity, player, controlAllUnits))
    151160        {
    152             var queue = Engine.QueryInterface(cmd.entity, IID_TrainingQueue);
     161            var cmpTechMan = QueryOwnerInterface(cmd.entity, IID_TechnologyManager);
     162            // TODO: Enable this check once the AI gets technology support
     163            if (cmpTechMan.CanResearch(cmd.template) || true)
     164            {
     165                var queue = Engine.QueryInterface(cmd.entity, IID_ProductionQueue);
     166                if (queue)
     167                    queue.AddBatch(cmd.template, "technology");
     168            }
     169            else if (g_DebugCommands)
     170            {
     171                warn("Invalid command: Requirements to research technology are not met: " + uneval(cmd));
     172            }
     173        }
     174        else if (g_DebugCommands)
     175        {
     176            warn("Invalid command: research building cannot be controlled by player "+player+": "+uneval(cmd));
     177        }
     178        break;
     179
     180    case "stop-production":
     181        // Verify that the building can be controlled by the player
     182        if (CanControlUnit(cmd.entity, player, controlAllUnits))
     183        {
     184            var queue = Engine.QueryInterface(cmd.entity, IID_ProductionQueue);
    153185            if (queue)
    154186                queue.RemoveBatch(cmd.id);
    155187        }
    156188        else if (g_DebugCommands)
    157189        {
    158             warn("Invalid command: training building cannot be controlled by player "+player+": "+uneval(cmd));
     190            warn("Invalid command: production building cannot be controlled by player "+player+": "+uneval(cmd));
    159191        }
    160192        break;
    161193
     
    233265            Engine.DestroyEntity(ent);
    234266            break;
    235267        }
     268       
     269        var cmpTechMan = QueryPlayerIDInterface(player, IID_TechnologyManager);
     270        // TODO: Enable this check once the AI gets technology support
     271        if (!cmpTechMan.CanProduce(cmd.template) && false)
     272        {
     273            if (g_DebugCommands)
     274            {
     275                warn("Invalid command: required technology check failed for player "+player+": "+uneval(cmd));
     276            }
    236277
     278            var cmpGuiInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface);
     279            cmpGuiInterface.PushNotification({ "player": player, "message": "Building's technology requirements are not met." });
     280
     281            // Remove the foundation because the construction was aborted
     282            Engine.DestroyEntity(ent);
     283        }
     284
    237285        // TODO: AI has no visibility info
    238286        if (!cmpPlayer.IsAI())
    239287        {
  • binaries/data/mods/public/simulation/components/GuiInterface.js

     
    6666            "popLimit": cmpPlayer.GetPopulationLimit(),
    6767            "popMax": cmpPlayer.GetMaxPopulation(),
    6868            "resourceCounts": cmpPlayer.GetResourceCounts(),
    69             "trainingQueueBlocked": cmpPlayer.IsTrainingQueueBlocked(),
     69            "trainingBlocked": cmpPlayer.IsTrainingBlocked(),
    7070            "state": cmpPlayer.GetState(),
    7171            "team": cmpPlayer.GetTeam(),
    7272            "phase": cmpPlayer.GetPhase(),
     
    177177        ret.buildEntities = cmpBuilder.GetEntitiesList();
    178178    }
    179179
    180     var cmpTrainingQueue = Engine.QueryInterface(ent, IID_TrainingQueue);
    181     if (cmpTrainingQueue)
     180    var cmpProductionQueue = Engine.QueryInterface(ent, IID_ProductionQueue);
     181    if (cmpProductionQueue)
    182182    {
    183         ret.training = {
    184             "entities": cmpTrainingQueue.GetEntitiesList(),
    185             "queue": cmpTrainingQueue.GetQueue(),
     183        ret.production = {
     184            "entities": cmpProductionQueue.GetEntitiesList(),
     185            "technologies": cmpProductionQueue.GetTechnologiesList(),
     186            "queue": cmpProductionQueue.GetQueue(),
    186187        };
    187188    }
    188189
     
    346347        };
    347348        ret.icon = template.Identity.Icon;
    348349        ret.tooltip =  template.Identity.Tooltip;
     350        ret.requiredTechnology = template.Identity.RequiredTechnology;
    349351    }
    350352
    351353    if (template.UnitMotion)
     
    359361    return ret;
    360362};
    361363
     364GuiInterface.prototype.GetTechnologyData = function(player, name)
     365{
     366    var cmpTechTempMan = Engine.QueryInterface(SYSTEM_ENTITY, IID_TechnologyTemplateManager);
     367    var template = cmpTechTempMan.GetTemplate(name);
     368   
     369    if (!template)
     370    {
     371        warn("tried to get data for invaalid technology: " + name);
     372        return null;
     373    }
     374   
     375    var ret = {};
     376   
     377    var cmpPlayer = QueryPlayerIDInterface(player, IID_Player);
     378    var specific = template.specificName;
     379    if (template["specificName_" + cmpPlayer.GetCiv()])
     380        specific = template["specificName_" + cmpPlayer.GetCiv()];
     381   
     382    ret.name = {
     383        "specific": specific,
     384        "generic": template.genericName,
     385    };
     386    ret.icon = template.icon;
     387    ret.cost = {
     388        "food": +template.cost.food,
     389        "wood": +template.cost.wood,
     390        "metal": +template.cost.metal,
     391        "stone": +template.cost.stone,
     392    }
     393    ret.tooltip = template.tooltip;
     394   
     395    if (template.requirementsTooltip)
     396        ret.requirementsTooltip = template.requirementsTooltip;
     397    else
     398        ret.requirementsTooltip = "";
     399   
     400    ret.description = template.description;
     401   
     402    return ret;
     403};
     404
     405GuiInterface.prototype.IsTechnologyResearched = function(player, tech)
     406{
     407    var cmpTechMan = QueryPlayerIDInterface(player, IID_TechnologyManager);
     408   
     409    if (!cmpTechMan)
     410        return false;
     411   
     412    return cmpTechMan.IsTechnologyResearched(tech);
     413}
     414
     415// Checks whether the requirements for this technology have been met
     416GuiInterface.prototype.CheckTechnologyRequirements = function(player, tech)
     417{
     418    var cmpTechMan = QueryPlayerIDInterface(player, IID_TechnologyManager);
     419   
     420    if (!cmpTechMan)
     421        return false;
     422   
     423    return cmpTechMan.CanResearch(tech);
     424}
     425
    362426GuiInterface.prototype.PushNotification = function(notification)
    363427{
    364428    this.notifications.push(notification);
     
    812876    "ClearRenamedEntities": 1,
    813877    "GetEntityState": 1,
    814878    "GetTemplateData": 1,
     879    "GetTechnologyData": 1,
     880    "IsTechnologyResearched": 1,
     881    "CheckTechnologyRequirements": 1,
    815882    "GetNextNotification": 1,
    816883
    817884    "GetFormationRequirements": 1,
  • binaries/data/mods/public/simulation/components/interfaces/TrainingQueue.js

     
    1 Engine.RegisterInterface("TrainingQueue");
    2 
    3 // Message of the form { } (use GetQueue if you want the current details),
    4 // sent to the current entity whenever the training queue changes.
    5 Engine.RegisterMessageType("TrainingQueueChanged");
    6 
    7 // Message of the form { entities: [id, ...], metadata: ... }
    8 // sent to the current entity whenever a unit has been trained.
    9 Engine.RegisterMessageType("TrainingFinished");
  • binaries/data/mods/public/simulation/components/interfaces/TechnologyManager.js

     
     1Engine.RegisterInterface("TechnologyManager");
     2
     3// Message of the form { "component": "Attack", "player": 3 }
     4// Sent when a new technology is researched which modifies a component
     5Engine.RegisterMessageType("TechnologyModificationChange");
  • binaries/data/mods/public/simulation/components/interfaces/ProductionQueue.js

     
    1 Engine.RegisterInterface("TrainingQueue");
     1Engine.RegisterInterface("ProductionQueue");
    22
    33// Message of the form { } (use GetQueue if you want the current details),
    44// sent to the current entity whenever the training queue changes.
    5 Engine.RegisterMessageType("TrainingQueueChanged");
     5Engine.RegisterMessageType("ProductionQueueChanged");
    66
    77// Message of the form { entities: [id, ...], metadata: ... }
    88// sent to the current entity whenever a unit has been trained.
  • binaries/data/mods/public/simulation/components/interfaces/TechnologyTemplateManager.js

     
     1Engine.RegisterInterface("TechnologyTemplateManager");
     2 No newline at end of file
  • binaries/data/mods/public/simulation/components/ResourceGatherer.js

     
    125125        return undefined;
    126126};
    127127
     128// Remove any cached template data which is based on technology data
     129ResourceGatherer.prototype.OnTechnologyModificationChange = function(msg)
     130{
     131    var cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership);
     132    if (!cmpOwnership)
     133        return;
     134   
     135    var player = cmpOwnership.GetOwner();
     136   
     137    if (msg.component === "ResourceGatherer" && msg.player === player)
     138        delete this.gatherRatesCache;
     139};
     140
    128141ResourceGatherer.prototype.GetGatherRates = function()
    129142{
    130     var ret = {};
    131     for (var r in this.template.Rates)
    132         ret[r] = this.template.Rates[r] * this.template.BaseSpeed;
    133     return ret;
     143    if (!this.gatherRatesCache){
     144        this.gatherRatesCache = {};
     145        var cmpTechManager = QueryOwnerInterface(this.entity, IID_TechnologyManager);
     146        var baseSpeed = cmpTechManager.ApplyModifications("ResourceGatherer/BaseSpeed", this.template.BaseSpeed, this.entity);
     147        for (var r in this.template.Rates)
     148        {
     149            var rate = cmpTechManager.ApplyModifications("ResourceGatherer/Rates/" + r, this.template.Rates[r], this.entity);
     150            this.gatherRatesCache[r] = rate * baseSpeed;
     151        }
     152    }
     153   
     154    return this.gatherRatesCache;
    134155};
    135156
    136157ResourceGatherer.prototype.GetRange = function()
    137158{
    138159    return { "max": +this.template.MaxDistance, "min": 0 };
    139160    // maybe this should depend on the unit or target or something?
    140 }
     161};
    141162
    142163/**
    143164 * Try to gather treasure
     
    223244    var type = cmpResourceSupply.GetType();
    224245
    225246    var rate;
    226     if (type.specific && this.template.Rates[type.generic+"."+type.specific])
    227         rate = this.template.Rates[type.generic+"."+type.specific];
     247    if (type.specific && this.GetGatherRates()[type.generic+"."+type.specific])
     248        rate = this.GetGatherRates()[type.generic+"."+type.specific];
    228249    else
    229         rate = this.template.Rates[type.generic];
     250        rate = this.GetGatherRates()[type.generic];
    230251
    231     return (rate || 0) * this.template.BaseSpeed;
    232 }
     252    return (rate || 0);
     253};
    233254
    234255/**
    235256 * Returns whether this unit can carry more of the given type of resource.
  • binaries/data/mods/public/simulation/components/TrainingQueue.js

     
    1 var g_ProgressInterval = 1000;
    2 const MAX_QUEUE_SIZE = 16;
    3 
    4 function TrainingQueue() {}
    5 
    6 TrainingQueue.prototype.Schema =
    7     "<a:help>Allows the building to train new units.</a:help>" +
    8     "<a:example>" +
    9         "<Entities datatype='tokens'>" +
    10             "\n    units/{civ}_support_female_citizen\n    units/{civ}_support_trader\n    units/celt_infantry_spearman_b\n  " +
    11         "</Entities>" +
    12     "</a:example>" +
    13     "<element name='Entities' a:help='Space-separated list of entity template names that this building can train. The special string \"{civ}\" will be automatically replaced by the building&apos;s four-character civ code'>" +
    14         "<attribute name='datatype'>" +
    15             "<value>tokens</value>" +
    16         "</attribute>" +
    17         "<text/>" +
    18     "</element>";
    19 
    20 TrainingQueue.prototype.Init = function()
    21 {
    22     this.nextID = 1;
    23 
    24     this.queue = [];
    25     // Queue items are:
    26     //   {
    27     //     "id": 1,
    28     //     "player": 1, // who paid for this batch; we need this to cope with refunds cleanly
    29     //     "template": "units/example",
    30     //     "count": 10,
    31     //     "resources": { "wood": 100, ... },   // resources per unit, multiply by count to get total
    32     //     "population": 1, // population per unit, multiply by count to get total
    33     //     "trainingStarted": false, // true iff we have reserved population
    34     //     "timeTotal": 15000, // msecs
    35     //     "timeRemaining": 10000, // msecs
    36     //   }
    37    
    38     this.timer = undefined; // g_ProgressInterval msec timer, active while the queue is non-empty
    39    
    40     this.entityCache = [];
    41     this.spawnNotified = false;
    42 };
    43 
    44 /*
    45  * Returns list of entities that can be trained by this building.
    46  */
    47 TrainingQueue.prototype.GetEntitiesList = function()
    48 {
    49     var string = this.template.Entities._string;
    50    
    51     // Replace the "{civ}" codes with this entity's civ ID
    52     var cmpIdentity = Engine.QueryInterface(this.entity, IID_Identity);
    53     if (cmpIdentity)
    54         string = string.replace(/\{civ\}/g, cmpIdentity.GetCiv());
    55    
    56     return string.split(/\s+/);
    57 };
    58 
    59 /*
    60  * Adds a new batch of identical units to the training queue.
    61  */
    62 TrainingQueue.prototype.AddBatch = function(templateName, count, metadata)
    63 {
    64     // TODO: there should probably be a limit on the number of queued batches
    65     // TODO: there should be a way for the GUI to determine whether it's going
    66     // to be possible to add a batch (based on resource costs and length limits)
    67     var cmpPlayer = QueryOwnerInterface(this.entity, IID_Player);
    68 
    69     if (this.queue.length < MAX_QUEUE_SIZE)
    70     {
    71         // Find the template data so we can determine the build costs
    72         var cmpTempMan = Engine.QueryInterface(SYSTEM_ENTITY, IID_TemplateManager);
    73         var template = cmpTempMan.GetTemplate(templateName);
    74         if (!template)
    75             return;
    76 
    77         // Apply a time discount to larger batches.
    78         // TODO: work out what equation we should use here.
    79         var timeMult = Math.pow(count, 0.7);
    80 
    81         var time = timeMult * template.Cost.BuildTime;
    82 
    83         var totalCosts = {};
    84         for each (var r in ["food", "wood", "stone", "metal"])
    85             totalCosts[r] = Math.floor(count * template.Cost.Resources[r]);
    86 
    87         var population = template.Cost.Population;
    88    
    89         // TrySubtractResources should report error to player (they ran out of resources)
    90         if (!cmpPlayer.TrySubtractResources(totalCosts))
    91             return;
    92 
    93         this.queue.push({
    94             "id": this.nextID++,
    95             "player": cmpPlayer.GetPlayerID(),
    96             "template": templateName,
    97             "count": count,
    98             "metadata": metadata,
    99             "resources": deepcopy(template.Cost.Resources), // need to copy to avoid serialization problems
    100             "population": population,
    101             "trainingStarted": false,
    102             "timeTotal": time*1000,
    103             "timeRemaining": time*1000,
    104         });
    105         Engine.PostMessage(this.entity, MT_TrainingQueueChanged, { });
    106 
    107         // If this is the first item in the queue, start the timer
    108         if (!this.timer)
    109         {
    110             var cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
    111             this.timer = cmpTimer.SetTimeout(this.entity, IID_TrainingQueue, "ProgressTimeout", g_ProgressInterval, {});
    112         }
    113     }
    114     else
    115     {
    116         var notification = {"player": cmpPlayer.GetPlayerID(), "message": "The training queue is full."};
    117         var cmpGUIInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface);
    118         cmpGUIInterface.PushNotification(notification);
    119     }
    120 };
    121 
    122 /*
    123  * Removes an existing batch of units from the training queue.
    124  * Refunds resource costs and population reservations.
    125  */
    126 TrainingQueue.prototype.RemoveBatch = function(id)
    127 {
    128     // Destroy any cached entities (those which didn't spawn for some reason)
    129     for (var i = 0; i < this.entityCache.length; ++i)
    130     {
    131         Engine.DestroyEntity(this.entityCache[i]);
    132     }
    133     this.entityCache = [];
    134    
    135     for (var i = 0; i < this.queue.length; ++i)
    136     {
    137         var item = this.queue[i];
    138         if (item.id != id)
    139             continue;
    140 
    141         // Now we've found the item to remove
    142 
    143         var cmpPlayer = QueryPlayerIDInterface(item.player, IID_Player);
    144 
    145         // Refund the resource cost for this batch
    146         var totalCosts = {};
    147         for each (var r in ["food", "wood", "stone", "metal"])
    148             totalCosts[r] = Math.floor(item.count * item.resources[r]);
    149            
    150         cmpPlayer.AddResources(totalCosts);
    151 
    152         // Remove reserved population slots if necessary
    153         if (item.trainingStarted)
    154             cmpPlayer.UnReservePopulationSlots(item.population * item.count);
    155 
    156         // Remove from the queue
    157         // (We don't need to remove the timer - it'll expire if it discovers the queue is empty)
    158         this.queue.splice(i, 1);
    159         Engine.PostMessage(this.entity, MT_TrainingQueueChanged, { });
    160 
    161         return;
    162     }
    163 };
    164 
    165 /*
    166  * Returns basic data from all batches in the training queue.
    167  */
    168 TrainingQueue.prototype.GetQueue = function()
    169 {
    170     var out = [];
    171     for each (var item in this.queue)
    172     {
    173         out.push({
    174             "id": item.id,
    175             "template": item.template,
    176             "count": item.count,
    177             "progress": 1-(item.timeRemaining/item.timeTotal),
    178             "metadata": item.metadata,
    179         });
    180     }
    181     return out;
    182 };
    183 
    184 /*
    185  * Removes all existing batches from the queue.
    186  */
    187 TrainingQueue.prototype.ResetQueue = function()
    188 {
    189     // Empty the training queue and refund all the resource costs
    190     // to the player. (This is to avoid players having to micromanage their
    191     // buildings' queues when they're about to be destroyed or captured.)
    192 
    193     while (this.queue.length)
    194         this.RemoveBatch(this.queue[0].id);
    195 };
    196 
    197 TrainingQueue.prototype.OnOwnershipChanged = function(msg)
    198 {
    199     if (msg.from != -1)
    200     {
    201         // Unset flag that previous owner's training queue may be blocked
    202         var cmpPlayer = QueryPlayerIDInterface(msg.from, IID_Player);
    203         if (cmpPlayer && this.queue.length > 0)
    204             cmpPlayer.UnBlockTrainingQueue();
    205     }
    206 
    207     // Reset the training queue whenever the owner changes.
    208     // (This should prevent players getting surprised when they capture
    209     // an enemy building, and then loads of the enemy's civ's soldiers get
    210     // created from it. Also it means we don't have to worry about
    211     // updating the reserved pop slots.)
    212     this.ResetQueue();
    213 };
    214 
    215 TrainingQueue.prototype.OnDestroy = function()
    216 {
    217     // Reset the queue to refund any resources
    218     this.ResetQueue();
    219 
    220     if (this.timer)
    221     {
    222         var cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
    223         cmpTimer.CancelTimer(this.timer);
    224     }
    225 };
    226 
    227 /*
    228  * This function creates the entities and places them in world if possible.
    229  * returns the number of successfully spawned entities.
    230  */
    231 TrainingQueue.prototype.SpawnUnits = function(templateName, count, metadata)
    232 {
    233     var cmpFootprint = Engine.QueryInterface(this.entity, IID_Footprint);
    234     var cmpPosition = Engine.QueryInterface(this.entity, IID_Position);
    235     var cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership);
    236     var cmpRallyPoint = Engine.QueryInterface(this.entity, IID_RallyPoint);
    237    
    238     var spawnedEnts = [];
    239    
    240     if (this.entityCache.length == 0)
    241     {
    242         // We need entities to test spawning, but we don't want to waste resources,
    243         //  so only create them once and use as needed
    244         for (var i = 0; i < count; ++i)
    245         {
    246             this.entityCache.push(Engine.AddEntity(templateName));
    247         }
    248     }
    249 
    250     for (var i = 0; i < count; ++i)
    251     {
    252         var ent = this.entityCache[0];
    253         var pos = cmpFootprint.PickSpawnPoint(ent);
    254         if (pos.y < 0)
    255         {
    256             // Fail: there wasn't any space to spawn the unit
    257             break;
    258         }
    259         else
    260         {
    261             // Successfully spawned
    262             var cmpNewPosition = Engine.QueryInterface(ent, IID_Position);
    263             cmpNewPosition.JumpTo(pos.x, pos.z);
    264             // TODO: what direction should they face in?
    265 
    266             var cmpNewOwnership = Engine.QueryInterface(ent, IID_Ownership);
    267             cmpNewOwnership.SetOwner(cmpOwnership.GetOwner());
    268            
    269             var cmpPlayerStatisticsTracker = QueryOwnerInterface(this.entity, IID_StatisticsTracker);
    270             cmpPlayerStatisticsTracker.IncreaseTrainedUnitsCounter();
    271 
    272             // Play a sound, but only for the first in the batch (to avoid nasty phasing effects)
    273             if (spawnedEnts.length == 0)
    274                 PlaySound("trained", ent);
    275            
    276             this.entityCache.shift();
    277             spawnedEnts.push(ent);
    278         }
    279     }
    280 
    281     if (spawnedEnts.length > 0)
    282     {
    283         // If a rally point is set, walk towards it (in formation) using a suitable command based on where the
    284         // rally point is placed.
    285         if (cmpRallyPoint)
    286         {
    287             var rallyPos = cmpRallyPoint.GetPosition();
    288             if (rallyPos)
    289             {
    290                 ProcessCommand(cmpOwnership.GetOwner(), GetRallyPointCommand(cmpRallyPoint, spawnedEnts));
    291             }
    292         }
    293 
    294         Engine.PostMessage(this.entity, MT_TrainingFinished, {
    295             "entities": spawnedEnts,
    296             "owner": cmpOwnership.GetOwner(),
    297             "metadata": metadata,
    298         });
    299     }
    300    
    301     return spawnedEnts.length;
    302 };
    303 
    304 /*
    305  * Increments progress on the first batch in the training queue, and blocks the
    306  * queue if population limit is reached or some units failed to spawn.
    307  */
    308 TrainingQueue.prototype.ProgressTimeout = function(data)
    309 {
    310     // Allocate the 1000msecs to as many queue items as it takes
    311     // until we've used up all the time (so that we work accurately
    312     // with items that take fractions of a second)
    313     var time = g_ProgressInterval;
    314     var cmpPlayer = QueryOwnerInterface(this.entity, IID_Player);
    315 
    316     while (time > 0 && this.queue.length)
    317     {
    318         var item = this.queue[0];
    319         if (!item.trainingStarted)
    320         {
    321             // Batch's training hasn't started yet.
    322             // Try to reserve the necessary population slots
    323             if (!cmpPlayer.TryReservePopulationSlots(item.population * item.count))
    324             {
    325                 // No slots available - don't train this batch now
    326                 // (we'll try again on the next timeout)
    327 
    328                 // Set flag that training queue is blocked
    329                 cmpPlayer.BlockTrainingQueue();
    330                 break;
    331             }
    332 
    333             // Unset flag that training queue is blocked
    334             cmpPlayer.UnBlockTrainingQueue();
    335 
    336             item.trainingStarted = true;
    337         }
    338 
    339         // If we won't finish the batch now, just update its timer
    340         if (item.timeRemaining > time)
    341         {
    342             item.timeRemaining -= time;
    343             break;
    344         }
    345 
    346         var numSpawned = this.SpawnUnits(item.template, item.count, item.metadata);
    347         if (numSpawned == item.count)
    348         {
    349             // All entities spawned, this batch finished
    350             cmpPlayer.UnReservePopulationSlots(item.population * numSpawned);
    351             time -= item.timeRemaining;
    352             this.queue.shift();
    353             // Unset flag that training queue is blocked
    354             cmpPlayer.UnBlockTrainingQueue();
    355             this.spawnNotified = false;
    356             Engine.PostMessage(this.entity, MT_TrainingQueueChanged, { });
    357         }
    358         else
    359         {
    360             if (numSpawned > 0)
    361             {
    362                 // Only partially finished
    363                 cmpPlayer.UnReservePopulationSlots(item.population * numSpawned);
    364                 item.count -= numSpawned;
    365                 Engine.PostMessage(this.entity, MT_TrainingQueueChanged, { });
    366             }
    367 
    368             // Some entities failed to spawn
    369             // Set flag that training queue is blocked
    370             cmpPlayer.BlockTrainingQueue();
    371            
    372             if (!this.spawnNotified)
    373             {
    374                 var cmpPlayer = QueryOwnerInterface(this.entity, IID_Player);
    375                 var notification = {"player": cmpPlayer.GetPlayerID(), "message": "Can't find free space to spawn trained units" };
    376                 var cmpGUIInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface);
    377                 cmpGUIInterface.PushNotification(notification);
    378                 this.spawnNotified = true;
    379             }
    380             break;
    381         }
    382     }
    383 
    384     // If the queue's empty, delete the timer, else repeat it
    385     if (this.queue.length == 0)
    386     {
    387         this.timer = undefined;
    388 
    389         // Unset flag that training queue is blocked
    390         // (This might happen when the player unqueues all batches)
    391         cmpPlayer.UnBlockTrainingQueue();
    392     }
    393     else
    394     {
    395         var cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
    396         this.timer = cmpTimer.SetTimeout(this.entity, IID_TrainingQueue, "ProgressTimeout", g_ProgressInterval, data);
    397     }
    398 }
    399 
    400 Engine.RegisterComponentType(IID_TrainingQueue, "TrainingQueue", TrainingQueue);
  • binaries/data/mods/public/simulation/components/tests/test_GuiInterface.js

     
    1212Engine.LoadComponentScript("interfaces/ResourceDropsite.js");
    1313Engine.LoadComponentScript("interfaces/ResourceGatherer.js");
    1414Engine.LoadComponentScript("interfaces/ResourceSupply.js");
    15 Engine.LoadComponentScript("interfaces/TrainingQueue.js");
     15Engine.LoadComponentScript("interfaces/ProductionQueue.js");
    1616Engine.LoadComponentScript("interfaces/Trader.js")
    1717Engine.LoadComponentScript("interfaces/Timer.js");
    1818Engine.LoadComponentScript("interfaces/StatisticsTracker.js");
     
    5858    GetPopulationLimit: function() { return 20; },
    5959    GetMaxPopulation: function() { return 200; },
    6060    GetResourceCounts: function() { return { food: 100 }; },
    61     IsTrainingQueueBlocked: function() { return false; },
     61    IsTrainingBlocked: function() { return false; },
    6262    GetState: function() { return "active"; },
    6363    GetTeam: function() { return -1; },
    6464    GetDiplomacy: function() { return [-1, 1]; },
     
    105105    GetPopulationLimit: function() { return 30; },
    106106    GetMaxPopulation: function() { return 300; },
    107107    GetResourceCounts: function() { return { food: 200 }; },
    108     IsTrainingQueueBlocked: function() { return false; },
     108    IsTrainingBlocked: function() { return false; },
    109109    GetState: function() { return "active"; },
    110110    GetTeam: function() { return -1; },
    111111    GetDiplomacy: function() { return [-1, 1]; },
     
    157157            popLimit: 20,
    158158            popMax: 200,
    159159            resourceCounts: { food: 100 },
    160             trainingQueueBlocked: false,
     160            trainingBlocked: false,
    161161            state: "active",
    162162            team: -1,
    163163            phase: "",
     
    174174            popLimit: 30,
    175175            popMax: 300,
    176176            resourceCounts: { food: 200 },
    177             trainingQueueBlocked: false,
     177            trainingBlocked: false,
    178178            state: "active",
    179179            team: -1,
    180180            phase: "village",
     
    198198            popLimit: 20,
    199199            popMax: 200,
    200200            resourceCounts: { food: 100 },
    201             trainingQueueBlocked: false,
     201            trainingBlocked: false,
    202202            state: "active",
    203203            team: -1,
    204204            phase: "",
     
    231231            popLimit: 30,
    232232            popMax: 300,
    233233            resourceCounts: { food: 200 },
    234             trainingQueueBlocked: false,
     234            trainingBlocked: false,
    235235            state: "active",
    236236            team: -1,
    237237            phase: "village",
  • binaries/data/mods/public/simulation/components/Identity.js

     
    6868        "<element name='Icon'>" +
    6969            "<text/>" +
    7070        "</element>" +
     71    "</optional>" +
     72    "<optional>" +
     73        "<element name='RequiredTechnology' a:help='Optional name of a technology which must be researched before the entity can be produced'>" +
     74            "<text/>" +
     75        "</element>" +
    7176    "</optional>";
    7277
    7378
     
    126131Identity.prototype.GetSelectionGroupName = function()
    127132{
    128133    return (this.template.SelectionGroupName || "");
    129 }
     134};
    130135
    131136Engine.RegisterComponentType(IID_Identity, "Identity", Identity);
  • binaries/data/mods/public/simulation/components/AIProxy.js

     
    119119    this.changes.unitAIOrderData = msg.to;
    120120};
    121121
    122 AIProxy.prototype.OnTrainingQueueChanged = function(msg)
     122AIProxy.prototype.OnProductionQueueChanged = function(msg)
    123123{
    124124    this.NotifyChange();
    125125
    126     var cmpTrainingQueue = Engine.QueryInterface(this.entity, IID_TrainingQueue);
    127     this.changes.trainingQueue = cmpTrainingQueue.GetQueue();
     126    var cmpProductionQueue = Engine.QueryInterface(this.entity, IID_ProductionQueue);
     127    this.changes.trainingQueue = cmpProductionQueue.GetQueue();
    128128};
    129129
    130130AIProxy.prototype.OnGarrisonedUnitsChanged = function(msg)
     
    206206        ret.unitAIOrderData = cmpUnitAI.GetOrderData();
    207207    }
    208208
    209     var cmpTrainingQueue = Engine.QueryInterface(this.entity, IID_TrainingQueue);
    210     if (cmpTrainingQueue)
     209    var cmpProductionQueue = Engine.QueryInterface(this.entity, IID_ProductionQueue);
     210    if (cmpProductionQueue)
    211211    {
    212         // Updated by OnTrainingQueueChanged
    213         ret.trainingQueue = cmpTrainingQueue.GetQueue();
     212        // Updated by OnProductionQueueChanged
     213        ret.trainingQueue = cmpProductionQueue.GetQueue();
    214214    }
    215215
    216216    var cmpFoundation = Engine.QueryInterface(this.entity, IID_Foundation);
  • binaries/data/mods/public/simulation/components/Player.js

     
    1212    this.popUsed = 0; // population of units owned or trained by this player
    1313    this.popBonuses = 0; // sum of population bonuses of player's entities
    1414    this.maxPop = 300; // maximum population
    15     this.trainingQueueBlocked = false; // indicates whether any training queue is currently blocked
     15    this.trainingBlocked = false; // indicates whether any training queue is currently blocked
    1616    this.resourceCount = {
    1717        "food": 1000,   
    1818        "wood": 1000,   
     
    104104    return this.maxPop;
    105105};
    106106
    107 Player.prototype.IsTrainingQueueBlocked = function()
     107Player.prototype.IsTrainingBlocked = function()
    108108{
    109     return this.trainingQueueBlocked;
     109    return this.trainingBlocked;
    110110};
    111111
    112 Player.prototype.BlockTrainingQueue = function()
     112Player.prototype.BlockTraining = function()
    113113{
    114     this.trainingQueueBlocked = true;
     114    this.trainingBlocked = true;
    115115};
    116116
    117 Player.prototype.UnBlockTrainingQueue = function()
     117Player.prototype.UnBlockTraining = function()
    118118{
    119     this.trainingQueueBlocked = false;
     119    this.trainingBlocked = false;
    120120};
    121121
    122122Player.prototype.SetResourceCounts = function(resources)
  • binaries/data/mods/public/simulation/components/TechnologyManager.js

     
     1function TechnologyManager() {}
     2
     3TechnologyManager.prototype.Schema =
     4    "<a:component type='system'/><empty/>";
     5
     6TechnologyManager.prototype.Init = function ()
     7{
     8    var cmpTechTempMan = Engine.QueryInterface(SYSTEM_ENTITY, IID_TechnologyTemplateManager);
     9    this.allTechs = cmpTechTempMan.GetAllTechs();
     10    this.researchedTechs = {}; // technologies which have been researched
     11    this.inProgressTechs = {}; // technologies which are being researched currently
     12   
     13    // This stores the modifications to unit stats from researched technologies
     14    // Example data: {"ResourceGatherer/Rates/food.grain": [ {"multiplier": 1.15, "affects": ["Female", "Infantry Swordsman"]},
     15    //                                                      {"add": 2} ]}
     16    this.modifications = {};
     17   
     18    this.typeCounts = {}; // stores the number of entities of each type
     19    this.classCounts = {}; // stores the number of entities of each Class
     20    this.typeCountsByClass = {}; // stores the number of entities of each type for each class i.e.
     21                                 // {"someClass": {"unit/spearman": 2, "unit/cav": 5} "someOtherClass":...}
     22   
     23    // Some technologies are automatically researched when their conditions are met.  They have no cost and are
     24    // researched instantly.  This allows civ bonuses and more complicated technologies.
     25    this.autoResearchTech = {};
     26    for (var key in this.allTechs)
     27    {
     28        if (this.allTechs[key].autoResearch)
     29            this.autoResearchTech[key] = this.allTechs[key];
     30    }
     31   
     32    this._UpdateAutoResearch();
     33};
     34
     35// This function checks if the requirements of any autoresearch techs are met and if they are it researches them
     36TechnologyManager.prototype._UpdateAutoResearch = function ()
     37{
     38    for (var key in this.autoResearchTech)
     39    {
     40        if (this.CanResearch(key))
     41        {
     42            delete this.autoResearchTech[key];
     43            this.ResearchTechnology(key);
     44            return; // We will have recursively handled any knock-on effects so can just return
     45        }
     46    }
     47}
     48
     49TechnologyManager.prototype.GetTechnologyTemplate = function (tech)
     50{
     51    return this.allTechs[tech];
     52};
     53
     54// This function checks an entity template to see if it's technology requirements have been met
     55TechnologyManager.prototype.CanProduce = function (templateName)
     56{
     57    var cmpTempManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_TemplateManager);
     58    var template = cmpTempManager.GetTemplate(templateName);
     59   
     60    if (template.Identity && template.Identity.RequiredTechnology)
     61        return this.IsTechnologyResearched(template.Identity.RequiredTechnology);
     62    else
     63        return true; // If there is no required technology then this entity can be produced
     64};
     65
     66TechnologyManager.prototype.IsTechnologyResearched = function (tech)
     67{
     68    return (this.researchedTechs[tech] !== undefined);
     69};
     70
     71// Checks the requirements for a technology to see if it can be researched at the current time
     72TechnologyManager.prototype.CanResearch = function (tech)
     73{
     74    var template = this.GetTechnologyTemplate(tech);
     75    if (!template)
     76    {
     77        warn("Technology \"" + tech + "\" does not exist");
     78        return false;
     79    }
     80   
     81    var ret = true;
     82   
     83    // The technology which this technology supercedes is required
     84    if (template.supercedes)
     85        ret = ret && this.IsTechnologyResearched(template.supercedes);
     86   
     87    ret = ret && this._CheckTechnologyRequirements(template.requirements);
     88   
     89    return ret;
     90};
     91
     92TechnologyManager.prototype._CheckTechnologyRequirements = function (reqs)
     93{
     94    // If there are no requirements then all requirements are met
     95    if (!reqs)
     96        return true;
     97   
     98    if (reqs.tech)
     99    {
     100        return this.IsTechnologyResearched(reqs.tech);
     101    }
     102    else if (reqs.all)
     103    {
     104        var ret = true;
     105        for (var i = 0; i < reqs.all.length; i++)
     106        {
     107            ret = ret && this._CheckTechnologyRequirements(reqs.all[i]);
     108        }
     109        return ret;
     110    }
     111    else if (reqs.any)
     112    {
     113        for (var i = 0; i < reqs.any.length; i++)
     114        {
     115            if (this._CheckTechnologyRequirements(reqs.any[i]))
     116                return true;
     117        }
     118        return false
     119    }
     120    else if (reqs["class"])
     121    {
     122        return (reqs.numberOfTypes <= Object.keys(this.typeCountsByClass[reqs["class"]]).length);
     123    }
     124   
     125    // The technologies requirements are not a recognised format
     126    error("Bad requirements " + uneval(reqs));
     127    return false;
     128};
     129
     130TechnologyManager.prototype.OnGlobalOwnershipChanged = function (msg)
     131{
     132    // This automatically updates typeCounts, classCounts and typeCountsByClass
     133    var playerID = (Engine.QueryInterface(this.entity, IID_Player)).GetPlayerID();
     134    if (msg.to == playerID)
     135    {
     136        var cmpTemplateManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_TemplateManager);
     137        var template = cmpTemplateManager.GetCurrentTemplateName(msg.entity);
     138       
     139        this.typeCounts[template] = this.typeCounts[template] || 0;
     140        this.typeCounts[template] += 1;
     141       
     142        // don't use foundations for the class counts
     143        if (Engine.QueryInterface(msg.entity, IID_Foundation))
     144            return;
     145       
     146        var cmpIdentity = Engine.QueryInterface(msg.entity, IID_Identity);
     147        if (cmpIdentity)
     148        {
     149            var classes = cmpIdentity.GetClassesList();
     150            for (var i in classes)
     151            {
     152                this.classCounts[classes[i]] = this.classCounts[classes[i]] || 0;
     153                this.classCounts[classes[i]] += 1;
     154               
     155                this.typeCountsByClass[classes[i]] = this.typeCountsByClass[classes[i]] || {};
     156                this.typeCountsByClass[classes[i]][template] = this.typeCountsByClass[classes[i]][template] || 0;
     157                this.typeCountsByClass[classes[i]][template] += 1;
     158            }
     159        }
     160    }
     161    if (msg.from == playerID)
     162    {
     163        var cmpTemplateManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_TemplateManager);
     164        var template = cmpTemplateManager.GetCurrentTemplateName(msg.entity);
     165       
     166        this.typeCounts[template] -= 1;
     167       
     168        // don't use foundations for the class counts
     169        if (Engine.QueryInterface(msg.entity, IID_Foundation))
     170            return;
     171       
     172        var cmpIdentity = Engine.QueryInterface(msg.entity, IID_Identity);
     173        if (cmpIdentity)
     174        {
     175            var classes = cmpIdentity.GetClassesList();
     176            for (var i in classes)
     177            {
     178                this.classCounts[classes[i]] -= 1;
     179               
     180                this.typeCountsByClass[classes[i]][template] -= 1;
     181            }
     182        }
     183    }
     184};
     185   
     186// Marks a technology as researched.  Note that this does not verify that the requirements are met.
     187TechnologyManager.prototype.ResearchTechnology = function (tech)
     188{
     189    this.StoppedResearch(tech); // The tech is no longer being currently researched
     190   
     191    var template = this.GetTechnologyTemplate(tech);
     192    if (template)
     193    {
     194        var modifiedComponents = {};
     195        this.researchedTechs[tech] = template;
     196        // store the modifications in an easy to access structure
     197        if (template.modifications)
     198        {
     199            var affects = [];
     200            if (template.affects && template.affects.length > 0)
     201            {
     202                for (var i in template.affects)
     203                {
     204                    // Put the list of classes into an array for convenient access
     205                    affects.push(template.affects[i].split(" "));
     206                }
     207            }
     208            else
     209            {
     210                affects.push([]);
     211            }
     212           
     213            // We add an item to this.modifications for every
     214            for (var i in template.modifications)
     215            {
     216                var modification = template.modifications[i];
     217                if (!this.modifications[modification.value])
     218                    this.modifications[modification.value] = [];
     219               
     220                var mod = {"affects": affects};
     221                // copy the modification data into our new data structure
     222                for (var j in modification)
     223                    if (j !== "value")
     224                        mod[j] = modification[j]
     225               
     226                this.modifications[modification.value].push(mod);
     227                modifiedComponents[modification.value.split("/")[0]] = true;
     228            }
     229        }
     230       
     231        var cmpPlayer = Engine.QueryInterface(this.entity, IID_Player);
     232        var player = cmpPlayer.GetPlayerID();
     233       
     234        for (var component in modifiedComponents)
     235            Engine.BroadcastMessage(MT_TechnologyModificationChange, { "component": component, "player": player });
     236       
     237        this._UpdateAutoResearch();
     238    }
     239    else
     240    {
     241        error("Tried to research invalid techonology: " + uneval(tech));
     242    }
     243};
     244
     245TechnologyManager.prototype.ApplyModifications = function(valueName, curValue, ent)
     246{   
     247    // Get all modifications to this value
     248    var modifications = this.modifications[valueName];
     249    if (!modifications) // no modifications so return the orignal value
     250        return curValue;
     251   
     252    // Get the classes which this entity belongs to
     253    var cmpIdentity = Engine.QueryInterface(ent, IID_Identity);
     254    var classes = cmpIdentity.GetClassesList();
     255   
     256    var retValue = +curValue;
     257   
     258    for (var i in modifications)
     259    {
     260        var modification = modifications[i];
     261        var applies = false;
     262        // See if any of the lists of classes matches this entity
     263        for (var j in modification.affects)
     264        {
     265            var hasAllClasses = true;
     266            // Check each
     267            for (var k in modification.affects[j])
     268                hasAllClasses = hasAllClasses && (classes.indexOf(modification.affects[j][k]) !== -1);
     269           
     270            if (hasAllClasses)
     271            {
     272                applies = true;
     273                break;
     274            }
     275        }
     276       
     277        // Nothing is cumulative so that ordering doesn't matter as much as possible
     278        if (modification.multiplier)
     279            retValue += (modification.multiplier - 1) * +curValue;
     280        else if (modification.add)
     281            retValue += modification.add;
     282        else if (modification.replace) // This will depend on ordering because there is no choice
     283            retValue = modification.replace;
     284        else
     285            warn("modification format not recognised (modifying " + valueName + "): " + uneval(modification));
     286    }
     287   
     288    return retValue;
     289};
     290
     291// Marks a technology as being currently researched
     292TechnologyManager.prototype.StartedResearch = function (tech)
     293{
     294    this.inProgressTechs[tech] = true;
     295};
     296
     297// Marks a technology as not being currently researched
     298TechnologyManager.prototype.StoppedResearch = function (tech)
     299{
     300    delete this.inProgressTechs[tech];
     301};
     302
     303// Checks whether a technology is being currently researched
     304TechnologyManager.prototype.IsInProgress = function(tech)
     305{
     306    if (this.inProgressTechs[tech])
     307        return true;
     308    else
     309        return false;
     310};
     311
     312Engine.RegisterComponentType(IID_TechnologyManager, "TechnologyManager", TechnologyManager);
  • binaries/data/mods/public/simulation/components/ProductionQueue.js

     
    11var g_ProgressInterval = 1000;
    22const MAX_QUEUE_SIZE = 16;
    33
    4 function TrainingQueue() {}
     4function ProductionQueue() {}
    55
    6 TrainingQueue.prototype.Schema =
    7     "<a:help>Allows the building to train new units.</a:help>" +
     6ProductionQueue.prototype.Schema =
     7    "<a:help>Allows the building to train new units and research technologies.</a:help>" +
    88    "<a:example>" +
    99        "<Entities datatype='tokens'>" +
    1010            "\n    units/{civ}_support_female_citizen\n    units/{civ}_support_trader\n    units/celt_infantry_spearman_b\n  " +
    1111        "</Entities>" +
    1212    "</a:example>" +
    13     "<element name='Entities' a:help='Space-separated list of entity template names that this building can train. The special string \"{civ}\" will be automatically replaced by the building&apos;s four-character civ code'>" +
    14         "<attribute name='datatype'>" +
    15             "<value>tokens</value>" +
    16         "</attribute>" +
    17         "<text/>" +
    18     "</element>";
     13    "<optional>" +
     14        "<element name='Entities' a:help='Space-separated list of entity template names that this building can train. The special string \"{civ}\" will be automatically replaced by the building&apos;s four-character civ code'>" +
     15            "<attribute name='datatype'>" +
     16                "<value>tokens</value>" +
     17            "</attribute>" +
     18            "<text/>" +
     19        "</element>" +
     20    "</optional>" +
     21    "<optional>" +
     22        "<element name='Technologies' a:help='Space-separated list of technology names that this building can research.'>" +
     23            "<attribute name='datatype'>" +
     24                "<value>tokens</value>" +
     25            "</attribute>" +
     26            "<text/>" +
     27        "</element>" +
     28    "</optional>";
    1929
    20 TrainingQueue.prototype.Init = function()
     30ProductionQueue.prototype.Init = function()
    2131{
    2232    this.nextID = 1;
    2333
     
    2636    //   {
    2737    //     "id": 1,
    2838    //     "player": 1, // who paid for this batch; we need this to cope with refunds cleanly
    29     //     "template": "units/example",
     39    //     "unitTemplate": "units/example",
    3040    //     "count": 10,
    3141    //     "resources": { "wood": 100, ... },   // resources per unit, multiply by count to get total
    3242    //     "population": 1, // population per unit, multiply by count to get total
    33     //     "trainingStarted": false, // true iff we have reserved population
     43    //     "productionStarted": false, // true iff we have reserved population
    3444    //     "timeTotal": 15000, // msecs
    3545    //     "timeRemaining": 10000, // msecs
    3646    //   }
     47    //   
     48    //   {
     49    //     "id": 1,
     50    //     "player": 1, // who paid for this research; we need this to cope with refunds cleanly
     51    //     "technologyTemplate": "example_tech",
     52    //     "resources": { "wood": 100, ... },   // resources needed for research
     53    //     "productionStarted": false, // true iff production has started
     54    //     "timeTotal": 15000, // msecs
     55    //     "timeRemaining": 10000, // msecs
     56    //   }
    3757   
    3858    this.timer = undefined; // g_ProgressInterval msec timer, active while the queue is non-empty
    3959   
     
    4464/*
    4565 * Returns list of entities that can be trained by this building.
    4666 */
    47 TrainingQueue.prototype.GetEntitiesList = function()
     67ProductionQueue.prototype.GetEntitiesList = function()
    4868{
     69    if (!this.template.Entities)
     70        return [];
     71   
    4972    var string = this.template.Entities._string;
    5073   
    5174    // Replace the "{civ}" codes with this entity's civ ID
     
    5780};
    5881
    5982/*
    60  * Adds a new batch of identical units to the training queue.
     83 * Returns list of technologies that can be researched by this building.
    6184 */
    62 TrainingQueue.prototype.AddBatch = function(templateName, count, metadata)
     85ProductionQueue.prototype.GetTechnologiesList = function()
    6386{
     87    if (!this.template.Technologies)
     88        return [];
     89   
     90    var string = this.template.Technologies._string;
     91   
     92    var cmpTechMan = QueryOwnerInterface(this.entity, IID_TechnologyManager);
     93    if (!cmpTechMan)
     94        return [];
     95   
     96    var techs = string.split(/\s+/);
     97    var ret = [];
     98    var superceded = {}; // Stores the tech which supercedes the key
     99   
     100    // Add any top level technologies to an array which corresponds to the displayed icons
     101    // Also store the "children" for the superceding,
     102    for (var i in techs)
     103    {
     104        var tech = techs[i];
     105        var template = cmpTechMan.GetTechnologyTemplate(tech);
     106        if (!template.supercedes || techs.indexOf(template.supercedes) === -1)
     107            ret.push(tech);
     108        else
     109            superceded[template.supercedes] = tech;
     110    }
     111   
     112    // Now make researched/in progress techs invisible
     113    for (var i in ret)
     114    {
     115        var tech = ret[i];
     116        while (cmpTechMan.IsTechnologyResearched(tech) || cmpTechMan.IsInProgress(tech))
     117        {
     118            tech = superceded[tech];
     119        }
     120
     121       
     122        ret[i] = tech;
     123    }
     124   
     125    return ret;
     126};
     127
     128/*
     129 * Adds a new batch of identical units to train or a technology to research to the production queue.
     130 */
     131ProductionQueue.prototype.AddBatch = function(templateName, type, count, metadata)
     132{
    64133    // TODO: there should probably be a limit on the number of queued batches
    65134    // TODO: there should be a way for the GUI to determine whether it's going
    66135    // to be possible to add a batch (based on resource costs and length limits)
     
    68137
    69138    if (this.queue.length < MAX_QUEUE_SIZE)
    70139    {
    71         // Find the template data so we can determine the build costs
    72         var cmpTempMan = Engine.QueryInterface(SYSTEM_ENTITY, IID_TemplateManager);
    73         var template = cmpTempMan.GetTemplate(templateName);
    74         if (!template)
    75             return;
     140       
     141        if (type == "unit")
     142        {
     143            // Find the template data so we can determine the build costs
     144            var cmpTempMan = Engine.QueryInterface(SYSTEM_ENTITY, IID_TemplateManager);
     145            var template = cmpTempMan.GetTemplate(templateName);
     146            if (!template)
     147                return;
     148           
     149            // Apply a time discount to larger batches.
     150            // TODO: work out what equation we should use here.
     151            var timeMult = Math.pow(count, 0.7);
    76152
    77         // Apply a time discount to larger batches.
    78         // TODO: work out what equation we should use here.
    79         var timeMult = Math.pow(count, 0.7);
     153            var time = timeMult * template.Cost.BuildTime;
    80154
    81         var time = timeMult * template.Cost.BuildTime;
     155            var totalCosts = {};
     156            for each (var r in ["food", "wood", "stone", "metal"])
     157                totalCosts[r] = Math.floor(count * template.Cost.Resources[r]);
    82158
    83         var totalCosts = {};
    84         for each (var r in ["food", "wood", "stone", "metal"])
    85             totalCosts[r] = Math.floor(count * template.Cost.Resources[r]);
     159            var population = template.Cost.Population;
     160       
     161            // TrySubtractResources should report error to player (they ran out of resources)
     162            if (!cmpPlayer.TrySubtractResources(totalCosts))
     163                return;
    86164
    87         var population = template.Cost.Population;
    88    
    89         // TrySubtractResources should report error to player (they ran out of resources)
    90         if (!cmpPlayer.TrySubtractResources(totalCosts))
     165            this.queue.push({
     166                "id": this.nextID++,
     167                "player": cmpPlayer.GetPlayerID(),
     168                "unitTemplate": templateName,
     169                "count": count,
     170                "metadata": metadata,
     171                "resources": deepcopy(template.Cost.Resources), // need to copy to avoid serialization problems
     172                "population": population,
     173                "productionStarted": false,
     174                "timeTotal": time*1000,
     175                "timeRemaining": time*1000,
     176            });
     177        }
     178        else if (type == "technology")
     179        {
     180            // Load the technology template
     181            var cmpTechTempMan = Engine.QueryInterface(SYSTEM_ENTITY, IID_TechnologyTemplateManager);
     182            var template = cmpTechTempMan.GetTemplate(templateName);
     183            if (!template)
     184                return;
     185           
     186            var time = template.researchTime;
     187
     188            var cost = {};
     189            for each (var r in ["food", "wood", "stone", "metal"])
     190                cost[r] = Math.floor(template.cost[r]);
     191           
     192            // TrySubtractResources should report error to player (they ran out of resources)
     193            if (!cmpPlayer.TrySubtractResources(cost))
     194                return;
     195           
     196            // Tell the technology manager that we have started researching this so that people can't research the same
     197            // thing twice.
     198            var cmpTechMan = QueryOwnerInterface(this.entity, IID_TechnologyManager);
     199            cmpTechMan.StartedResearch(templateName);
     200
     201            this.queue.push({
     202                "id": this.nextID++,
     203                "player": cmpPlayer.GetPlayerID(),
     204                "count": 1,
     205                "technologyTemplate": templateName,
     206                "resources": deepcopy(template.cost), // need to copy to avoid serialization problems
     207                "productionStarted": false,
     208                "timeTotal": time*1000,
     209                "timeRemaining": time*1000,
     210            });
     211        }
     212        else
     213        {
     214            warn("Tried to add invalid item of type \"" + type + "\" and template \"" + templateName + "\" to a production queue");
    91215            return;
     216        }
     217       
     218        Engine.PostMessage(this.entity, MT_ProductionQueueChanged, { });
    92219
    93         this.queue.push({
    94             "id": this.nextID++,
    95             "player": cmpPlayer.GetPlayerID(),
    96             "template": templateName,
    97             "count": count,
    98             "metadata": metadata,
    99             "resources": deepcopy(template.Cost.Resources), // need to copy to avoid serialization problems
    100             "population": population,
    101             "trainingStarted": false,
    102             "timeTotal": time*1000,
    103             "timeRemaining": time*1000,
    104         });
    105         Engine.PostMessage(this.entity, MT_TrainingQueueChanged, { });
    106 
    107220        // If this is the first item in the queue, start the timer
    108221        if (!this.timer)
    109222        {
    110223            var cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
    111             this.timer = cmpTimer.SetTimeout(this.entity, IID_TrainingQueue, "ProgressTimeout", g_ProgressInterval, {});
     224            this.timer = cmpTimer.SetTimeout(this.entity, IID_ProductionQueue, "ProgressTimeout", g_ProgressInterval, {});
    112225        }
    113226    }
    114227    else
    115228    {
    116         var notification = {"player": cmpPlayer.GetPlayerID(), "message": "The training queue is full."};
     229        var notification = {"player": cmpPlayer.GetPlayerID(), "message": "The production queue is full."};
    117230        var cmpGUIInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface);
    118231        cmpGUIInterface.PushNotification(notification);
    119232    }
    120233};
    121234
    122235/*
    123  * Removes an existing batch of units from the training queue.
     236 * Removes an existing batch of units from the production queue.
    124237 * Refunds resource costs and population reservations.
    125238 */
    126 TrainingQueue.prototype.RemoveBatch = function(id)
     239ProductionQueue.prototype.RemoveBatch = function(id)
    127240{
    128241    // Destroy any cached entities (those which didn't spawn for some reason)
    129242    for (var i = 0; i < this.entityCache.length; ++i)
     
    139252            continue;
    140253
    141254        // Now we've found the item to remove
    142 
     255       
    143256        var cmpPlayer = QueryPlayerIDInterface(item.player, IID_Player);
    144257
    145258        // Refund the resource cost for this batch
    146259        var totalCosts = {};
    147260        for each (var r in ["food", "wood", "stone", "metal"])
    148261            totalCosts[r] = Math.floor(item.count * item.resources[r]);
    149            
     262       
    150263        cmpPlayer.AddResources(totalCosts);
    151 
     264       
    152265        // Remove reserved population slots if necessary
    153         if (item.trainingStarted)
     266        if (item.productionStarted && item.unitTemplate)
    154267            cmpPlayer.UnReservePopulationSlots(item.population * item.count);
    155 
     268       
     269        // Mark the research as stopped if we cancel it
     270        if (item.technologyTemplate)
     271        {
     272            var cmpTechMan = QueryOwnerInterface(this.entity, IID_TechnologyManager);
     273            cmpTechMan.StoppedResearch(item.technologyTemplate);
     274        }
     275       
    156276        // Remove from the queue
    157277        // (We don't need to remove the timer - it'll expire if it discovers the queue is empty)
    158278        this.queue.splice(i, 1);
    159         Engine.PostMessage(this.entity, MT_TrainingQueueChanged, { });
     279        Engine.PostMessage(this.entity, MT_ProductionQueueChanged, { });
    160280
    161281        return;
    162282    }
    163283};
    164284
    165285/*
    166  * Returns basic data from all batches in the training queue.
     286 * Returns basic data from all batches in the production queue.
    167287 */
    168 TrainingQueue.prototype.GetQueue = function()
     288ProductionQueue.prototype.GetQueue = function()
    169289{
    170290    var out = [];
    171291    for each (var item in this.queue)
    172292    {
    173293        out.push({
    174294            "id": item.id,
    175             "template": item.template,
     295            "unitTemplate": item.unitTemplate,
     296            "technologyTemplate": item.technologyTemplate,
    176297            "count": item.count,
    177298            "progress": 1-(item.timeRemaining/item.timeTotal),
    178299            "metadata": item.metadata,
     
    184305/*
    185306 * Removes all existing batches from the queue.
    186307 */
    187 TrainingQueue.prototype.ResetQueue = function()
     308ProductionQueue.prototype.ResetQueue = function()
    188309{
    189     // Empty the training queue and refund all the resource costs
     310    // Empty the production queue and refund all the resource costs
    190311    // to the player. (This is to avoid players having to micromanage their
    191312    // buildings' queues when they're about to be destroyed or captured.)
    192313
     
    194315        this.RemoveBatch(this.queue[0].id);
    195316};
    196317
    197 TrainingQueue.prototype.OnOwnershipChanged = function(msg)
     318ProductionQueue.prototype.OnOwnershipChanged = function(msg)
    198319{
    199320    if (msg.from != -1)
    200321    {
    201         // Unset flag that previous owner's training queue may be blocked
     322        // Unset flag that previous owner's training may be blocked
    202323        var cmpPlayer = QueryPlayerIDInterface(msg.from, IID_Player);
    203324        if (cmpPlayer && this.queue.length > 0)
    204             cmpPlayer.UnBlockTrainingQueue();
     325            cmpPlayer.UnBlockTraining();
    205326    }
    206327
    207     // Reset the training queue whenever the owner changes.
     328    // Reset the production queue whenever the owner changes.
    208329    // (This should prevent players getting surprised when they capture
    209330    // an enemy building, and then loads of the enemy's civ's soldiers get
    210331    // created from it. Also it means we don't have to worry about
     
    212333    this.ResetQueue();
    213334};
    214335
    215 TrainingQueue.prototype.OnDestroy = function()
     336ProductionQueue.prototype.OnDestroy = function()
    216337{
    217338    // Reset the queue to refund any resources
    218339    this.ResetQueue();
     
    228349 * This function creates the entities and places them in world if possible.
    229350 * returns the number of successfully spawned entities.
    230351 */
    231 TrainingQueue.prototype.SpawnUnits = function(templateName, count, metadata)
     352ProductionQueue.prototype.SpawnUnits = function(templateName, count, metadata)
    232353{
    233354    var cmpFootprint = Engine.QueryInterface(this.entity, IID_Footprint);
    234355    var cmpPosition = Engine.QueryInterface(this.entity, IID_Position);
     
    302423};
    303424
    304425/*
    305  * Increments progress on the first batch in the training queue, and blocks the
     426 * Increments progress on the first batch in the production queue, and blocks the
    306427 * queue if population limit is reached or some units failed to spawn.
    307428 */
    308 TrainingQueue.prototype.ProgressTimeout = function(data)
     429ProductionQueue.prototype.ProgressTimeout = function(data)
    309430{
    310431    // Allocate the 1000msecs to as many queue items as it takes
    311432    // until we've used up all the time (so that we work accurately
     
    316437    while (time > 0 && this.queue.length)
    317438    {
    318439        var item = this.queue[0];
    319         if (!item.trainingStarted)
     440        if (!item.productionStarted)
    320441        {
    321             // Batch's training hasn't started yet.
    322             // Try to reserve the necessary population slots
    323             if (!cmpPlayer.TryReservePopulationSlots(item.population * item.count))
     442            // If the item is a unit then do population checks
     443            if (item.unitTemplate)
    324444            {
    325                 // No slots available - don't train this batch now
    326                 // (we'll try again on the next timeout)
     445                // Batch's training hasn't started yet.
     446                // Try to reserve the necessary population slots
     447                if (item.unitTemplate && !cmpPlayer.TryReservePopulationSlots(item.population * item.count))
     448                {
     449                    // No slots available - don't train this batch now
     450                    // (we'll try again on the next timeout)
    327451
    328                 // Set flag that training queue is blocked
    329                 cmpPlayer.BlockTrainingQueue();
    330                 break;
     452                    // Set flag that training is blocked
     453                    cmpPlayer.BlockTraining();
     454                    break;
     455                }
     456               
     457                // Unset flag that training is blocked
     458                cmpPlayer.UnBlockTraining();
    331459            }
    332460
    333             // Unset flag that training queue is blocked
    334             cmpPlayer.UnBlockTrainingQueue();
    335 
    336             item.trainingStarted = true;
     461            item.productionStarted = true;
    337462        }
    338463
    339464        // If we won't finish the batch now, just update its timer
     
    343468            break;
    344469        }
    345470
    346         var numSpawned = this.SpawnUnits(item.template, item.count, item.metadata);
    347         if (numSpawned == item.count)
     471        if (item.unitTemplate)
    348472        {
    349             // All entities spawned, this batch finished
    350             cmpPlayer.UnReservePopulationSlots(item.population * numSpawned);
    351             time -= item.timeRemaining;
    352             this.queue.shift();
    353             // Unset flag that training queue is blocked
    354             cmpPlayer.UnBlockTrainingQueue();
    355             this.spawnNotified = false;
    356             Engine.PostMessage(this.entity, MT_TrainingQueueChanged, { });
    357         }
    358         else
    359         {
    360             if (numSpawned > 0)
     473            var numSpawned = this.SpawnUnits(item.unitTemplate, item.count, item.metadata);
     474            if (numSpawned == item.count)
    361475            {
    362                 // Only partially finished
     476                // All entities spawned, this batch finished
    363477                cmpPlayer.UnReservePopulationSlots(item.population * numSpawned);
    364                 item.count -= numSpawned;
    365                 Engine.PostMessage(this.entity, MT_TrainingQueueChanged, { });
     478                time -= item.timeRemaining;
     479                this.queue.shift();
     480                // Unset flag that training is blocked
     481                cmpPlayer.UnBlockTraining();
     482                this.spawnNotified = false;
     483                Engine.PostMessage(this.entity, MT_ProductionQueueChanged, { });
    366484            }
     485            else
     486            {
     487                if (numSpawned > 0)
     488                {
     489                    // Only partially finished
     490                    cmpPlayer.UnReservePopulationSlots(item.population * numSpawned);
     491                    item.count -= numSpawned;
     492                    Engine.PostMessage(this.entity, MT_ProductionQueueChanged, { });
     493                }
    367494
    368             // Some entities failed to spawn
    369             // Set flag that training queue is blocked
    370             cmpPlayer.BlockTrainingQueue();
    371            
    372             if (!this.spawnNotified)
    373             {
    374                 var cmpPlayer = QueryOwnerInterface(this.entity, IID_Player);
    375                 var notification = {"player": cmpPlayer.GetPlayerID(), "message": "Can't find free space to spawn trained units" };
    376                 var cmpGUIInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface);
    377                 cmpGUIInterface.PushNotification(notification);
    378                 this.spawnNotified = true;
     495                // Some entities failed to spawn
     496                // Set flag that training is blocked
     497                cmpPlayer.BlockTraining();
     498               
     499                if (!this.spawnNotified)
     500                {
     501                    var cmpPlayer = QueryOwnerInterface(this.entity, IID_Player);
     502                    var notification = {"player": cmpPlayer.GetPlayerID(), "message": "Can't find free space to spawn trained units" };
     503                    var cmpGUIInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface);
     504                    cmpGUIInterface.PushNotification(notification);
     505                    this.spawnNotified = true;
     506                }
     507                break;
    379508            }
    380             break;
    381509        }
     510        else if (item.technologyTemplate)
     511        {
     512            var cmpTechnologyManager = QueryOwnerInterface(this.entity, IID_TechnologyManager);
     513            cmpTechnologyManager.ResearchTechnology(item.technologyTemplate);
     514           
     515            this.queue.shift();
     516            Engine.PostMessage(this.entity, MT_ProductionQueueChanged, { });
     517        }
    382518    }
    383519
    384520    // If the queue's empty, delete the timer, else repeat it
     
    386522    {
    387523        this.timer = undefined;
    388524
    389         // Unset flag that training queue is blocked
     525        // Unset flag that training is blocked
    390526        // (This might happen when the player unqueues all batches)
    391         cmpPlayer.UnBlockTrainingQueue();
     527        cmpPlayer.UnBlockTraining();
    392528    }
    393529    else
    394530    {
    395531        var cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
    396         this.timer = cmpTimer.SetTimeout(this.entity, IID_TrainingQueue, "ProgressTimeout", g_ProgressInterval, data);
     532        this.timer = cmpTimer.SetTimeout(this.entity, IID_ProductionQueue, "ProgressTimeout", g_ProgressInterval, data);
    397533    }
    398534}
    399535
    400 Engine.RegisterComponentType(IID_TrainingQueue, "TrainingQueue", TrainingQueue);
     536Engine.RegisterComponentType(IID_ProductionQueue, "ProductionQueue", ProductionQueue);
  • binaries/data/mods/public/simulation/components/TechnologyTemplateManager.js

     
     1/**
     2 * System component which loads the technology data files
     3 */
     4function TechnologyTemplateManager() {}
     5
     6TechnologyTemplateManager.prototype.Schema =
     7    "<a:component type='system'/><empty/>";
     8   
     9TechnologyTemplateManager.prototype.Init = function()
     10{
     11    this.allTechs = {};
     12    var techNames = this.ListAllTechs();
     13    for (i in techNames)
     14        this.GetTemplate(techNames[i]);
     15};
     16
     17TechnologyTemplateManager.prototype.GetTemplate = function(template)
     18{
     19    if (!this.allTechs[template])
     20    {
     21        this.allTechs[template] = Engine.ReadJSONFile("technologies/" + template + ".json");
     22        if (! this.allTechs[template])
     23            error("Failed to load technology \"" + template + "\"");
     24    }
     25   
     26    return this.allTechs[template];
     27};
     28
     29TechnologyTemplateManager.prototype.ListAllTechs = function()
     30{
     31    return Engine.FindAllTechnologyTemplates();
     32}
     33
     34TechnologyTemplateManager.prototype.GetAllTechs = function()
     35{
     36    return this.allTechs;
     37}
     38
     39Engine.RegisterComponentType(IID_TechnologyTemplateManager, "TechnologyTemplateManager", TechnologyTemplateManager);
     40 No newline at end of file
  • binaries/data/mods/public/simulation/ai/common-api/base.js

     
    4343// CCmpTemplateManager::CopyFoundationSubset and only includes components
    4444// that our EntityTemplate class currently uses.)
    4545var g_FoundationForbiddenComponents = {
    46     "TrainingQueue": 1,
     46    "ProductionQueue": 1,
    4747    "ResourceSupply": 1,
    4848    "ResourceDropsite": 1,
    4949    "GarrisonHolder": 1,
  • binaries/data/mods/public/simulation/ai/common-api/entity.js

     
    126126    },
    127127
    128128    trainableEntities: function() {
    129         if (!this._template.TrainingQueue)
     129        if (!this._template.ProductionQueue)
    130130            return undefined;
    131131        var civ = this.civ();
    132         var templates = this._template.TrainingQueue.Entities._string.replace(/\{civ\}/g, civ).split(/\s+/);
     132        var templates = this._template.ProductionQueue.Entities._string.replace(/\{civ\}/g, civ).split(/\s+/);
    133133        return templates;
    134134    },
    135135
  • binaries/data/mods/public/simulation/ai/common-api-v2/base.js

     
    4444// CCmpTemplateManager::CopyFoundationSubset and only includes components
    4545// that our EntityTemplate class currently uses.)
    4646var g_FoundationForbiddenComponents = {
    47     "TrainingQueue": 1,
     47    "ProductionQueue": 1,
    4848    "ResourceSupply": 1,
    4949    "ResourceDropsite": 1,
    5050    "GarrisonHolder": 1,
  • binaries/data/mods/public/simulation/ai/common-api-v2/entity.js

     
    127127    },
    128128
    129129    trainableEntities: function() {
    130         if (!this._template.TrainingQueue)
     130        if (!this._template.ProductionQueue)
    131131            return undefined;
    132132        var civ = this.civ();
    133         var templates = this._template.TrainingQueue.Entities._string.replace(/\{civ\}/g, civ).split(/\s+/);
     133        var templates = this._template.ProductionQueue.Entities._string.replace(/\{civ\}/g, civ).split(/\s+/);
    134134        return templates;
    135135    },
    136136
  • binaries/data/mods/public/simulation/data/technologies/town_phase.json

     
     1{
     2    "genericName": "Town Phase",
     3    "description": "Advances from a small village to a bustling town, ready to expand rapidly.",
     4    "cost": { "food": 100, "wood": 100, "stone": 0, "metal": 50 },
     5    "requirements": { "class": "Village", "numberOfTypes": 2 },
     6    "requirementsTooltip": "Requires two village structures",
     7    "supercedes": "village_phase",
     8    "icon": "technologies/town_phase.png",
     9    "researchTime": 10,
     10    "tooltip": "Advance to Town Phase"
     11}
  • binaries/data/mods/public/simulation/data/technologies/city_phase.json

     
     1{
     2    "genericName": "City Phase",
     3    "specificName": "Generic Specific City Name",
     4    "specificName_hele": "Greek City",
     5    "description": "Advances from a bustling town to a veritable metropolis, full of the wonders of modern technology.",
     6    "cost": {"food": 0, "wood": 0, "stone": 50, "metal": 0},
     7    "supercedes": "town_phase",
     8    "icon": "technologies/city_phase.png",
     9    "researchTime": 10,
     10    "tooltip": "Advance to City Phase"
     11}
  • binaries/data/mods/public/simulation/data/technologies/plough.json

     
     1{
     2    "genericName": "Plough",
     3    "description": "A horse drawn instrument to turn the sod",
     4    "cost": {"food": 0, "wood": 0, "stone": 0, "metal": 0},
     5    "requirements": {"tech": "town_phase"},
     6    "requirementsTooltip": "Requires Town Phase",
     7    "icon": "technologies/plough.png",
     8    "researchTime": 10,
     9    "tooltip": "Discover the Plough",
     10    "modifications": [{"value": "ResourceGatherer/Rates/food.grain", "multiplier": 15}],
     11    "affects": ["Female"]
     12}
  • binaries/data/mods/public/simulation/data/technologies/village_phase.json

     
     1{
     2    "genericName": "Village Phase",
     3    "description": "Advances from a small village to a bustling town, ready to expand rapidly.",
     4    "autoResearch": true,
     5    "icon": "technologies/town_phase.png",
     6    "researchTime": 10,
     7    "tooltip": "Advance to Town Phase"
     8}
  • binaries/data/mods/public/simulation/templates/special/player.xml

     
    1010  </BuildLimits>
    1111  <Player/>
    1212  <StatisticsTracker/>
     13  <TechnologyManager/>
    1314</Entity>
  • binaries/data/mods/public/simulation/templates/structures/celt_dock.xml

     
    1515  <Obstruction>
    1616    <Static width="10.0" depth="22.0"/>
    1717  </Obstruction>
    18   <TrainingQueue>
     18  <ProductionQueue>
    1919    <Entities datatype="tokens">
    2020      units/celt_ship_trireme
    2121    </Entities>
    22   </TrainingQueue>
     22  </ProductionQueue>
    2323  <VisualActor>
    2424    <Actor>structures/celts/dock_new.xml</Actor>
    2525    <FoundationActor>structures/fndn_celt_dock.xml</FoundationActor>
  • binaries/data/mods/public/simulation/templates/structures/rome_army_camp.xml

     
    6868    <HealthDecayRate>5</HealthDecayRate>
    6969  </TerritoryDecay>
    7070  <TerritoryInfluence disable=""/>
    71   <TrainingQueue>
     71  <ProductionQueue>
    7272    <Entities datatype="tokens">
    7373      units/rome_infantry_swordsman_b
    7474      units/rome_infantry_spearman_a
     
    7878      units/rome_mechanical_siege_scorpio
    7979      units/rome_mechanical_siege_ram
    8080    </Entities>
    81   </TrainingQueue>
     81  </ProductionQueue>
    8282  <Vision>
    8383    <Range>60</Range>
    8484  </Vision>
     
    8686    <FoundationActor>structures/fndn_8x8.xml</FoundationActor>
    8787    <Actor>structures/romans/camp.xml</Actor>
    8888  </VisualActor>
    89 </Entity>
    90  No newline at end of file
     89</Entity>
  • binaries/data/mods/public/simulation/templates/structures/hele_civil_centre.xml

     
    1111    <SpecificName>Agorā́</SpecificName>
    1212    <History>The most important place in most Classical Greek poleis, the Agora served many purposes; it was a place for public speeches and was the stage for civic life and commercial interests.</History>
    1313  </Identity>
    14   <TrainingQueue>
     14  <ProductionQueue>
    1515    <Entities datatype="tokens">
    1616      units/hele_infantry_spearman_b
    1717      units/hele_infantry_javelinist_b
    1818      units/hele_cavalry_javelinist_b
    1919    </Entities>
    20   </TrainingQueue>
     20  </ProductionQueue>
    2121  <VisualActor>
    2222    <Actor>structures/hellenes/civic_centre_new.xml</Actor>
    2323  </VisualActor>
  • binaries/data/mods/public/simulation/templates/structures/mace_barracks.xml

     
    1515    <SpecificName>Stratēgeîon</SpecificName>
    1616    <History>The Stratigeion was the main military headquarters, where important decisions were taken and plans for battles discussed by the Hellene Generals, or "Strategoi".</History>
    1717  </Identity>
    18   <TrainingQueue>
     18  <ProductionQueue>
    1919    <Entities datatype="tokens">
    2020      units/mace_infantry_spearman_b
    2121      units/mace_infantry_javelinist_b
     
    2424      units/mace_cavalry_spearman_b
    2525      units/mace_cavalry_javelinist_b
    2626    </Entities>
    27   </TrainingQueue>
     27  </ProductionQueue>
    2828  <VisualActor>
    2929    <Actor>structures/hellenes/barracks.xml</Actor>
    3030  </VisualActor>
  • binaries/data/mods/public/simulation/templates/structures/pers_apadana.xml

     
    3232    <Root>true</Root>
    3333    <Radius>38</Radius>
    3434  </TerritoryInfluence>
    35   <TrainingQueue>
     35  <ProductionQueue>
    3636    <Entities datatype="tokens">
    3737      units/pers_hero_cyrus
    3838      units/pers_hero_darius
    3939      units/pers_hero_xerxes
    4040      units/pers_champion_infantry
    4141    </Entities>
    42   </TrainingQueue>
     42  </ProductionQueue>
    4343  <VisualActor>
    4444    <Actor>structures/persians/sb1_new.xml</Actor>
    4545    <FoundationActor>structures/fndn_6x6.xml</FoundationActor>
  • binaries/data/mods/public/simulation/templates/structures/iber_corral.xml

     
    1212  <Obstruction>
    1313    <Static width="14.0" depth="14.0"/>
    1414  </Obstruction>
    15   <TrainingQueue>
     15  <ProductionQueue>
    1616    <Entities datatype="tokens">
    1717      gaia/fauna_goat
    1818    </Entities>
    19   </TrainingQueue>
     19  </ProductionQueue>
    2020  <VisualActor>
    2121    <Actor>structures/iberians/corral.xml</Actor>
    2222    <FoundationActor>structures/fndn_4x4.xml</FoundationActor>
  • binaries/data/mods/public/simulation/templates/structures/pers_stables.xml

     
    2525  <Obstruction>
    2626    <Static width="18.0" depth="16.0"/>
    2727  </Obstruction>
    28   <TrainingQueue>
     28  <ProductionQueue>
    2929    <Entities datatype="tokens">
    3030      units/pers_cavalry_spearman_b
    3131      units/pers_cavalry_swordsman_b
    3232      units/pers_cavalry_javelinist_b
    3333      units/pers_cavalry_archer_b
    3434    </Entities>
    35   </TrainingQueue>
     35  </ProductionQueue>
    3636  <VisualActor>
    3737    <Actor>structures/persians/stables.xml</Actor>
    3838    <FoundationActor>structures/fndn_4x4.xml</FoundationActor>
  • binaries/data/mods/public/simulation/templates/structures/rome_civil_centre.xml

     
    1212  <Obstruction>
    1313    <Static width="37.0" depth="37.0"/>
    1414  </Obstruction>
    15   <TrainingQueue>
     15  <ProductionQueue>
    1616    <Entities datatype="tokens">
    1717      units/rome_infantry_swordsman_b
    1818      units/rome_infantry_javelinist_b
    1919      units/rome_cavalry_spearman_b
    2020    </Entities>
    21   </TrainingQueue>
     21  </ProductionQueue>
    2222  <VisualActor>
    2323    <FoundationActor>structures/fndn_8x8.xml</FoundationActor>
    2424    <Actor>structures/romans/civic_centre.xml</Actor>
  • binaries/data/mods/public/simulation/templates/structures/spart_corral.xml

     
    1818  <Obstruction>
    1919    <Static width="14.0" depth="14.0"/>
    2020  </Obstruction>
    21   <TrainingQueue>
     21  <ProductionQueue>
    2222    <Entities datatype="tokens">
    2323      gaia/fauna_goat
    2424    </Entities>
    25   </TrainingQueue>
     25  </ProductionQueue>
    2626  <VisualActor>
    2727    <Actor>structures/hellenes/corral.xml</Actor>
    2828    <FoundationActor>structures/fndn_3x3.xml</FoundationActor>
  • binaries/data/mods/public/simulation/templates/structures/athen_dock.xml

     
    1111    <SpecificName>Limḗn</SpecificName>
    1212    <History>Greece is a sea country, which is why some of the greatest Hellenic and Hellenistic cities like Ephesus, Corinth, Alexandria and Antioch were built by the sea. It should also be noted that all colonies during the Great Colonisation were thriving port centres, which traded with the local population.</History>
    1313  </Identity>
    14   <TrainingQueue>
     14  <ProductionQueue>
    1515    <Entities datatype="tokens">
    1616      units/athen_ship_bireme
    1717      units/athen_ship_trireme
    1818    </Entities>
    19   </TrainingQueue>
     19  </ProductionQueue>
    2020  <VisualActor>
    2121    <Actor>structures/athenians/dock.xml</Actor>
    2222  </VisualActor>
  • binaries/data/mods/public/simulation/templates/structures/rome_corral.xml

     
    1212  <Obstruction>
    1313    <Static width="14" depth="20"/>
    1414  </Obstruction>
    15   <TrainingQueue>
     15  <ProductionQueue>
    1616    <Entities datatype="tokens">
    1717      gaia/fauna_goat
    1818      gaia/fauna_sheep
    1919    </Entities>
    20   </TrainingQueue>
     20  </ProductionQueue>
    2121  <VisualActor>
    2222    <FoundationActor>structures/fndn_2x4.xml</FoundationActor>
    2323    <Actor>structures/romans/corral.xml</Actor>
  • binaries/data/mods/public/simulation/templates/structures/spart_syssiton.xml

     
    3333      <death>attack/destruction/building_collapse_large.xml</death>
    3434    </SoundGroups>
    3535  </Sound>
    36   <TrainingQueue>
     36  <ProductionQueue>
    3737    <Entities datatype="tokens">
    3838      units/hele_hero_leonidas
    3939      units/spart_champion_infantry_spear
    4040    </Entities>
    41   </TrainingQueue>
     41  </ProductionQueue>
    4242  <VisualActor>
    4343    <Actor>structures/hellenes/gymnasion.xml</Actor>
    4444    <FoundationActor>structures/fndn_6x6.xml</FoundationActor>
  • binaries/data/mods/public/simulation/templates/structures/cart_super_dock.xml

     
    4646  </Sound>
    4747  <TerritoryDecay disable=""/>
    4848  <TerritoryInfluence disable=""/>
    49   <TrainingQueue>
     49  <ProductionQueue>
    5050    <Entities datatype="tokens">
    5151      units/cart_ship_bireme
    5252      units/cart_ship_trireme
    5353      units/cart_ship_quinquereme
    5454    </Entities>
    55   </TrainingQueue>
     55  </ProductionQueue>
    5656  <Vision>
    5757    <Range>100</Range>
    5858  </Vision>
  • binaries/data/mods/public/simulation/templates/structures/iber_fortress.xml

     
    1919  <Obstruction>
    2020    <Static width="27.0" depth="27.0"/>
    2121  </Obstruction>
    22   <TrainingQueue>
     22  <ProductionQueue>
    2323    <Entities datatype="tokens">
    2424      units/iber_hero_caros
    2525      units/iber_hero_indibil
     
    2828      units/iber_champion_cavalry
    2929      units/iber_mechanical_siege_ram
    3030    </Entities>
    31   </TrainingQueue>
     31  </ProductionQueue>
    3232  <VisualActor>
    3333    <Actor>structures/iberians/fortress.xml</Actor>
    3434  </VisualActor>
  • binaries/data/mods/public/simulation/templates/structures/pers_corral.xml

     
    1818  <Obstruction>
    1919    <Static width="17.0" depth="11.0"/>
    2020  </Obstruction>
    21   <TrainingQueue>
     21  <ProductionQueue>
    2222    <Entities datatype="tokens">
    2323      gaia/fauna_goat
    2424    </Entities>
    25   </TrainingQueue>
     25  </ProductionQueue>
    2626  <VisualActor>
    2727    <Actor>structures/persians/corral.xml</Actor>
    2828    <FoundationActor>structures/fndn_4x2.xml</FoundationActor>
  • binaries/data/mods/public/simulation/templates/structures/celt_fortress_b.xml

     
    2929      <death>attack/destruction/building_collapse_large.xml</death>
    3030    </SoundGroups>
    3131  </Sound>
    32   <TrainingQueue>
     32  <ProductionQueue>
    3333    <Entities datatype="tokens">
    3434      units/celt_hero_boudicca
    3535      units/celt_hero_caratacos
     
    3838      units/celt_champion_infantry_brit
    3939      units/celt_mechanical_siege_ram
    4040    </Entities>
    41   </TrainingQueue>
     41  </ProductionQueue>
    4242  <Vision>
    4343    <Range>100</Range>
    4444  </Vision>
  • binaries/data/mods/public/simulation/templates/structures/spart_fortress.xml

     
    1919  <Obstruction>
    2020    <Static width="24.0" depth="26.0"/>
    2121  </Obstruction>
    22   <TrainingQueue>
     22  <ProductionQueue>
    2323    <Entities datatype="tokens">
    2424      units/spart_mechanical_siege_ram
    2525    </Entities>
    26   </TrainingQueue>
     26  </ProductionQueue>
    2727  <VisualActor>
    2828    <Actor>structures/hellenes/fortress_new.xml</Actor>
    2929  </VisualActor>
  • binaries/data/mods/public/simulation/templates/structures/athen_gymnasion.xml

     
    3333      <death>attack/destruction/building_collapse_large.xml</death>
    3434    </SoundGroups>
    3535  </Sound>
    36   <TrainingQueue>
     36  <ProductionQueue>
    3737    <Entities datatype="tokens">
    3838      units/athen_champion_infantry
    3939      units/athen_champion_ranged
    4040    </Entities>
    41   </TrainingQueue>
     41  </ProductionQueue>
    4242  <VisualActor>
    4343    <Actor>structures/athenians/gymnasion.xml</Actor>
    4444    <FoundationActor>structures/fndn_6x6.xml</FoundationActor>
  • binaries/data/mods/public/simulation/templates/structures/cart_corral.xml

     
    1212  <Obstruction>
    1313    <Static width="16.0" depth="14.5"/>
    1414  </Obstruction>
    15   <TrainingQueue>
     15  <ProductionQueue>
    1616    <Entities datatype="tokens">
    1717      gaia/fauna_goat
    1818    </Entities>
    19   </TrainingQueue>
     19  </ProductionQueue>
    2020  <VisualActor>
    2121    <Actor>structures/carthaginians/corral.xml</Actor>
    2222    <FoundationActor>structures/fndn_3x3.xml</FoundationActor>
  • binaries/data/mods/public/simulation/templates/structures/pers_fortress.xml

     
    1212    <History>The Susa Chateau was a fortress in the administrative capital of Susa, which was reconstructed by a French archaeologist in 1890 with the use of original building material.</History>
    1313    <Tooltip>Train Champion Units and Construct Siege Rams.</Tooltip>
    1414  </Identity>
    15   <TrainingQueue>
     15  <ProductionQueue>
    1616    <Entities datatype="tokens">
    1717      units/pers_champion_cavalry
    1818      units/pers_mechanical_siege_ram
    1919    </Entities>
    20   </TrainingQueue>
     20  </ProductionQueue>
    2121  <VisualActor>
    2222    <Actor>structures/persians/fortress.xml</Actor>
    2323  </VisualActor>
  • binaries/data/mods/public/simulation/templates/structures/mace_dock.xml

     
    1111    <SpecificName>Limḗn</SpecificName>
    1212    <History>Greece is a sea country, which is why some of the greatest Hellenic and Hellenistic cities like Ephesus, Corinth, Alexandria and Antioch were built by the sea. It should also be noted that all colonies during the Great Colonisation were thriving port centres, which traded with the local population.</History>
    1313  </Identity>
    14   <TrainingQueue>
     14  <ProductionQueue>
    1515    <Entities datatype="tokens">
    1616      units/hele_ship_bireme
    1717      units/hele_ship_trireme
    1818    </Entities>
    19   </TrainingQueue>
     19  </ProductionQueue>
    2020  <VisualActor>
    2121    <Actor>structures/hellenes/dock.xml</Actor>
    2222  </VisualActor>
  • binaries/data/mods/public/simulation/templates/structures/iber_civil_centre.xml

     
    55    <SpecificName>Oppidum</SpecificName>
    66    <History>The Oppidum, plural Oppida (oh-PEE-dah), has a long history in the Iberian Peninsula. They were walled towns, dating back to even before the time period of the game and expanding greatly during it. They were usually built upon heights for better defensive purposes but sometimes right out on the plains, especially in the east where there may not have been heights at desirable locations near meandering rivers. This concept drawing is derived from an actual archeological site that has been excavated in the northeast of Spain having belonged to the Ilergete (ee-layer-HAY-tay) tribe as shown in the figure below and from the virtual reconstruction of the site at the museum located adjacent to it.</History>
    77  </Identity>
    8   <TrainingQueue>
     8  <ProductionQueue>
    99    <Entities datatype="tokens">
    1010      units/iber_infantry_swordsman_b
    1111      units/iber_infantry_javelinist_b
    1212      units/iber_cavalry_javelinist_b
    1313    </Entities>
    14   </TrainingQueue>
     14  </ProductionQueue>
    1515  <VisualActor>
    1616    <Actor>structures/iberians/civil_centre.xml</Actor>
    1717  </VisualActor>
  • binaries/data/mods/public/simulation/templates/structures/spart_civil_centre.xml

     
    1111    <SpecificName>Agorā́</SpecificName>
    1212    <History>The most important place in most Classical Greek poleis, the Agora served many purposes; it was a place for public speeches and was the stage for civic life and commercial interests.</History>
    1313  </Identity>
    14   <TrainingQueue>
     14  <ProductionQueue>
    1515    <Entities datatype="tokens">
    1616      units/spart_infantry_spearman_b
    1717      units/spart_infantry_javelinist_b
    1818      units/spart_cavalry_javelinist_b
    1919    </Entities>
    20   </TrainingQueue>
     20  </ProductionQueue>
    2121  <VisualActor>
    2222    <Actor>structures/hellenes/civic_centre_new.xml</Actor>
    2323  </VisualActor>
  • binaries/data/mods/public/simulation/templates/structures/cart_fortress.xml

     
    1313  <Obstruction>
    1414    <Static width="26.0" depth="28.0"/>
    1515  </Obstruction>
    16   <TrainingQueue>
     16  <ProductionQueue>
    1717    <Entities datatype="tokens">
    1818      units/cart_hero_hamilcar
    1919      units/cart_hero_hannibal
     
    2222      units/cart_mechanical_siege_ballista
    2323      units/cart_mechanical_siege_oxybeles
    2424    </Entities>
    25   </TrainingQueue>
     25  </ProductionQueue>
    2626  <VisualActor>
    2727    <Actor>structures/carthaginians/fortress.xml</Actor>
    2828  </VisualActor>
  • binaries/data/mods/public/simulation/templates/structures/hele_barracks.xml

     
    1515    <SpecificName>Stratēgeîon</SpecificName>
    1616    <History>The Stratigeion was the main military headquarters, where important decisions were taken and plans for battles discussed by the Hellene Generals, or "Strategoi".</History>
    1717  </Identity>
    18   <TrainingQueue>
     18  <ProductionQueue>
    1919    <Entities datatype="tokens">
    2020      units/hele_infantry_spearman_b
    2121      units/hele_infantry_javelinist_b
     
    2424      units/hele_cavalry_swordsman_b
    2525      units/hele_cavalry_javelinist_b
    2626    </Entities>
    27   </TrainingQueue>
     27  </ProductionQueue>
    2828  <VisualActor>
    2929    <Actor>structures/hellenes/barracks.xml</Actor>
    3030  </VisualActor>
  • binaries/data/mods/public/simulation/templates/structures/pers_civil_centre.xml

     
    1212    <SpecificName>Xsacapava</SpecificName>
    1313    <History>Possibly of Median origin, the word 'satrapy' means province. Soon after coming to the throne, Darius the Great carried out a vast administrative reform, dividing the huge empire into 20 satrapies governed by satraps.</History>
    1414  </Identity>
    15   <TrainingQueue>
     15  <ProductionQueue>
    1616    <Entities datatype="tokens">
    1717      units/pers_infantry_spearman_b
    1818      units/pers_infantry_archer_b
    1919      units/pers_cavalry_javelinist_b
    2020    </Entities>
    21   </TrainingQueue>
     21  </ProductionQueue>
    2222  <VisualActor>
    2323    <Actor>structures/persians/civil_centre.xml</Actor>
    2424  </VisualActor>
  • binaries/data/mods/public/simulation/templates/structures/hele_gymnasion.xml

     
    3333      <death>attack/destruction/building_collapse_large.xml</death>
    3434    </SoundGroups>
    3535  </Sound>
    36   <TrainingQueue>
     36  <ProductionQueue>
    3737    <Entities datatype="tokens">
    3838      units/hele_champion_cavalry_mace
    3939      units/hele_champion_infantry_mace
    4040      units/hele_champion_infantry_polis
    4141      units/hele_champion_swordsman_polis
    4242    </Entities>
    43   </TrainingQueue>
     43  </ProductionQueue>
    4444  <VisualActor>
    4545    <Actor>structures/hellenes/gymnasion.xml</Actor>
    4646    <FoundationActor>structures/fndn_6x6.xml</FoundationActor>
  • binaries/data/mods/public/simulation/templates/structures/cart_embassy_iberian.xml

     
    1717  <Obstruction>
    1818    <Static width="16.0" depth="16.0"/>
    1919  </Obstruction>
    20   <TrainingQueue>
     20  <ProductionQueue>
    2121    <Entities datatype="tokens">
    2222      units/cart_infantry_javelinist_b
    2323      units/cart_infantry_slinger_b
    2424      units/cart_cavalry_swordsman_b
    2525    </Entities>
    26   </TrainingQueue>
     26  </ProductionQueue>
    2727  <VisualActor>
    2828    <Actor>structures/carthaginians/embassy_iberian.xml</Actor>
    2929  </VisualActor>
  • binaries/data/mods/public/simulation/templates/structures/cart_embassy_italiote.xml

     
    2020  <Obstruction>
    2121    <Static width="11.0" depth="14.0"/>
    2222  </Obstruction>
    23   <TrainingQueue>
     23  <ProductionQueue>
    2424    <Entities datatype="tokens">
    2525      units/cart_infantry_swordsman_2_b
    2626      units/cart_cavalry_spearman_b
    2727    </Entities>
    28   </TrainingQueue>
     28  </ProductionQueue>
    2929  <VisualActor>
    3030    <Actor>structures/carthaginians/embassy_italiote.xml</Actor>
    3131  </VisualActor>
  • binaries/data/mods/public/simulation/templates/structures/celt_civil_centre.xml

     
    1212  <Obstruction>
    1313    <Static width="25.0" depth="25.0"/>
    1414  </Obstruction>
    15   <TrainingQueue>
     15  <ProductionQueue>
    1616    <Entities datatype="tokens">
    1717      units/celt_infantry_spearman_b
    1818      units/celt_infantry_javelinist_b
    1919      units/celt_cavalry_javelinist_b
    2020    </Entities>
    21   </TrainingQueue>
     21  </ProductionQueue>
    2222  <VisualActor>
    2323    <Actor>structures/celts/civic_centre.xml</Actor>
    2424  </VisualActor>
  • binaries/data/mods/public/simulation/templates/structures/cart_civil_centre.xml

     
    55    <SpecificName>Merkāz</SpecificName>
    66    <History>Carthiginian's History</History>
    77  </Identity>
    8   <TrainingQueue>
     8  <ProductionQueue>
    99    <Entities datatype="tokens">
    1010      units/cart_infantry_spearman_b
    1111      units/cart_infantry_archer_b
    1212      units/cart_cavalry_javelinist_b
    1313    </Entities>
    14   </TrainingQueue>
     14  </ProductionQueue>
    1515  <VisualActor>
    1616    <Actor>structures/carthaginians/civil_centre.xml</Actor>
    1717  </VisualActor>
  • binaries/data/mods/public/simulation/templates/structures/athen_fortress.xml

     
    1919  <Obstruction>
    2020    <Static width="24.0" depth="26.0"/>
    2121  </Obstruction>
    22   <TrainingQueue>
     22  <ProductionQueue>
    2323    <Entities datatype="tokens">
    2424      units/athen_mechanical_siege_oxybeles
    2525      units/athen_mechanical_siege_lithobolos
    2626    </Entities>
    27   </TrainingQueue>
     27  </ProductionQueue>
    2828  <VisualActor>
    2929    <Actor>structures/athenians/fortress.xml</Actor>
    3030  </VisualActor>
  • binaries/data/mods/public/simulation/templates/structures/rome_fortress.xml

     
    55    <SpecificName>Castellum</SpecificName>
    66    <History>Fortified auxillary camp.</History>
    77  </Identity>
    8   <TrainingQueue>
     8  <ProductionQueue>
    99    <Entities datatype="tokens">
    1010      units/rome_hero_marcellus
    1111      units/rome_hero_maximus
     
    1616      units/rome_mechanical_siege_scorpio
    1717      units/rome_mechanical_siege_ram
    1818    </Entities>
    19   </TrainingQueue>
     19  </ProductionQueue>
    2020  <VisualActor>
    2121    <Actor>structures/romans/fortress.xml</Actor>
    2222  </VisualActor>
  • binaries/data/mods/public/simulation/templates/structures/mace_corral.xml

     
    1818  <Obstruction>
    1919    <Static width="14.0" depth="14.0"/>
    2020  </Obstruction>
    21   <TrainingQueue>
     21  <ProductionQueue>
    2222    <Entities datatype="tokens">
    2323      gaia/fauna_goat
    2424    </Entities>
    25   </TrainingQueue>
     25  </ProductionQueue>
    2626  <VisualActor>
    2727    <Actor>structures/hellenes/corral.xml</Actor>
    2828    <FoundationActor>structures/fndn_3x3.xml</FoundationActor>
  • binaries/data/mods/public/simulation/templates/structures/hele_dock.xml

     
    1111    <SpecificName>Limḗn</SpecificName>
    1212    <History>Greece is a sea country, which is why some of the greatest Hellenic and Hellenistic cities like Ephesus, Corinth, Alexandria and Antioch were built by the sea. It should also be noted that all colonies during the Great Colonisation were thriving port centres, which traded with the local population.</History>
    1313  </Identity>
    14   <TrainingQueue>
     14  <ProductionQueue>
    1515    <Entities datatype="tokens">
    1616      units/hele_ship_bireme
    1717      units/hele_ship_trireme
    1818    </Entities>
    19   </TrainingQueue>
     19  </ProductionQueue>
    2020  <VisualActor>
    2121    <Actor>structures/hellenes/dock.xml</Actor>
    2222  </VisualActor>
  • binaries/data/mods/public/simulation/templates/structures/pers_sb2.xml

     
    4040    <Root>false</Root>
    4141    <Radius>38</Radius>
    4242  </TerritoryInfluence>
    43   <TrainingQueue>
     43  <ProductionQueue>
    4444    <Entities datatype="tokens">
    4545      units/pers_kardakes_hoplite
    4646      units/pers_kardakes_skirmisher
    4747      units/pers_war_elephant
    4848    </Entities>
    49   </TrainingQueue>
     49  </ProductionQueue>
    5050  <VisualActor>
    5151    <Actor>structures/persians/sb2.xml</Actor>
    5252    <FoundationActor>structures/fndn_6x6.xml</FoundationActor>
  • binaries/data/mods/public/simulation/templates/structures/athen_civil_centre.xml

     
    1111    <SpecificName>Agorā́</SpecificName>
    1212    <History>The most important place in most Classical Greek poleis, the Agora served many purposes; it was a place for public speeches and was the stage for civic life and commercial interests.</History>
    1313  </Identity>
    14   <TrainingQueue>
     14  <ProductionQueue>
    1515    <Entities datatype="tokens">
    1616      units/athen_infantry_spearman_b
    1717      units/athen_infantry_slinger_b
    1818      units/athen_cavalry_javelinist_b
    1919    </Entities>
    20   </TrainingQueue>
     20  </ProductionQueue>
    2121  <VisualActor>
    2222    <Actor>structures/athenians/civic_centre_new.xml</Actor>
    2323  </VisualActor>
  • binaries/data/mods/public/simulation/templates/structures/iber_barracks.xml

     
    1111    <SpecificName>Cuartel</SpecificName>
    1212    <History>To the best of our knowledge, the Iberians did not have standing armies in the sense that we know of them elsewhere or of today, it is doubtful that they had specific structures designated as military centres; however as a game construct we show a modest structure wherein military related activities take place.</History>
    1313  </Identity>
    14   <TrainingQueue>
     14  <ProductionQueue>
    1515    <Entities datatype="tokens">
    1616      units/iber_infantry_spearman_b
    1717      units/iber_infantry_swordsman_b
     
    2020      units/iber_cavalry_spearman_b
    2121      units/iber_cavalry_javelinist_b
    2222    </Entities>
    23   </TrainingQueue>
     23  </ProductionQueue>
    2424  <VisualActor>
    2525    <Actor>structures/iberians/barracks.xml</Actor>
    2626  </VisualActor>
  • binaries/data/mods/public/simulation/templates/structures/mace_fortress.xml

     
    1919  <Obstruction>
    2020    <Static width="24.0" depth="26.0"/>
    2121  </Obstruction>
    22   <TrainingQueue>
     22  <ProductionQueue>
    2323    <Entities datatype="tokens">
    2424      units/mace_hero_philip
    2525      units/mace_hero_alexander
     
    3030      units/mace_mechanical_siege_lithobolos
    3131      units/mace_mechanical_siege_tower
    3232    </Entities>
    33   </TrainingQueue>
     33  </ProductionQueue>
    3434  <VisualActor>
    3535    <Actor>structures/hellenes/fortress_new.xml</Actor>
    3636  </VisualActor>
  • binaries/data/mods/public/simulation/templates/structures/spart_barracks.xml

     
    1515    <SpecificName>Stratēgeîon</SpecificName>
    1616    <History>The Stratigeion was the main military headquarters, where important decisions were taken and plans for battles discussed by the Hellene Generals, or "Strategoi".</History>
    1717  </Identity>
    18   <TrainingQueue>
     18  <ProductionQueue>
    1919    <Entities datatype="tokens">
    2020      units/spart_infantry_spearman_b
    2121      units/spart_champion_infantry_sword
    2222      units/spart_infantry_javelinist_b
    2323      units/spart_cavalry_javelinist_b
    2424    </Entities>
    25   </TrainingQueue>
     25  </ProductionQueue>
    2626  <VisualActor>
    2727    <Actor>structures/hellenes/barracks.xml</Actor>
    2828  </VisualActor>
  • binaries/data/mods/public/simulation/templates/structures/rome_dock.xml

     
    1212  <Obstruction>
    1313    <Static width="20.0" depth="24.0"/>
    1414  </Obstruction>
    15   <TrainingQueue>
     15  <ProductionQueue>
    1616    <Entities datatype="tokens">
    1717      units/rome_ship_bireme
    1818      units/rome_ship_trireme
    1919      units/rome_ship_quinquereme
    2020    </Entities>
    21   </TrainingQueue>
     21  </ProductionQueue>
    2222  <VisualActor>
    2323    <Actor>structures/romans/dock.xml</Actor>
    2424  </VisualActor>
  • binaries/data/mods/public/simulation/templates/structures/pers_barracks.xml

     
    1717    <Tooltip>Levy citizen-infantry units.</Tooltip>
    1818    <Icon>structures/pers_barracks.png</Icon>
    1919  </Identity>
    20   <TrainingQueue>
     20  <ProductionQueue>
    2121    <Entities datatype="tokens">
    2222      units/pers_infantry_spearman_b
    2323      units/pers_infantry_javelinist_b
    2424      units/pers_infantry_archer_b
    2525    </Entities>
    26   </TrainingQueue>
     26  </ProductionQueue>
    2727  <VisualActor>
    2828    <Actor>structures/persians/barracks.xml</Actor>
    2929  </VisualActor>
  • binaries/data/mods/public/simulation/templates/structures/celt_kennel.xml

     
    4040    <Radius>20</Radius>
    4141    <Weight>65536</Weight>
    4242  </TerritoryInfluence>
    43   <TrainingQueue>
     43  <ProductionQueue>
    4444    <Entities datatype="tokens">
    4545      units/celt_war_dog_b
    4646    </Entities>
    47   </TrainingQueue>
     47  </ProductionQueue>
    4848  <VisualActor>
    4949    <Actor>structures/celts/kennel.xml</Actor>
    5050    <FoundationActor>structures/fndn_2x2.xml</FoundationActor>
  • binaries/data/mods/public/simulation/templates/structures/celt_fortress_g.xml

     
    1616      <death>attack/destruction/building_collapse_large.xml</death>
    1717    </SoundGroups>
    1818  </Sound>
    19   <TrainingQueue>
     19  <ProductionQueue>
    2020    <Entities datatype="tokens">
    2121      units/celt_hero_brennus
    2222      units/celt_hero_britomartus
     
    2525      units/celt_champion_infantry_gaul
    2626      units/celt_mechanical_siege_ram
    2727    </Entities>
    28   </TrainingQueue>
     28  </ProductionQueue>
    2929  <VisualActor>
    3030    <Actor>structures/celts/fortress_gallic.xml</Actor>
    3131  </VisualActor>
  • binaries/data/mods/public/simulation/templates/structures/celt_corral.xml

     
    1212  <Obstruction>
    1313    <Static width="10.0" depth="20.0"/>
    1414  </Obstruction>
    15   <TrainingQueue>
     15  <ProductionQueue>
    1616    <Entities datatype="tokens">
    1717      gaia/fauna_sheep
    1818    </Entities>
    19   </TrainingQueue>
     19  </ProductionQueue>
    2020  <VisualActor>
    2121    <Actor>structures/celts/plot_corral.xml</Actor>
    2222  </VisualActor>
  • binaries/data/mods/public/simulation/templates/structures/mace_civil_centre.xml

     
    1111    <SpecificName>Agorā́</SpecificName>
    1212    <History>The most important place in most Classical Greek poleis, the Agora served many purposes; it was a place for public speeches and was the stage for civic life and commercial interests.</History>
    1313  </Identity>
    14   <TrainingQueue>
     14  <ProductionQueue>
    1515    <Entities datatype="tokens">
    1616      units/mace_infantry_spearman_b
    1717      units/mace_infantry_javelinist_b
    1818      units/mace_cavalry_spearman_b
    1919    </Entities>
    20   </TrainingQueue>
     20  </ProductionQueue>
    2121  <VisualActor>
    2222    <Actor>structures/hellenes/civic_centre_new.xml</Actor>
    2323  </VisualActor>
  • binaries/data/mods/public/simulation/templates/structures/celt_barracks.xml

     
    1414  <Obstruction>
    1515    <Static width="20.0" depth="20.0"/>
    1616  </Obstruction>
    17   <TrainingQueue>
     17  <ProductionQueue>
    1818    <Entities datatype="tokens">
    1919      units/celt_infantry_spearman_b
    2020      units/celt_infantry_javelinist_b
     
    2222      units/celt_cavalry_swordsman_b
    2323      units/celt_cavalry_javelinist_b
    2424    </Entities>
    25   </TrainingQueue>
     25  </ProductionQueue>
    2626  <VisualActor>
    2727    <Actor>structures/celts/barracks_new.xml</Actor>
    2828    <FoundationActor>structures/fndn_5x5.xml</FoundationActor>
  • binaries/data/mods/public/simulation/templates/structures/cart_barracks.xml

     
    1919  <Obstruction>
    2020    <Static width="22.0" depth="23.0"/>
    2121  </Obstruction>
    22   <TrainingQueue>
     22  <ProductionQueue>
    2323    <Entities datatype="tokens">
    2424      units/cart_infantry_spearman_b
    2525      units/cart_infantry_archer_b
    2626      units/cart_cavalry_javelinist_b
    2727    </Entities>
    28   </TrainingQueue>
     28  </ProductionQueue>
    2929  <VisualActor>
    3030    <Actor>structures/carthaginians/barracks.xml</Actor>
    3131    <FoundationActor>structures/fndn_5x5.xml</FoundationActor>
  • binaries/data/mods/public/simulation/templates/structures/hele_corral.xml

     
    1818  <Obstruction>
    1919    <Static width="14.0" depth="14.0"/>
    2020  </Obstruction>
    21   <TrainingQueue>
     21  <ProductionQueue>
    2222    <Entities datatype="tokens">
    2323      gaia/fauna_goat
    2424    </Entities>
    25   </TrainingQueue>
     25  </ProductionQueue>
    2626  <VisualActor>
    2727    <Actor>structures/hellenes/corral.xml</Actor>
    2828    <FoundationActor>structures/fndn_3x3.xml</FoundationActor>
  • binaries/data/mods/public/simulation/templates/structures/iber_dock.xml

     
    1212  <Obstruction>
    1313    <Static width="14.0" depth="24.0"/>
    1414  </Obstruction>
    15   <TrainingQueue>
     15  <ProductionQueue>
    1616    <Entities datatype="tokens">
    1717      units/iber_ship_fire
    1818    </Entities>
    19   </TrainingQueue>
     19  </ProductionQueue>
    2020  <VisualActor>
    2121    <Actor>structures/iberians/dock.xml</Actor>
    2222    <FoundationActor>structures/fndn_dock_iber.xml</FoundationActor>
  • binaries/data/mods/public/simulation/templates/structures/hele_prytaneion.xml

     
    3434      <death>attack/destruction/building_collapse_large.xml</death>
    3535    </SoundGroups>
    3636  </Sound>
    37   <TrainingQueue>
     37  <ProductionQueue>
    3838    <Entities datatype="tokens">
    3939      units/hele_hero_alexander
    4040      units/hele_hero_demetrius
     
    4343      units/hele_hero_themistocles
    4444      units/hele_hero_xenophon
    4545    </Entities>
    46   </TrainingQueue>
     46  </ProductionQueue>
    4747  <VisualActor>
    4848    <Actor>structures/hellenes/tholos.xml</Actor>
    4949  </VisualActor>
  • binaries/data/mods/public/simulation/templates/structures/spart_gerousia.xml

     
    3434      <death>attack/destruction/building_collapse_large.xml</death>
    3535    </SoundGroups>
    3636  </Sound>
    37   <TrainingQueue>
     37  <ProductionQueue>
    3838    <Entities datatype="tokens">
    3939      units/hele_hero_leonidas
    4040    </Entities>
    41   </TrainingQueue>
     41  </ProductionQueue>
    4242  <VisualActor>
    4343    <Actor>structures/hellenes/tholos.xml</Actor>
    4444  </VisualActor>
  • binaries/data/mods/public/simulation/templates/structures/spart_dock.xml

     
    1111    <SpecificName>Limḗn</SpecificName>
    1212    <History>Greece is a sea country, which is why some of the greatest Hellenic and Hellenistic cities like Ephesus, Corinth, Alexandria and Antioch were built by the sea. It should also be noted that all colonies during the Great Colonisation were thriving port centres, which traded with the local population.</History>
    1313  </Identity>
    14   <TrainingQueue>
     14  <ProductionQueue>
    1515    <Entities datatype="tokens">
    1616      units/spart_ship_bireme
    1717      units/spart_ship_trireme
    1818    </Entities>
    19   </TrainingQueue>
     19  </ProductionQueue>
    2020  <VisualActor>
    2121    <Actor>structures/hellenes/dock.xml</Actor>
    2222  </VisualActor>
  • binaries/data/mods/public/simulation/templates/structures/cart_temple.xml

     
    1818  <Obstruction>
    1919    <Static width="17.0" depth="30.0"/>
    2020  </Obstruction>
    21   <TrainingQueue>
     21  <ProductionQueue>
    2222    <Entities datatype="tokens">
    2323      units/cart_champion_infantry
    2424    </Entities>
    25   </TrainingQueue>
     25  </ProductionQueue>
    2626  <VisualActor>
    2727    <Actor>structures/carthaginians/temple_big.xml</Actor>
    2828  </VisualActor>
  • binaries/data/mods/public/simulation/templates/structures/cart_embassy_celtic.xml

     
    2424  <Obstruction>
    2525    <Static width="15.0" depth="12.0"/>
    2626  </Obstruction>
    27   <TrainingQueue>
     27  <ProductionQueue>
    2828    <Entities datatype="tokens">
    2929      units/cart_infantry_swordsman_b
    3030      units/cart_cavalry_swordsman_2_b
    3131    </Entities>
    32   </TrainingQueue>
     32  </ProductionQueue>
    3333  <VisualActor>
    3434    <Actor>structures/carthaginians/embassy_celtic.xml</Actor>
    3535  </VisualActor>
  • binaries/data/mods/public/simulation/templates/structures/athen_corral.xml

     
    1818  <Obstruction>
    1919    <Static width="14.0" depth="14.0"/>
    2020  </Obstruction>
    21   <TrainingQueue>
     21  <ProductionQueue>
    2222    <Entities datatype="tokens">
    2323      gaia/fauna_goat
    2424    </Entities>
    25   </TrainingQueue>
     25  </ProductionQueue>
    2626  <VisualActor>
    2727    <Actor>structures/athenians/corral.xml</Actor>
    2828    <FoundationActor>structures/fndn_3x3.xml</FoundationActor>
  • binaries/data/mods/public/simulation/templates/structures/hele_fortress.xml

     
    1919  <Obstruction>
    2020    <Static width="24.0" depth="26.0"/>
    2121  </Obstruction>
    22   <TrainingQueue>
     22  <ProductionQueue>
    2323    <Entities datatype="tokens">
    2424      units/hele_mechanical_siege_oxybeles
    2525      units/hele_mechanical_siege_lithobolos
    2626      units/hele_mechanical_siege_tower
    2727    </Entities>
    28   </TrainingQueue>
     28  </ProductionQueue>
    2929  <VisualActor>
    3030    <Actor>structures/hellenes/fortress_new.xml</Actor>
    3131  </VisualActor>
  • binaries/data/mods/public/simulation/templates/structures/athen_barracks.xml

     
    1515    <SpecificName>Stratēgeîon</SpecificName>
    1616    <History>The Stratigeion was the main military headquarters, where important decisions were taken and plans for battles discussed by the Hellene Generals, or "Strategoi".</History>
    1717  </Identity>
    18   <TrainingQueue>
     18  <ProductionQueue>
    1919    <Entities datatype="tokens">
    2020      units/athen_infantry_spearman_b
    2121      units/athen_infantry_javelinist_b
     
    2323      units/athen_cavalry_swordsman_b
    2424      units/athen_cavalry_javelinist_b
    2525    </Entities>
    26   </TrainingQueue>
     26  </ProductionQueue>
    2727  <VisualActor>
    2828    <Actor>structures/athenians/barracks.xml</Actor>
    2929  </VisualActor>
  • binaries/data/mods/public/simulation/templates/structures/athen_prytaneion.xml

     
    3434      <death>attack/destruction/building_collapse_large.xml</death>
    3535    </SoundGroups>
    3636  </Sound>
    37   <TrainingQueue>
     37  <ProductionQueue>
    3838    <Entities datatype="tokens">
    3939      units/athen_hero_themistocles
    4040      units/athen_hero_pericles
    4141      units/athen_hero_xenophon
    4242    </Entities>
    43   </TrainingQueue>
     43  </ProductionQueue>
    4444  <VisualActor>
    4545    <Actor>structures/athenians/prytaneion.xml</Actor>
    4646  </VisualActor>
  • binaries/data/mods/public/simulation/templates/structures/pers_dock.xml

     
    1818  <Obstruction>
    1919    <Static width="23.0" depth="15.0"/>
    2020  </Obstruction>
    21   <TrainingQueue>
     21  <ProductionQueue>
    2222    <Entities datatype="tokens">
    2323      units/pers_ship_bireme
    2424      units/pers_ship_trireme
    2525    </Entities>
    26   </TrainingQueue>
     26  </ProductionQueue>
    2727  <VisualActor>
    2828    <Actor>structures/persians/dock.xml</Actor>
    2929  </VisualActor>
  • binaries/data/mods/public/simulation/templates/structures/rome_barracks.xml

     
    1818  <Obstruction>
    1919    <Static width="24.0" depth="24.0"/>
    2020  </Obstruction>
    21   <TrainingQueue>
     21  <ProductionQueue>
    2222    <Entities datatype="tokens">
    2323      units/rome_infantry_swordsman_b
    2424      units/rome_infantry_spearman_a
    2525      units/rome_infantry_javelinist_b
    2626      units/rome_cavalry_spearman_b
    2727    </Entities>
    28   </TrainingQueue>
     28  </ProductionQueue>
    2929  <VisualActor>
    3030    <FoundationActor>structures/fndn_5x5.xml</FoundationActor>
    3131    <Actor>structures/romans/barracks.xml</Actor>
  • binaries/data/mods/public/simulation/templates/structures/cart_embassy.xml

     
    2121  <Obstruction>
    2222    <Static width="28.0" depth="28.0"/>
    2323  </Obstruction>
    24   <TrainingQueue>
     24  <ProductionQueue>
    2525    <Entities datatype="tokens">
    2626      units/cart_infantry_swordsman_b
    2727      units/cart_infantry_javelinist_b
     
    2929      units/cart_cavalry_swordsman_b
    3030      units/cart_cavalry_spearman_b
    3131    </Entities>
    32   </TrainingQueue>
     32  </ProductionQueue>
    3333  <VisualActor>
    3434    <Actor>structures/carthaginians/embassy.xml</Actor>
    3535    <FoundationActor>structures/fndn_5x5.xml</FoundationActor>
  • binaries/data/mods/public/simulation/templates/template_structure_civic_civil_centre.xml

     
    6262        CivCentre
    6363    </Classes>
    6464    <Icon>structures/civic_centre.png</Icon>
     65    <RequiredTechnology>town_phase</RequiredTechnology>
    6566  </Identity>
    6667  <Loot>
    6768    <xp>200</xp>
     
    8990    <Radius>180</Radius>
    9091    <Weight>65536</Weight>
    9192  </TerritoryInfluence>
    92   <TrainingQueue>
     93  <ProductionQueue>
    9394    <Entities datatype="tokens">
    9495      units/{civ}_support_female_citizen
    9596    </Entities>
    96   </TrainingQueue>
     97    <Technologies datatype="tokens">
     98      town_phase
     99      city_phase
     100      plough
     101    </Technologies>
     102  </ProductionQueue>
    97103  <Vision>
    98104    <Range>90</Range>
    99105  </Vision>
  • binaries/data/mods/public/simulation/templates/units/pers_infantry_spearman_b.xml

     
    2323    <SpecificName>Mada Sparabara</SpecificName>
    2424    <Icon>units/pers_infantry_spearman.png</Icon>
    2525    <History>Mede Shieldbearers comprised the main infantry regiment of the Persians during this period, especially in the reign of Xerxes. First under the Medes and later the Achaemenids these soldiers were the bread and butter infantry for hand-to-hand engagement. Within the Satabam, the basic tactical unit of the Achamenid army, the shieldbearers formed the first two ranks, protecting the arhcers and also serving as a way to keep the enemy pinned down until the cavalry could act. While well known for tenacity the shieldbearers were not equipped to last long in an extended melee with heavy infantry, like hoplites. </History>
     26    <RequiredTechnology>town_phase</RequiredTechnology>
    2627  </Identity>
    2728  <Promotion>
    2829    <Entity>units/pers_infantry_spearman_a</Entity>
  • binaries/data/mods/public/simulation/templates/units/pers_hero_cyrus.xml

     
    99Hero Aura: "Lead from the Front." Boosts attack of nearby cavalry units.</Tooltip>
    1010    <History>(559 BC - 530 BC) The son of a Median princess and the ruler of Anshan; justly called the 'Father of the Empire', Cyrus the Great conquered Media, Lydia, Babylonia and Bactria, thereby establishing the Persian Empire. He was also renown as a benevolent conqueror. Technically the second ruler of the Persians by that name, and so appears as Kurush II on his documents and coins. Kurush I was his grandfather.</History>
    1111  </Identity>
    12   <TrainingQueue>
     12  <ProductionQueue>
    1313    <Entities datatype="tokens">
    1414      units/pers_champion_infantry
    1515    </Entities>
    16   </TrainingQueue>
     16  </ProductionQueue>
    1717  <VisualActor>
    1818    <Actor>units/persians/hero_cyrus.xml</Actor>
    1919  </VisualActor>
  • binaries/data/mods/public/simulation/templates/units/athen_ship_trireme.xml

     
    99    <History>The first Triremes were built circa 650BC, and by 500BC the Trireme was the most widely used heavy warship of the Greek city-states. In the Trireme the outriggers were now an integral part of the ship's hull. The Trireme also had a partial or full fighting deck above the rowers. The length of the Trireme remained approximately 35-38 meters, and the beam was approximately 3.5 metres. A Trireme carried 170 oarsmen, plus twenty sailors and fourteen marines in Greek navies. The top speed of a Trireme was approximately 11.5 knots. Some Triremes may have been able to reach higher speeds in short bursts. A Trireme travelling from Athens to Mitylene in 427BC made the 350 kilometre trip in only 24 hours, averaging eight knots (14.6 km/h). The Trireme could accelerate much faster than a Bireme or Penteconter, and was much more manoeuvrable. This gave the Trireme an advantage in combat, where higher speed and manoeuvrability meant a better chance of victory.</History>
    1010    <Icon>units/hele_ship_trireme.png</Icon>
    1111  </Identity>
    12   <TrainingQueue>
     12  <ProductionQueue>
    1313    <Entities datatype="tokens">
    1414      units/athen_champion_marine
    1515    </Entities>
    16   </TrainingQueue>
     16  </ProductionQueue>
    1717  <VisualActor>
    1818    <Actor>structures/athenians/trireme.xml</Actor>
    1919  </VisualActor>
  • binaries/data/mods/public/simulation/templates/template_structure_economic_market.xml

     
    4949    <Radius>40</Radius>
    5050    <Weight>65536</Weight>
    5151  </TerritoryInfluence>
    52   <TrainingQueue>
     52  <ProductionQueue>
    5353    <Entities datatype="tokens">
    5454      units/{civ}_support_trader
    5555    </Entities>
    56   </TrainingQueue>
     56  </ProductionQueue>
    5757  <Vision>
    5858    <Range>32</Range>
    5959  </Vision>
  • binaries/data/mods/public/simulation/templates/other/celt_homestead.xml

     
    3535  <ResourceDropsite>
    3636    <Types>food wood stone metal</Types>
    3737  </ResourceDropsite>
    38   <TrainingQueue>
     38  <ProductionQueue>
    3939    <Entities datatype="tokens">
    4040      units/celt_cavalry_javelinist_b
    4141      units/celt_infantry_javelinist_b
    4242      units/celt_infantry_spearman_b
    4343    </Entities>
    44   </TrainingQueue>
     44  </ProductionQueue>
    4545  <TerritoryInfluence>
    4646    <Radius>100</Radius>
    4747    <Weight>65536</Weight>
  • binaries/data/mods/public/simulation/templates/other/celt_tavern.xml

     
    3939    <Radius>32</Radius>
    4040    <Weight>65536</Weight>
    4141  </TerritoryInfluence>
    42   <TrainingQueue>
     42  <ProductionQueue>
    4343    <Entities datatype="tokens">
    4444      units/celt_fanatic
    4545    </Entities>
    46   </TrainingQueue>
     46  </ProductionQueue>
    4747  <VisualActor>
    4848    <Actor>structures/celts/tavern.xml</Actor>
    4949    <FoundationActor>structures/fndn_4x4.xml</FoundationActor>
  • binaries/data/mods/public/simulation/templates/other/pers_inn.xml

     
    2121  <TerritoryInfluence>
    2222    <Radius>26</Radius>
    2323  </TerritoryInfluence>
    24   <TrainingQueue>
     24  <ProductionQueue>
    2525    <Entities datatype="tokens">
    2626      units/{civ}_support_female_citizen
    2727    </Entities>
    28   </TrainingQueue>
     28  </ProductionQueue>
    2929  <VisualActor>
    3030    <Actor>props/structures/persians/alt_building_04.xml</Actor>
    3131  </VisualActor>
  • binaries/data/mods/public/simulation/templates/other/hellenic_royal_stoa.xml

     
    4848    <Radius>40</Radius>
    4949    <Weight>65536</Weight>
    5050  </TerritoryInfluence>
    51   <TrainingQueue>
     51  <ProductionQueue>
    5252    <Entities datatype="tokens">
    5353      units/thrace_black_cloak
    5454      units/mace_thorakites
    5555      units/mace_thureophoros
    5656    </Entities>
    57   </TrainingQueue>
     57  </ProductionQueue>
    5858  <Vision>
    5959    <Range>40</Range>
    6060    <RetainInFog>true</RetainInFog>
  • binaries/data/mods/public/simulation/templates/other/pers_apartment_block.xml

     
    2121  <TerritoryInfluence>
    2222    <Radius>25</Radius>
    2323  </TerritoryInfluence>
    24   <TrainingQueue>
     24  <ProductionQueue>
    2525    <Entities datatype="tokens">
    2626      units/{civ}_support_female_citizen
    2727    </Entities>
    28   </TrainingQueue>
     28  </ProductionQueue>
    2929  <VisualActor>
    3030    <Actor>props/structures/persians/alt_building_03.xml</Actor>
    3131  </VisualActor>
  • binaries/data/mods/public/simulation/templates/other/cart_tophet.xml

     
    3434    <Static width="22.0" depth="24.0"/>
    3535  </Obstruction>
    3636  <TerritoryDecay disable=""/>
    37   <TrainingQueue>
     37  <ProductionQueue>
    3838    <Entities datatype="tokens">
    3939      units/cart_sacred_band_cavalry
    4040    </Entities>
    41   </TrainingQueue>
     41  </ProductionQueue>
    4242  <Vision>
    4343    <Range>40</Range>
    4444  </Vision>
  • binaries/data/mods/public/simulation/templates/template_structure_civic_temple.xml

     
    6363    <Radius>40</Radius>
    6464    <Weight>65536</Weight>
    6565  </TerritoryInfluence>
    66   <TrainingQueue>
     66  <ProductionQueue>
    6767    <Entities datatype="tokens">
    6868      units/{civ}_support_healer_b
    6969    </Entities>
    70   </TrainingQueue>
     70  </ProductionQueue>
    7171  <Vision>
    7272    <Range>40</Range>
    7373  </Vision>
  • binaries/data/mods/public/simulation/templates/template_structure_military_dock.xml

     
    5757    </SoundGroups>
    5858  </Sound>
    5959  <TerritoryDecay disable=""/>
    60   <TrainingQueue>
     60  <ProductionQueue>
    6161    <Entities datatype="tokens">
    6262      units/{civ}_ship_fishing
    6363      units/{civ}_ship_merchant
    6464    </Entities>
    65   </TrainingQueue>
     65  </ProductionQueue>
    6666  <Vision>
    6767    <Range>40</Range>
    6868  </Vision>