Ticket #3: technology_20-03-12.2.diff

File technology_20-03-12.2.diff, 116.1 KB (added by Jonathan Waller, 12 years ago)

proper patch now that svn is fixed

  • source/scriptinterface/ScriptInterface.cpp

     
    10231023    return ParseJSON(content);
    10241024}
    10251025
     1026static Status AddToTemplates(const VfsPath& pathname, const FileInfo& UNUSED(fileInfo), const uintptr_t cbData)
     1027{
     1028    std::vector<std::string>& templates = *(std::vector<std::string>*)cbData;
     1029
     1030    // Strip the .json extension
     1031    VfsPath pathstem = pathname.ChangeExtension(L"");
     1032    // Strip the root from the path
     1033    std::wstring name = pathstem.string().substr(ARRAY_SIZE("simulation/data/technologies/")-1);
     1034
     1035    templates.push_back(std::string(name.begin(), name.end()));
     1036    return INFO::OK;
     1037}
     1038
     1039std::vector<std::string> ScriptInterface::FindAllTechnologyTemplates()
     1040{
     1041    // TODO: eventually this should probably read all the template files and look for flags to
     1042    // determine which should be displayed in the editor (and in what categories etc); for now we'll
     1043    // just return all the files
     1044
     1045    std::vector<std::string> templates;
     1046
     1047    Status ok;
     1048
     1049    // Find all the normal entity templates first
     1050    ok = vfs::ForEachFile(g_VFS, "simulation/data/technologies/", AddToTemplates, (uintptr_t)&templates, L"*.json", vfs::DIR_RECURSIVE);
     1051    WARN_IF_ERR(ok);
     1052
     1053    return templates;
     1054}
     1055
    10261056struct Stringifier
    10271057{
    10281058    static JSBool callback(const jschar* buf, uint32 len, void* data)
  • source/scriptinterface/ScriptInterface.h

     
    230230     * Read a JSON file. Returns the undefined value on error.
    231231     */
    232232    CScriptValRooted ReadJSONFile(const VfsPath& path);
     233   
     234    std::vector<std::string> FindAllTechnologyTemplates();
    233235
    234236    /**
    235237     * Stringify to a JSON string, UTF-8 encoded. Returns an empty string on error.
  • 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
     949std::vector<std::string> CComponentManager::Script_FindAllTechnologyTemplates(void* cbdata)
     950{
     951    CComponentManager* componentManager = static_cast<CComponentManager*> (cbdata);
     952
     953    return componentManager->GetScriptInterface().FindAllTechnologyTemplates();
     954}
  • 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/public/gui/session/session.xml

     
    730730                </object>
    731731
    732732                <object name="unitResearchPanel"
    733                     style="TranslucentPanelThinBorder"
    734                     size="0 100%-56 100% 100%"
    735                     type="text"
     733                    size="14 100%-56 100% 100%"
    736734                >
    737                     <object size="-5 -2 59 62" type="image" sprite="snIconSheetTab" tooltip_style="sessionToolTipBottom"
    738                          cell_id="1" tooltip="Research"/>
    739 
    740                     [research commands]
     735                    <object size="0 0 100% 100%">
     736                        <repeat count="8">
     737                            <object name="unitResearchButton[n]" hidden="true" style="iconButton" type="button" size="0 0 46 46" tooltip_style="sessionToolTipBottom">
     738                                <object name="unitResearchIcon[n]" type="image" ghost="true" size="3 3 43 43"/>
     739                            </object>
     740                        </repeat>
     741                    </object>
    741742                </object>
    742743
    743744                <object name="unitTrainingPanel"
  • binaries/data/mods/public/gui/session/input.js

     
    737737        case "hotkeyup":
    738738            if (ev.hotkey == "session.batchtrain")
    739739            {
    740                 flushTrainingQueueBatch();
     740                flushTrainingBatch();
    741741                inputState = INPUT_NORMAL;
    742742            }
    743743            break;
     
    11691169var batchTrainingCount;
    11701170const batchIncrementSize = 5;
    11711171
    1172 function flushTrainingQueueBatch()
     1172function flushTrainingBatch()
    11731173{
    11741174    Engine.PostNetworkCommand({"type": "train", "entity": batchTrainingEntity, "template": batchTrainingType, "count": batchTrainingCount});
    11751175}
    11761176
    11771177// Called by GUI when user clicks training button
    1178 function addToTrainingQueue(entity, trainEntType)
     1178function addTrainingToQueue(entity, trainEntType)
    11791179{
    11801180    if (Engine.HotkeyIsPressed("session.batchtrain"))
    11811181    {
     
    11901190            // Otherwise start a new one
    11911191            else
    11921192            {
    1193                 flushTrainingQueueBatch();
     1193                flushTrainingBatch();
    11941194                // fall through to create the new batch
    11951195            }
    11961196        }
     
    12061206    }
    12071207}
    12081208
     1209// Called by GUI when user clicks training button
     1210function addResearchToQueue(entity, trainEntType)
     1211{
     1212    Engine.PostNetworkCommand({"type": "research", "entity": entity, "template": trainEntType});
     1213}
     1214
    12091215// Returns the number of units that will be present in a batch if the user clicks
    12101216// the training button with shift down
    1211 function getTrainingQueueBatchStatus(entity, trainEntType)
     1217function getTrainingBatchStatus(entity, trainEntType)
    12121218{
    12131219    if (inputState == INPUT_BATCHTRAINING && batchTrainingEntity == entity && batchTrainingType == trainEntType)
    12141220        return [batchTrainingCount, batchIncrementSize];
     
    12171223}
    12181224
    12191225// Called by GUI when user clicks production queue item
    1220 function removeFromTrainingQueue(entity, id)
     1226function removeFromProductionQueue(entity, id)
    12211227{
    1222     Engine.PostNetworkCommand({"type": "stop-train", "entity": entity, "id": id});
     1228    Engine.PostNetworkCommand({"type": "stop-production", "entity": entity, "id": id});
    12231229}
    12241230
    12251231// 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"];
     
    172173            if (numberOfItems > 24)
    173174                numberOfItems =  24;
    174175            break;
     176       
     177        case RESEARCH:
     178            if (numberOfItems > 8)
     179                numberOfItems =  8;
     180            break;
    175181
    176182        case CONSTRUCTION:
    177183            if (numberOfItems > 24)
     
    192198    for (i = 0; i < numberOfItems; i++)
    193199    {
    194200        var item = items[i];
    195         var entType = ((guiName == "Queue")? item.template : item);
     201       
     202        // If a tech has been researched it leaves an empty slot
     203        if (guiName == RESEARCH && !item)
     204        {
     205            getGUIObjectByName("unit"+guiName+"Button["+i+"]").hidden = true;
     206            continue;
     207        }
     208       
    196209        var template;
    197         if (guiName != "Formation" && guiName != "Command" && guiName != "Stance")
     210        var entType;
     211        if (guiName == QUEUE)
    198212        {
    199             template = GetTemplateData(entType);
     213            // The queue can hold both technologies and units so we need to use the correct code for loading the templates
     214            if (item.unitTemplate)
     215            {
     216                entType = item.unitTemplate;
     217                template = GetTemplateData(entType);
     218            }
     219            else if (item.technologyTemplate)
     220            {
     221                entType = item.technologyTemplate;
     222                template = GetTechnologyData(entType);
     223            }
     224           
    200225            if (!template)
    201                 continue; // ignore attempts to use invalid templates (an error should have been reported already)
     226                    continue; // ignore attempts to use invalid templates (an error should have been reported already)
    202227        }
     228        else
     229        {
     230            entType = item;
     231            if (guiName != FORMATION && guiName != COMMAND && guiName != STANCE && guiName != RESEARCH)
     232            {
     233                template = GetTemplateData(entType);
     234                if (!template)
     235                    continue; // ignore attempts to use invalid templates (an error should have been reported already)
     236            }
     237           
     238            if (guiName == RESEARCH)
     239            {
     240                template = GetTechnologyData(entType);
     241                if (!template)
     242                    continue; // TODO: should make some kind of warning happen somewhere in the code
     243            }   
     244        }
    203245
    204246        switch (guiName)
    205247        {
     
    242284                if (template.tooltip)
    243285                    tooltip += "\n[font=\"serif-13\"]" + template.tooltip + "[/font]";
    244286
    245                 var [batchSize, batchIncrement] = getTrainingQueueBatchStatus(unitEntState.id, entType);
     287                var [batchSize, batchIncrement] = getTrainingBatchStatus(unitEntState.id, entType);
    246288                var trainNum = batchSize ? batchSize+batchIncrement : batchIncrement;
    247289
    248290                tooltip += "\n" + getEntityCost(template);
     
    259301                tooltip += "\n\n[font=\"serif-bold-13\"]Shift-click[/font][font=\"serif-13\"] to train " + trainNum + ".[/font]";
    260302
    261303                break;
     304               
     305            case RESEARCH:
     306                var tooltip = getEntityNameWithGenericType(template);
    262307
     308                if (template.tooltip)
     309                    tooltip += "\n[font=\"serif-13\"]" + template.tooltip + "[/font]";
     310
     311                tooltip += "\n" + getEntityCost(template);
     312                break;
     313
    263314            case CONSTRUCTION:
    264315                var tooltip = getEntityNameWithGenericType(template);
    265316                if (template.tooltip)
     
    344395        }
    345396        else if (template.icon)
    346397        {
    347             icon.sprite = "stretched:session/portraits/" + template.icon;
     398            var grayscale = "";
     399            button.enabled = true;
     400           
     401            if (template.requiredTechnology && !Engine.GuiInterfaceCall("IsTechnologyResearched", template.requiredTechnology))
     402            {
     403                button.enabled = false;
     404                var techName = getEntityName(GetTechnologyData(template.requiredTechnology));
     405                button.tooltip += "\nRequires " + techName;
     406                grayscale = "grayscale:";
     407            }
     408           
     409            if (guiName == RESEARCH && !Engine.GuiInterfaceCall("CheckTechnologyRequirements", entType))
     410            {
     411                button.enabled = false;
     412                button.tooltip += "\n" + GetTechnologyData(entType).requirementsTooltip;
     413                grayscale = "grayscale:";
     414            }
     415           
     416            icon.sprite = "stretched:" + grayscale + "session/portraits/" + template.icon;
    348417        }
    349418        else
    350419        {
     
    539608            setupUnitPanel("Construction", usedPanels, entState, entState.buildEntities, startBuildingPlacement);
    540609//          isInvisible = false;
    541610        }
    542 
    543         if (entState.training && entState.training.entities.length)
     611       
     612        if (entState.production && entState.production.entities.length)
    544613        {
    545             setupUnitPanel("Training", usedPanels, entState, entState.training.entities,
    546                 function (trainEntType) { addToTrainingQueue(entState.id, trainEntType); } );
     614            setupUnitPanel("Training", usedPanels, entState, entState.production.entities,
     615                function (trainEntType) { addTrainingToQueue(entState.id, trainEntType); } );
    547616//          isInvisible = false;
    548617        }
     618       
     619        if (entState.production && entState.production.technologies.length)
     620        {
     621            setupUnitPanel("Research", usedPanels, entState, entState.production.technologies,
     622                function (researchType) { addResearchToQueue(entState.id, researchType); } );
     623//          isInvisible = false;
     624        }
    549625
    550         if (entState.training && entState.training.queue.length)
    551             setupUnitPanel("Queue", usedPanels, entState, entState.training.queue,
    552                 function (item) { removeFromTrainingQueue(entState.id, item.id); } );
     626        if (entState.production && entState.production.queue.length)
     627            setupUnitPanel("Queue", usedPanels, entState, entState.production.queue,
     628                function (item) { removeFromProductionQueue(entState.id, item.id); } );
    553629
    554630        if (entState.trader)
    555631        {
  • 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

     
    121121        // Verify that the building can be controlled by the player
    122122        if (CanControlUnit(cmd.entity, player, controlAllUnits))
    123123        {
    124             var queue = Engine.QueryInterface(cmd.entity, IID_TrainingQueue);
    125             if (queue)
    126                 queue.AddBatch(cmd.template, +cmd.count, cmd.metadata);
     124            var cmpTechMan = QueryOwnerInterface(cmd.entity, IID_TechnologyManager);
     125            // TODO: Enable this check once the AI gets technology support
     126            if (cmpTechMan.CanProduce(cmd.template) || true)
     127            {
     128                var queue = Engine.QueryInterface(cmd.entity, IID_ProductionQueue);
     129                if (queue)
     130                    queue.AddBatch(cmd.template, "unit", +cmd.count, cmd.metadata);
     131            }
     132            else if (g_DebugCommands)
     133            {
     134                warn("Invalid command: training requires unresearched technology: " + uneval(cmd));
     135            }
    127136        }
    128137        else if (g_DebugCommands)
    129138        {
     
    131140        }
    132141        break;
    133142
    134     case "stop-train":
     143    case "research":
    135144        // Verify that the building can be controlled by the player
    136145        if (CanControlUnit(cmd.entity, player, controlAllUnits))
    137146        {
    138             var queue = Engine.QueryInterface(cmd.entity, IID_TrainingQueue);
     147            var cmpTechMan = QueryOwnerInterface(cmd.entity, IID_TechnologyManager);
     148            // TODO: Enable this check once the AI gets technology support
     149            if (cmpTechMan.CanResearch(cmd.template) || true)
     150            {
     151                var queue = Engine.QueryInterface(cmd.entity, IID_ProductionQueue);
     152                if (queue)
     153                    queue.AddBatch(cmd.template, "technology");
     154            }
     155            else if (g_DebugCommands)
     156            {
     157                warn("Invalid command: Requirements to research technology are not met: " + uneval(cmd));
     158            }
     159        }
     160        else if (g_DebugCommands)
     161        {
     162            warn("Invalid command: research building cannot be controlled by player "+player+": "+uneval(cmd));
     163        }
     164        break;
     165
     166    case "stop-production":
     167        // Verify that the building can be controlled by the player
     168        if (CanControlUnit(cmd.entity, player, controlAllUnits))
     169        {
     170            var queue = Engine.QueryInterface(cmd.entity, IID_ProductionQueue);
    139171            if (queue)
    140172                queue.RemoveBatch(cmd.id);
    141173        }
    142174        else if (g_DebugCommands)
    143175        {
    144             warn("Invalid command: training building cannot be controlled by player "+player+": "+uneval(cmd));
     176            warn("Invalid command: production building cannot be controlled by player "+player+": "+uneval(cmd));
    145177        }
    146178        break;
    147179
     
    219251            Engine.DestroyEntity(ent);
    220252            break;
    221253        }
     254       
     255        var cmpTechMan = QueryPlayerIDInterface(player, IID_TechnologyManager);
     256        // TODO: Enable this check once the AI gets technology support
     257        if (!cmpTechMan.CanProduce(cmd.template) && false)
     258        {
     259            if (g_DebugCommands)
     260            {
     261                warn("Invalid command: required technology check failed for player "+player+": "+uneval(cmd));
     262            }
    222263
     264            var cmpGuiInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface);
     265            cmpGuiInterface.PushNotification({ "player": player, "message": "Building's technology requirements are not met." });
     266
     267            // Remove the foundation because the construction was aborted
     268            Engine.DestroyEntity(ent);
     269        }
     270
    223271        // TODO: AI has no visibility info
    224272        if (!cmpPlayer.IsAI())
    225273        {
  • 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(),
     
    176176        ret.buildEntities = cmpBuilder.GetEntitiesList();
    177177    }
    178178
    179     var cmpTrainingQueue = Engine.QueryInterface(ent, IID_TrainingQueue);
    180     if (cmpTrainingQueue)
     179    var cmpProductionQueue = Engine.QueryInterface(ent, IID_ProductionQueue);
     180    if (cmpProductionQueue)
    181181    {
    182         ret.training = {
    183             "entities": cmpTrainingQueue.GetEntitiesList(),
    184             "queue": cmpTrainingQueue.GetQueue(),
     182        ret.production = {
     183            "entities": cmpProductionQueue.GetEntitiesList(),
     184            "technologies": cmpProductionQueue.GetTechnologiesList(),
     185            "queue": cmpProductionQueue.GetQueue(),
    185186        };
    186187    }
    187188
     
    336337        };
    337338        ret.icon = template.Identity.Icon;
    338339        ret.tooltip =  template.Identity.Tooltip;
     340        ret.requiredTechnology = template.Identity.RequiredTechnology;
    339341    }
    340342
    341343    if (template.UnitMotion)
     
    349351    return ret;
    350352};
    351353
     354GuiInterface.prototype.GetTechnologyData = function(player, name)
     355{
     356    var cmpTechTempMan = Engine.QueryInterface(SYSTEM_ENTITY, IID_TechnologyTemplateManager);
     357    var template = cmpTechTempMan.GetTemplate(name);
     358   
     359    if (!template)
     360        return null;
     361   
     362    var ret = {};
     363   
     364    ret.name = {
     365        "specific": template.specificName,
     366        "generic": template.genericName,
     367    };
     368    ret.icon = template.icon;
     369    ret.cost = {
     370        "food": +template.cost.food,
     371        "wood": +template.cost.wood,
     372        "metal": +template.cost.metal,
     373        "stone": +template.cost.stone,
     374    }
     375    ret.tooltip = template.tooltip;
     376   
     377    if (template.requirementsTooltip)
     378        ret.requirementsTooltip = template.requirementsTooltip;
     379    else
     380        ret.requirementsTooltip = "";
     381   
     382    ret.description = template.description;
     383   
     384    return ret;
     385};
     386
     387GuiInterface.prototype.IsTechnologyResearched = function(player, tech)
     388{
     389    var cmpTechMan = QueryPlayerIDInterface(player, IID_TechnologyManager);
     390   
     391    if (!cmpTechMan)
     392        return false;
     393   
     394    return cmpTechMan.IsTechnologyResearched(tech);
     395}
     396
     397// Checks whether the requirements for this technology have been met
     398GuiInterface.prototype.CheckTechnologyRequirements = function(player, tech)
     399{
     400    var cmpTechMan = QueryPlayerIDInterface(player, IID_TechnologyManager);
     401   
     402    if (!cmpTechMan)
     403        return false;
     404   
     405    return cmpTechMan.CanResearch(tech);
     406}
     407
    352408GuiInterface.prototype.PushNotification = function(notification)
    353409{
    354410    this.notifications.push(notification);
     
    781837    "ClearRenamedEntities": 1,
    782838    "GetEntityState": 1,
    783839    "GetTemplateData": 1,
     840    "GetTechnologyData": 1,
     841    "IsTechnologyResearched": 1,
     842    "CheckTechnologyRequirements": 1,
    784843    "GetNextNotification": 1,
    785844
    786845    "CanMoveEntsIntoFormation": 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");
  • 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/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

     
    1111Engine.LoadComponentScript("interfaces/ResourceDropsite.js");
    1212Engine.LoadComponentScript("interfaces/ResourceGatherer.js");
    1313Engine.LoadComponentScript("interfaces/ResourceSupply.js");
    14 Engine.LoadComponentScript("interfaces/TrainingQueue.js");
     14Engine.LoadComponentScript("interfaces/ProductionQueue.js");
    1515Engine.LoadComponentScript("interfaces/Trader.js")
    1616Engine.LoadComponentScript("interfaces/Timer.js");
    1717Engine.LoadComponentScript("interfaces/StatisticsTracker.js");
     
    5757    GetPopulationLimit: function() { return 20; },
    5858    GetMaxPopulation: function() { return 200; },
    5959    GetResourceCounts: function() { return { food: 100 }; },
    60     IsTrainingQueueBlocked: function() { return false; },
     60    IsTrainingBlocked: function() { return false; },
    6161    GetState: function() { return "active"; },
    6262    GetTeam: function() { return -1; },
    6363    GetDiplomacy: function() { return [-1, 1]; },
     
    104104    GetPopulationLimit: function() { return 30; },
    105105    GetMaxPopulation: function() { return 300; },
    106106    GetResourceCounts: function() { return { food: 200 }; },
    107     IsTrainingQueueBlocked: function() { return false; },
     107    IsTrainingBlocked: function() { return false; },
    108108    GetState: function() { return "active"; },
    109109    GetTeam: function() { return -1; },
    110110    GetDiplomacy: function() { return [-1, 1]; },
     
    156156            popLimit: 20,
    157157            popMax: 200,
    158158            resourceCounts: { food: 100 },
    159             trainingQueueBlocked: false,
     159            trainingBlocked: false,
    160160            state: "active",
    161161            team: -1,
    162162            phase: "",
     
    173173            popLimit: 30,
    174174            popMax: 300,
    175175            resourceCounts: { food: 200 },
    176             trainingQueueBlocked: false,
     176            trainingBlocked: false,
    177177            state: "active",
    178178            team: -1,
    179179            phase: "village",
     
    197197            popLimit: 20,
    198198            popMax: 200,
    199199            resourceCounts: { food: 100 },
    200             trainingQueueBlocked: false,
     200            trainingBlocked: false,
    201201            state: "active",
    202202            team: -1,
    203203            phase: "",
     
    230230            popLimit: 30,
    231231            popMax: 300,
    232232            resourceCounts: { food: 200 },
    233             trainingQueueBlocked: false,
     233            trainingBlocked: false,
    234234            state: "active",
    235235            team: -1,
    236236            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

     
    105105    this.changes.idle = msg.idle;
    106106};
    107107
    108 AIProxy.prototype.OnTrainingQueueChanged = function(msg)
     108AIProxy.prototype.OnProductionQueueChanged = function(msg)
    109109{
    110110    this.NotifyChange();
    111111
    112     var cmpTrainingQueue = Engine.QueryInterface(this.entity, IID_TrainingQueue);
    113     this.changes.trainingQueue = cmpTrainingQueue.GetQueue();
     112    var cmpProductionQueue = Engine.QueryInterface(this.entity, IID_ProductionQueue);
     113    this.changes.trainingQueue = cmpProductionQueue.GetQueue();
    114114}
    115115
    116116AIProxy.prototype.OnGarrisonedUnitsChanged = function(msg)
     
    170170        ret.idle = cmpUnitAI.IsIdle();
    171171    }
    172172
    173     var cmpTrainingQueue = Engine.QueryInterface(this.entity, IID_TrainingQueue);
    174     if (cmpTrainingQueue)
     173    var cmpProductionQueue = Engine.QueryInterface(this.entity, IID_ProductionQueue);
     174    if (cmpProductionQueue)
    175175    {
    176         // Updated by OnTrainingQueueChanged
    177         ret.trainingQueue = cmpTrainingQueue.GetQueue();
     176        // Updated by OnProductionQueueChanged
     177        ret.trainingQueue = cmpProductionQueue.GetQueue();
    178178    }
    179179
    180180    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.allTech = cmpTechTempMan.GetAllTechs();
     10    this.researchedTech = {}; // technologies which have been researched
     11    this.inProgressTech = {}; // technologies which are being ersearched currently
     12   
     13    // Some technologies are automatically researched when their conditions are met.  They have no cost and are
     14    // researched instantly
     15    this.autoResearchTech = {};
     16    for (var key in this.allTech)
     17    {
     18        if (this.allTech[key].autoResearch)
     19            this.autoResearchTech[key] = this.allTech[key];
     20    }
     21   
     22    this._UpdateAutoResearch();
     23};
     24
     25// This fnuction checks if the requirements of any autoresearch techs are met and if they are it researches then
     26TechnologyManager.prototype._UpdateAutoResearch = function ()
     27{
     28    for (var key in this.autoResearchTech)
     29    {
     30        if (this.CanResearch(key))
     31        {
     32            delete this.autoResearchTech[key];
     33            this.ResearchTechnology(key);
     34            return; // We will have recursively handled any knock-on effects so can just return
     35        }
     36    }
     37}
     38
     39TechnologyManager.prototype.GetTechnologyTemplate = function (tech)
     40{
     41    return this.allTech[tech];
     42};
     43
     44// This function checks an entity template to see if it's technology requirements have been met
     45TechnologyManager.prototype.CanProduce = function (templateName)
     46{
     47    var cmpTempManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_TemplateManager);
     48    var template = cmpTempManager.GetTemplate(templateName);
     49   
     50    if (template.Identity && template.Identity.RequiredTechnology)
     51        return this.IsTechnologyResearched(template.Identity.RequiredTechnology);
     52    else
     53        return true; // If there is no required technology then this entity can be produced
     54};
     55
     56TechnologyManager.prototype.IsTechnologyResearched = function (tech)
     57{
     58    return (this.researchedTech[tech] !== undefined);
     59};
     60
     61// Checks the requirements for a technology to see if it can be researched at the current time
     62TechnologyManager.prototype.CanResearch = function (tech)
     63{
     64    var template = this.GetTechnologyTemplate(tech);
     65    if (!template)
     66        return false;
     67   
     68    var ret = true;
     69   
     70    // The technology which this tech supercedes is required
     71    if (template.supercedes)
     72        ret = ret && this.IsTechnologyResearched(template.supercedes);
     73   
     74    ret = ret && this._CheckTechnologyRequirements(template.requirements);
     75   
     76    return ret;
     77};
     78
     79    TechnologyManager.prototype._CheckTechnologyRequirements = function (reqs)
     80    {
     81        // If there are no requirements then they are all met
     82        if (!reqs)
     83            return true;
     84       
     85        if (reqs.tech)
     86        {
     87            return this.IsTechnologyResearched(reqs.tech);
     88        }
     89        else if (reqs.all)
     90        {
     91            var ret = true;
     92            for (var i = 0; i < reqs.all.length; i++)
     93            {
     94                ret = ret && this._CheckTechnologyRequirements(reqs.all[i]);
     95            }
     96            return ret;
     97        }
     98       
     99        // The technologies requirements are not a recognised format
     100        error("Bad requirements " + uneval(reqs));
     101        return false;
     102    };
     103   
     104// Marks a technology as researched.  Note that this does not verify that the requirements are met.
     105TechnologyManager.prototype.ResearchTechnology = function (tech)
     106{
     107    this.StoppedResearch(tech); // The tech is no longer being currently researched
     108   
     109    var template = this.GetTechnologyTemplate(tech);
     110    if (template)
     111    {
     112        this.researchedTech[tech] = template;
     113    }
     114    else
     115    {
     116        error("Tried to research invalid techonology: " + uneval(tech));
     117    }
     118   
     119    this._UpdateAutoResearch();
     120};
     121
     122// Marks a technology as being currently researched
     123TechnologyManager.prototype.StartedResearch = function (tech)
     124{
     125    this.inProgressTech[tech] = true;
     126};
     127
     128// Marks a technology as not being currently researched
     129TechnologyManager.prototype.StoppedResearch = function (tech)
     130{
     131    delete this.inProgressTech[tech];
     132};
     133
     134// Checks whether a technology is being currently researched
     135TechnologyManager.prototype.IsInProgress = function(tech)
     136{
     137    if (this.inProgressTech[tech])
     138        return this.inProgressTech[tech];
     139    else
     140        return false;
     141}
     142
     143Engine.RegisterComponentType(IID_TechnologyManager, "TechnologyManager", TechnologyManager);
     144 No newline at end of file
  • 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'>" +
     13    "<optional><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'>" +
    1414        "<attribute name='datatype'>" +
    1515            "<value>tokens</value>" +
    1616        "</attribute>" +
    1717        "<text/>" +
    18     "</element>";
     18    "</element></optional>" +
     19    "<optional><element name='Technologies' a:help='Space-separated list of technology names that this building can research.'>" +
     20        "<attribute name='datatype'>" +
     21            "<value>tokens</value>" +
     22        "</attribute>" +
     23        "<text/>" +
     24    "</element></optional>";
    1925
    20 TrainingQueue.prototype.Init = function()
     26ProductionQueue.prototype.Init = function()
    2127{
    2228    this.nextID = 1;
    2329
     
    2632    //   {
    2733    //     "id": 1,
    2834    //     "player": 1, // who paid for this batch; we need this to cope with refunds cleanly
    29     //     "template": "units/example",
     35    //     "unitTemplate": "units/example",
    3036    //     "count": 10,
    3137    //     "resources": { "wood": 100, ... },   // resources per unit, multiply by count to get total
    3238    //     "population": 1, // population per unit, multiply by count to get total
    33     //     "trainingStarted": false, // true iff we have reserved population
     39    //     "productionStarted": false, // true iff we have reserved population
    3440    //     "timeTotal": 15000, // msecs
    3541    //     "timeRemaining": 10000, // msecs
    3642    //   }
     43    //   
     44    //   {
     45    //     "id": 1,
     46    //     "player": 1, // who paid for this batch; we need this to cope with refunds cleanly
     47    //     "technologyTemplate": "example_tech",
     48    //     "resources": { "wood": 100, ... },   // resources per unit, multiply by count to get total
     49    //     "productionStarted": false, // true iff production has started
     50    //     "timeTotal": 15000, // msecs
     51    //     "timeRemaining": 10000, // msecs
     52    //   }
    3753   
    3854    this.timer = undefined; // g_ProgressInterval msec timer, active while the queue is non-empty
    3955   
     
    4460/*
    4561 * Returns list of entities that can be trained by this building.
    4662 */
    47 TrainingQueue.prototype.GetEntitiesList = function()
     63ProductionQueue.prototype.GetEntitiesList = function()
    4864{
     65    if (!this.template.Entities)
     66        return [];
     67   
    4968    var string = this.template.Entities._string;
    5069   
    5170    // Replace the "{civ}" codes with this entity's civ ID
     
    5776};
    5877
    5978/*
    60  * Adds a new batch of identical units to the training queue.
     79 * Returns list of technologies that can be researched by this building.
    6180 */
    62 TrainingQueue.prototype.AddBatch = function(templateName, count, metadata)
     81ProductionQueue.prototype.GetTechnologiesList = function()
    6382{
     83    if (!this.template.Technologies)
     84        return [];
     85   
     86    var string = this.template.Technologies._string;
     87   
     88    var cmpTechMan = QueryOwnerInterface(this.entity, IID_TechnologyManager);
     89    if (!cmpTechMan)
     90        return [];
     91   
     92    var techs = string.split(/\s+/);
     93    var ret = [];
     94    var superceded = {}; // Stores the tech which supercedes the key
     95   
     96    // Add any top level technologies to an array which corresponds to the displayed icons
     97    // Also store the "children" for the superceding,
     98    for (var i in techs)
     99    {
     100        var tech = techs[i];
     101        var template = cmpTechMan.GetTechnologyTemplate(tech);
     102        if (!template.supercedes || techs.indexOf(template.supercedes) === -1)
     103            ret.push(tech);
     104        else
     105            superceded[template.supercedes] = tech;
     106    }
     107   
     108    // Now make researched/in progress techs invisible
     109    for (var i in ret)
     110    {
     111        var tech = ret[i];
     112        while (cmpTechMan.IsTechnologyResearched(tech) || cmpTechMan.IsInProgress(tech))
     113            tech = superceded[tech];
     114       
     115        ret[i] = tech;
     116    }
     117   
     118    return ret;
     119};
     120
     121/*
     122 * Adds a new batch of identical units to train or a technology to research to the production queue.
     123 */
     124ProductionQueue.prototype.AddBatch = function(templateName, type, count, metadata)
     125{
    64126    // TODO: there should probably be a limit on the number of queued batches
    65127    // TODO: there should be a way for the GUI to determine whether it's going
    66128    // to be possible to add a batch (based on resource costs and length limits)
     
    68130
    69131    if (this.queue.length < MAX_QUEUE_SIZE)
    70132    {
    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;
     133       
     134        if (type == "unit")
     135        {
     136            // Find the template data so we can determine the build costs
     137            var cmpTempMan = Engine.QueryInterface(SYSTEM_ENTITY, IID_TemplateManager);
     138            var template = cmpTempMan.GetTemplate(templateName);
     139            if (!template)
     140                return;
     141           
     142            // Apply a time discount to larger batches.
     143            // TODO: work out what equation we should use here.
     144            var timeMult = Math.pow(count, 0.7);
    76145
    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);
     146            var time = timeMult * template.Cost.BuildTime;
    80147
    81         var time = timeMult * template.Cost.BuildTime;
     148            var totalCosts = {};
     149            for each (var r in ["food", "wood", "stone", "metal"])
     150                totalCosts[r] = Math.floor(count * template.Cost.Resources[r]);
    82151
    83         var totalCosts = {};
    84         for each (var r in ["food", "wood", "stone", "metal"])
    85             totalCosts[r] = Math.floor(count * template.Cost.Resources[r]);
     152            var population = template.Cost.Population;
     153       
     154            // TrySubtractResources should report error to player (they ran out of resources)
     155            if (!cmpPlayer.TrySubtractResources(totalCosts))
     156                return;
    86157
    87         var population = template.Cost.Population;
    88    
    89         // TrySubtractResources should report error to player (they ran out of resources)
    90         if (!cmpPlayer.TrySubtractResources(totalCosts))
     158            this.queue.push({
     159                "id": this.nextID++,
     160                "player": cmpPlayer.GetPlayerID(),
     161                "unitTemplate": templateName,
     162                "count": count,
     163                "metadata": metadata,
     164                "resources": deepcopy(template.Cost.Resources), // need to copy to avoid serialization problems
     165                "population": population,
     166                "productionStarted": false,
     167                "timeTotal": time*1000,
     168                "timeRemaining": time*1000,
     169            });
     170        }
     171        else if (type == "technology")
     172        {
     173            // Load the technology template
     174            var cmpTechTempMan = Engine.QueryInterface(SYSTEM_ENTITY, IID_TechnologyTemplateManager);
     175            var template = cmpTechTempMan.GetTemplate(templateName);
     176            if (!template)
     177                return;
     178           
     179            var time = template.researchTime;
     180
     181            var cost = {};
     182            for each (var r in ["food", "wood", "stone", "metal"])
     183                cost[r] = Math.floor(template.cost[r]);
     184           
     185            // TrySubtractResources should report error to player (they ran out of resources)
     186            if (!cmpPlayer.TrySubtractResources(cost))
     187                return;
     188           
     189            // Tell the technology manager that we have started researching this so that people can't research the same
     190            // thing twice.
     191            var cmpTechMan = QueryOwnerInterface(this.entity, IID_TechnologyManager);
     192            cmpTechMan.StartedResearch(templateName);
     193
     194            this.queue.push({
     195                "id": this.nextID++,
     196                "player": cmpPlayer.GetPlayerID(),
     197                "count": 1,
     198                "technologyTemplate": templateName,
     199                "resources": deepcopy(template.cost), // need to copy to avoid serialization problems
     200                "productionStarted": false,
     201                "timeTotal": time*1000,
     202                "timeRemaining": time*1000,
     203            });
     204        }
     205        else
     206        {
    91207            return;
     208        }
     209       
     210        Engine.PostMessage(this.entity, MT_ProductionQueueChanged, { });
    92211
    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 
    107212        // If this is the first item in the queue, start the timer
    108213        if (!this.timer)
    109214        {
    110215            var cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
    111             this.timer = cmpTimer.SetTimeout(this.entity, IID_TrainingQueue, "ProgressTimeout", g_ProgressInterval, {});
     216            this.timer = cmpTimer.SetTimeout(this.entity, IID_ProductionQueue, "ProgressTimeout", g_ProgressInterval, {});
    112217        }
    113218    }
    114219    else
    115220    {
    116         var notification = {"player": cmpPlayer.GetPlayerID(), "message": "The training queue is full."};
     221        var notification = {"player": cmpPlayer.GetPlayerID(), "message": "The production queue is full."};
    117222        var cmpGUIInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface);
    118223        cmpGUIInterface.PushNotification(notification);
    119224    }
    120225};
    121226
    122227/*
    123  * Removes an existing batch of units from the training queue.
     228 * Removes an existing batch of units from the production queue.
    124229 * Refunds resource costs and population reservations.
    125230 */
    126 TrainingQueue.prototype.RemoveBatch = function(id)
     231ProductionQueue.prototype.RemoveBatch = function(id)
    127232{
    128233    // Destroy any cached entities (those which didn't spawn for some reason)
    129234    for (var i = 0; i < this.entityCache.length; ++i)
     
    139244            continue;
    140245
    141246        // Now we've found the item to remove
    142 
     247       
    143248        var cmpPlayer = QueryPlayerIDInterface(item.player, IID_Player);
    144249
    145250        // Refund the resource cost for this batch
    146251        var totalCosts = {};
    147252        for each (var r in ["food", "wood", "stone", "metal"])
    148253            totalCosts[r] = Math.floor(item.count * item.resources[r]);
    149            
     254       
    150255        cmpPlayer.AddResources(totalCosts);
    151 
     256       
    152257        // Remove reserved population slots if necessary
    153         if (item.trainingStarted)
     258        if (item.productionStarted && item.unitTemplate)
    154259            cmpPlayer.UnReservePopulationSlots(item.population * item.count);
    155 
     260       
     261        // Mark the research as stopped if we cancel it
     262        if (item.technologyTemplate)
     263        {
     264            var cmpTechMan = QueryOwnerInterface(this.entity, IID_TechnologyManager);
     265            cmpTechMan.StoppedResearch(item.technologyTemplate);
     266        }
     267       
    156268        // Remove from the queue
    157269        // (We don't need to remove the timer - it'll expire if it discovers the queue is empty)
    158270        this.queue.splice(i, 1);
    159         Engine.PostMessage(this.entity, MT_TrainingQueueChanged, { });
     271        Engine.PostMessage(this.entity, MT_ProductionQueueChanged, { });
    160272
    161273        return;
    162274    }
    163275};
    164276
    165277/*
    166  * Returns basic data from all batches in the training queue.
     278 * Returns basic data from all batches in the production queue.
    167279 */
    168 TrainingQueue.prototype.GetQueue = function()
     280ProductionQueue.prototype.GetQueue = function()
    169281{
    170282    var out = [];
    171283    for each (var item in this.queue)
    172284    {
    173285        out.push({
    174286            "id": item.id,
    175             "template": item.template,
     287            "unitTemplate": item.unitTemplate,
     288            "technologyTemplate": item.technologyTemplate,
    176289            "count": item.count,
    177290            "progress": 1-(item.timeRemaining/item.timeTotal),
    178291            "metadata": item.metadata,
     
    184297/*
    185298 * Removes all existing batches from the queue.
    186299 */
    187 TrainingQueue.prototype.ResetQueue = function()
     300ProductionQueue.prototype.ResetQueue = function()
    188301{
    189     // Empty the training queue and refund all the resource costs
     302    // Empty the production queue and refund all the resource costs
    190303    // to the player. (This is to avoid players having to micromanage their
    191304    // buildings' queues when they're about to be destroyed or captured.)
    192305
     
    194307        this.RemoveBatch(this.queue[0].id);
    195308};
    196309
    197 TrainingQueue.prototype.OnOwnershipChanged = function(msg)
     310ProductionQueue.prototype.OnOwnershipChanged = function(msg)
    198311{
    199312    if (msg.from != -1)
    200313    {
    201         // Unset flag that previous owner's training queue may be blocked
     314        // Unset flag that previous owner's training may be blocked
    202315        var cmpPlayer = QueryPlayerIDInterface(msg.from, IID_Player);
    203316        if (cmpPlayer && this.queue.length > 0)
    204             cmpPlayer.UnBlockTrainingQueue();
     317            cmpPlayer.UnBlockTraining();
    205318    }
    206319
    207     // Reset the training queue whenever the owner changes.
     320    // Reset the production queue whenever the owner changes.
    208321    // (This should prevent players getting surprised when they capture
    209322    // an enemy building, and then loads of the enemy's civ's soldiers get
    210323    // created from it. Also it means we don't have to worry about
     
    212325    this.ResetQueue();
    213326};
    214327
    215 TrainingQueue.prototype.OnDestroy = function()
     328ProductionQueue.prototype.OnDestroy = function()
    216329{
    217330    // Reset the queue to refund any resources
    218331    this.ResetQueue();
     
    228341 * This function creates the entities and places them in world if possible.
    229342 * returns the number of successfully spawned entities.
    230343 */
    231 TrainingQueue.prototype.SpawnUnits = function(templateName, count, metadata)
     344ProductionQueue.prototype.SpawnUnits = function(templateName, count, metadata)
    232345{
    233346    var cmpFootprint = Engine.QueryInterface(this.entity, IID_Footprint);
    234347    var cmpPosition = Engine.QueryInterface(this.entity, IID_Position);
     
    302415};
    303416
    304417/*
    305  * Increments progress on the first batch in the training queue, and blocks the
     418 * Increments progress on the first batch in the production queue, and blocks the
    306419 * queue if population limit is reached or some units failed to spawn.
    307420 */
    308 TrainingQueue.prototype.ProgressTimeout = function(data)
     421ProductionQueue.prototype.ProgressTimeout = function(data)
    309422{
    310423    // Allocate the 1000msecs to as many queue items as it takes
    311424    // until we've used up all the time (so that we work accurately
     
    316429    while (time > 0 && this.queue.length)
    317430    {
    318431        var item = this.queue[0];
    319         if (!item.trainingStarted)
     432        if (!item.productionStarted)
    320433        {
    321             // Batch's training hasn't started yet.
    322             // Try to reserve the necessary population slots
    323             if (!cmpPlayer.TryReservePopulationSlots(item.population * item.count))
     434            // If the item is a unit then do population checks
     435            if (item.unitTemplate)
    324436            {
    325                 // No slots available - don't train this batch now
    326                 // (we'll try again on the next timeout)
     437                // Batch's training hasn't started yet.
     438                // Try to reserve the necessary population slots
     439                if (item.unitTemplate && !cmpPlayer.TryReservePopulationSlots(item.population * item.count))
     440                {
     441                    // No slots available - don't train this batch now
     442                    // (we'll try again on the next timeout)
    327443
    328                 // Set flag that training queue is blocked
    329                 cmpPlayer.BlockTrainingQueue();
    330                 break;
     444                    // Set flag that training is blocked
     445                    cmpPlayer.BlockTraining();
     446                    break;
     447                }
     448               
     449                // Unset flag that training is blocked
     450                cmpPlayer.UnBlockTraining();
    331451            }
    332452
    333             // Unset flag that training queue is blocked
    334             cmpPlayer.UnBlockTrainingQueue();
    335 
    336             item.trainingStarted = true;
     453            item.productionStarted = true;
    337454        }
    338455
    339456        // If we won't finish the batch now, just update its timer
     
    343460            break;
    344461        }
    345462
    346         var numSpawned = this.SpawnUnits(item.template, item.count, item.metadata);
    347         if (numSpawned == item.count)
     463        if (item.unitTemplate)
    348464        {
    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)
     465            var numSpawned = this.SpawnUnits(item.unitTemplate, item.count, item.metadata);
     466            if (numSpawned == item.count)
    361467            {
    362                 // Only partially finished
     468                // All entities spawned, this batch finished
    363469                cmpPlayer.UnReservePopulationSlots(item.population * numSpawned);
    364                 item.count -= numSpawned;
    365                 Engine.PostMessage(this.entity, MT_TrainingQueueChanged, { });
     470                time -= item.timeRemaining;
     471                this.queue.shift();
     472                // Unset flag that training is blocked
     473                cmpPlayer.UnBlockTraining();
     474                this.spawnNotified = false;
     475                Engine.PostMessage(this.entity, MT_ProductionQueueChanged, { });
    366476            }
     477            else
     478            {
     479                if (numSpawned > 0)
     480                {
     481                    // Only partially finished
     482                    cmpPlayer.UnReservePopulationSlots(item.population * numSpawned);
     483                    item.count -= numSpawned;
     484                    Engine.PostMessage(this.entity, MT_ProductionQueueChanged, { });
     485                }
    367486
    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;
     487                // Some entities failed to spawn
     488                // Set flag that training is blocked
     489                cmpPlayer.BlockTraining();
     490               
     491                if (!this.spawnNotified)
     492                {
     493                    var cmpPlayer = QueryOwnerInterface(this.entity, IID_Player);
     494                    var notification = {"player": cmpPlayer.GetPlayerID(), "message": "Can't find free space to spawn trained units" };
     495                    var cmpGUIInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface);
     496                    cmpGUIInterface.PushNotification(notification);
     497                    this.spawnNotified = true;
     498                }
     499                break;
    379500            }
    380             break;
    381501        }
     502        else if (item.technologyTemplate)
     503        {
     504            var cmpTechnologyManager = QueryOwnerInterface(this.entity, IID_TechnologyManager);
     505            cmpTechnologyManager.ResearchTechnology(item.technologyTemplate);
     506           
     507            this.queue.shift();
     508            Engine.PostMessage(this.entity, MT_ProductionQueueChanged, { });
     509        }
    382510    }
    383511
    384512    // If the queue's empty, delete the timer, else repeat it
     
    386514    {
    387515        this.timer = undefined;
    388516
    389         // Unset flag that training queue is blocked
     517        // Unset flag that training is blocked
    390518        // (This might happen when the player unqueues all batches)
    391         cmpPlayer.UnBlockTrainingQueue();
     519        cmpPlayer.UnBlockTraining();
    392520    }
    393521    else
    394522    {
    395523        var cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
    396         this.timer = cmpTimer.SetTimeout(this.entity, IID_TrainingQueue, "ProgressTimeout", g_ProgressInterval, data);
     524        this.timer = cmpTimer.SetTimeout(this.entity, IID_ProductionQueue, "ProgressTimeout", g_ProgressInterval, data);
    397525    }
    398526}
    399527
    400 Engine.RegisterComponentType(IID_TrainingQueue, "TrainingQueue", TrainingQueue);
     528Engine.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/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    "supercedes": "village_phase",
     6    "icon": "technologies/town_phase.png",
     7    "researchTime": 10,
     8    "tooltip": "Advance to Town Phase"
     9}
  • binaries/data/mods/public/simulation/data/technologies/city_phase.json

     
     1{
     2    "genericName": "City Phase",
     3    "description": "Advances from a bustling town to a veritable metropolis, full of the wonders of modern technology.",
     4    "cost": {"food": 0, "wood": 0, "stone": 50, "metal": 0},
     5    "supercedes": "town_phase",
     6    "icon": "technologies/city_phase.png",
     7    "researchTime": 10,
     8    "tooltip": "Advance to City Phase"
     9}
  • 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": 100, "wood": 100, "stone": 0, "metal": 50},
     5    "requirements": {"tech": "town_phase"},
     6    "requirementsTooltip": "Requires Town Phase",
     7    "icon": "technologies/plough.png",
     8    "researchTime": 10,
     9    "tooltip": "Discover the Plough"
     10}
  • 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_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/rome_army_camp.xml

     
    6767    <HealthDecayRate>5</HealthDecayRate>
    6868  </TerritoryDecay>
    6969  <TerritoryInfluence disable=""/>
    70   <TrainingQueue>
     70  <ProductionQueue>
    7171    <Entities datatype="tokens">
    7272      units/rome_infantry_swordsman_b
    7373      units/rome_infantry_spearman_a
     
    7777      units/rome_mechanical_siege_scorpio
    7878      units/rome_mechanical_siege_ram
    7979    </Entities>
    80   </TrainingQueue>
     80  </ProductionQueue>
    8181  <Vision>
    8282    <Range>60</Range>
    8383  </Vision>
     
    8585    <FoundationActor>structures/fndn_8x8.xml</FoundationActor>
    8686    <Actor>structures/romans/camp.xml</Actor>
    8787  </VisualActor>
    88 </Entity>
    89  No newline at end of file
     88</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/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_apadana.xml

     
    3131    <Root>true</Root>
    3232    <Radius>38</Radius>
    3333  </TerritoryInfluence>
    34   <TrainingQueue>
     34  <ProductionQueue>
    3535    <Entities datatype="tokens">
    3636      units/pers_hero_cyrus
    3737      units/pers_hero_darius
    3838      units/pers_hero_xerxes
    3939      units/pers_champion_infantry
    4040    </Entities>
    41   </TrainingQueue>
     41  </ProductionQueue>
    4242  <VisualActor>
    4343    <Actor>structures/persians/sb1_new.xml</Actor>
    4444    <FoundationActor>structures/fndn_6x6.xml</FoundationActor>
  • 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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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  <Obstruction>
    6768    <Static width="30.0" depth="30.0"/>
     
    8182    <Radius>180</Radius>
    8283    <Weight>65536</Weight>
    8384  </TerritoryInfluence>
    84   <TrainingQueue>
     85  <ProductionQueue>
    8586    <Entities datatype="tokens">
    8687      units/{civ}_support_female_citizen
    8788    </Entities>
    88   </TrainingQueue>
     89    <Technologies datatype="tokens">
     90      town_phase
     91      city_phase
     92      plough
     93    </Technologies>
     94  </ProductionQueue>
    8995  <Vision>
    9096    <Range>90</Range>
    9197  </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/template_structure_economic_market.xml

     
    4242    <Radius>40</Radius>
    4343    <Weight>65536</Weight>
    4444  </TerritoryInfluence>
    45   <TrainingQueue>
     45  <ProductionQueue>
    4646    <Entities datatype="tokens">
    4747      units/{civ}_support_trader
    4848    </Entities>
    49   </TrainingQueue>
     49  </ProductionQueue>
    5050  <Vision>
    5151    <Range>32</Range>
    5252  </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/thebes_sacred_band_hoplitai
    5454      units/thespian_melanochitones
     
    5757      units/mace_thorakites
    5858      units/mace_thureophoros
    5959    </Entities>
    60   </TrainingQueue>
     60  </ProductionQueue>
    6161  <Vision>
    6262    <Range>40</Range>
    6363    <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

     
    5656    <Radius>40</Radius>
    5757    <Weight>65536</Weight>
    5858  </TerritoryInfluence>
    59   <TrainingQueue>
     59  <ProductionQueue>
    6060    <Entities datatype="tokens">
    6161      units/{civ}_support_healer_b
    6262    </Entities>
    63   </TrainingQueue>
     63  </ProductionQueue>
    6464  <Vision>
    6565    <Range>40</Range>
    6666  </Vision>
  • binaries/data/mods/public/simulation/templates/template_structure_military_dock.xml

     
    5050    </SoundGroups>
    5151  </Sound>
    5252  <TerritoryDecay disable=""/>
    53   <TrainingQueue>
     53  <ProductionQueue>
    5454    <Entities datatype="tokens">
    5555      units/{civ}_ship_fishing
    5656      units/{civ}_ship_merchant
    5757    </Entities>
    58   </TrainingQueue>
     58  </ProductionQueue>
    5959  <Vision>
    6060    <Range>40</Range>
    6161  </Vision>