Ticket #3: technology_07-04-12.2.diff

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

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

     
    8181        m_ScriptInterface.RegisterFunction<int, std::string, CComponentManager::Script_AddLocalEntity> ("AddLocalEntity");
    8282        m_ScriptInterface.RegisterFunction<void, int, CComponentManager::Script_DestroyEntity> ("DestroyEntity");
    8383        m_ScriptInterface.RegisterFunction<CScriptVal, std::wstring, CComponentManager::Script_ReadJSONFile> ("ReadJSONFile");
     84        m_ScriptInterface.RegisterFunction<std::vector<std::string>, CComponentManager::Script_FindAllTechnologyTemplates> ("FindAllTechnologyTemplates");
    8485    }
    8586
    8687    // Define MT_*, IID_* as script globals, and store their names
     
    944945
    945946    return componentManager->GetScriptInterface().ReadJSONFile(path).get();
    946947}
     948
     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        }
  • 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/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)
  • binaries/data/mods/public/simulation/templates/units/pers_infantry_spearman_b.xml

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

     
    99Hero Aura: "Lead from the Front." Boosts attack of nearby cavalry units.</Tooltip>
    1010    <History>(559 BC - 530 BC) The son of a Median princess and the ruler of Anshan; justly called the 'Father of the Empire', Cyrus the Great conquered Media, Lydia, Babylonia and Bactria, thereby establishing the Persian Empire. He was also renown as a benevolent conqueror. Technically the second ruler of the Persians by that name, and so appears as Kurush II on his documents and coins. Kurush I was his grandfather.</History>
    1111  </Identity>
    12   <TrainingQueue>
     12  <ProductionQueue>
    1313    <Entities datatype="tokens">
    1414      units/pers_champion_infantry
    1515    </Entities>
    16   </TrainingQueue>
     16  </ProductionQueue>
    1717  <VisualActor>
    1818    <Actor>units/persians/hero_cyrus.xml</Actor>
    1919  </VisualActor>
  • binaries/data/mods/public/simulation/templates/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>
  • 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/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_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"/>
     
    8283    <Radius>180</Radius>
    8384    <Weight>65536</Weight>
    8485  </TerritoryInfluence>
    85   <TrainingQueue>
     86  <ProductionQueue>
    8687    <Entities datatype="tokens">
    8788      units/{civ}_support_female_citizen
    8889    </Entities>
    89   </TrainingQueue>
     90    <Technologies datatype="tokens">
     91      town_phase
     92      city_phase
     93      plough
     94    </Technologies>
     95  </ProductionQueue>
    9096  <Vision>
    9197    <Range>90</Range>
    9298  </Vision>
  • 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_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/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/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/rome_army_camp.xml

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

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

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

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

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

     
    1010  </BuildLimits>
    1111  <Player/>
    1212  <StatisticsTracker/>
     13  <TechnologyManager/>
    1314</Entity>
  • 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/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/hellenic_royal_stoa.xml

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

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

     
     1{
     2    "genericName": "Village Phase",
     3    "description": "Advances from a small village to a bustling town, ready to expand rapidly.",
     4    "autoResearch": true,
     5    "icon": "technologies/town_phase.png",
     6    "researchTime": 10,
     7    "tooltip": "Advance to Town Phase"
     8}
  • binaries/data/mods/public/simulation/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/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/TechnologyTemplateManager.js

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

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

     
    1 Engine.RegisterInterface("TrainingQueue");
     1Engine.RegisterInterface("ProductionQueue");
    22
    33// Message of the form { } (use GetQueue if you want the current details),
    44// sent to the current entity whenever the training queue changes.
    5 Engine.RegisterMessageType("TrainingQueueChanged");
     5Engine.RegisterMessageType("ProductionQueueChanged");
    66
    77// Message of the form { entities: [id, ...], metadata: ... }
    88// sent to the current entity whenever a unit has been trained.
  • binaries/data/mods/public/simulation/components/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/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/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 researched currently
     12   
     13    // This stores the modifications to unit stats from researched technologies
     14    // Example data: {"ResourceGatherer/Rates/food.grain": [ {"multiplier": 1.15, "affects": ["Female", "Infantry Swordsman"]},
     15    //                                                      {"add": 2} ]}
     16    this.modifications = {};
     17   
     18    // Some technologies are automatically researched when their conditions are met.  They have no cost and are
     19    // researched instantly.  This allows civ bonuses and more complicated technologies.
     20    this.autoResearchTech = {};
     21    for (var key in this.allTech)
     22    {
     23        if (this.allTech[key].autoResearch)
     24            this.autoResearchTech[key] = this.allTech[key];
     25    }
     26   
     27    this._UpdateAutoResearch();
     28};
     29
     30// This fnuction checks if the requirements of any autoresearch techs are met and if they are it researches then
     31TechnologyManager.prototype._UpdateAutoResearch = function ()
     32{
     33    for (var key in this.autoResearchTech)
     34    {
     35        if (this.CanResearch(key))
     36        {
     37            delete this.autoResearchTech[key];
     38            this.ResearchTechnology(key);
     39            return; // We will have recursively handled any knock-on effects so can just return
     40        }
     41    }
     42}
     43
     44TechnologyManager.prototype.GetTechnologyTemplate = function (tech)
     45{
     46    return this.allTech[tech];
     47};
     48
     49// This function checks an entity template to see if it's technology requirements have been met
     50TechnologyManager.prototype.CanProduce = function (templateName)
     51{
     52    var cmpTempManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_TemplateManager);
     53    var template = cmpTempManager.GetTemplate(templateName);
     54   
     55    if (template.Identity && template.Identity.RequiredTechnology)
     56        return this.IsTechnologyResearched(template.Identity.RequiredTechnology);
     57    else
     58        return true; // If there is no required technology then this entity can be produced
     59};
     60
     61TechnologyManager.prototype.IsTechnologyResearched = function (tech)
     62{
     63    return (this.researchedTech[tech] !== undefined);
     64};
     65
     66// Checks the requirements for a technology to see if it can be researched at the current time
     67TechnologyManager.prototype.CanResearch = function (tech)
     68{
     69    var template = this.GetTechnologyTemplate(tech);
     70    if (!template)
     71        return false;
     72   
     73    var ret = true;
     74   
     75    // The technology which this tech supercedes is required
     76    if (template.supercedes)
     77        ret = ret && this.IsTechnologyResearched(template.supercedes);
     78   
     79    ret = ret && this._CheckTechnologyRequirements(template.requirements);
     80   
     81    return ret;
     82};
     83
     84    TechnologyManager.prototype._CheckTechnologyRequirements = function (reqs)
     85    {
     86        // If there are no requirements then they are all met
     87        if (!reqs)
     88            return true;
     89       
     90        if (reqs.tech)
     91        {
     92            return this.IsTechnologyResearched(reqs.tech);
     93        }
     94        else if (reqs.all)
     95        {
     96            var ret = true;
     97            for (var i = 0; i < reqs.all.length; i++)
     98            {
     99                ret = ret && this._CheckTechnologyRequirements(reqs.all[i]);
     100            }
     101            return ret;
     102        }
     103       
     104        // The technologies requirements are not a recognised format
     105        error("Bad requirements " + uneval(reqs));
     106        return false;
     107    };
     108   
     109// Marks a technology as researched.  Note that this does not verify that the requirements are met.
     110TechnologyManager.prototype.ResearchTechnology = function (tech)
     111{
     112    this.StoppedResearch(tech); // The tech is no longer being currently researched
     113   
     114    var template = this.GetTechnologyTemplate(tech);
     115    if (template)
     116    {
     117        var modifiedComponents = {};
     118        this.researchedTech[tech] = template;
     119        // store the modifications in an easy to access structure
     120        if (template.modifications)
     121        {
     122            var affects = [];
     123            if (template.affects && template.affects.length > 0)
     124            {
     125                for (var i in template.affects)
     126                {
     127                    // Put the list of classes into an array for convenient access
     128                    affects.push(template.affects[i].split(" "));
     129                }
     130            }
     131            else
     132            {
     133                affects.push([]);
     134            }
     135           
     136            // We add an item to this.modifications for every
     137            for (var i in template.modifications)
     138            {
     139                var modification = template.modifications[i];
     140                if (!this.modifications[modification.value])
     141                    this.modifications[modification.value] = [];
     142               
     143                var mod = {"affects": affects};
     144                // copy the modification data into our new data structure
     145                for (var j in modification)
     146                    if (j !== "value")
     147                        mod[j] = modification[j]
     148               
     149                this.modifications[modification.value].push(mod);
     150                modifiedComponents[modification.value.split("/")[0]] = true;
     151            }
     152        }
     153       
     154        var cmpPlayer = Engine.QueryInterface(this.entity, IID_Player);
     155        var player = cmpPlayer.GetPlayerID();
     156       
     157        for (var component in modifiedComponents)
     158            Engine.BroadcastMessage(MT_TechnologyModificationChange, { "component": component, "player": player });
     159    }
     160    else
     161    {
     162        error("Tried to research invalid techonology: " + uneval(tech));
     163    }
     164   
     165    this._UpdateAutoResearch();
     166};
     167
     168TechnologyManager.prototype.ApplyModifications = function(valueName, curValue, ent)
     169{
     170    // TODO: Add some caching here if it is too slow
     171   
     172    // Get all modifications to this value
     173    var modifications = this.modifications[valueName];
     174    if (!modifications) // no modifications so return the orignal value
     175        return curValue;
     176   
     177    // Get the classes which this entity belongs to
     178    var cmpIdentity = Engine.QueryInterface(ent, IID_Identity);
     179    var classes = cmpIdentity.GetClassesList();
     180   
     181    var retValue = +curValue;
     182   
     183    for (var i in modifications)
     184    {
     185        var modification = modifications[i];
     186        var applies = false;
     187        // See if any of the lists of classes matches this entity
     188        for (var j in modification.affects)
     189        {
     190            var hasAllClasses = true;
     191            // Check each
     192            for (var k in modification.affects[j])
     193                hasAllClasses = hasAllClasses && (classes.indexOf(modification.affects[j][k]) !== -1);
     194           
     195            if (hasAllClasses)
     196            {
     197                applies = true;
     198                break;
     199            }
     200        }
     201       
     202        // Nothing is cumulative so that ordering doesn't matter as much as possible
     203        if (modification.multiplier)
     204            retValue += (modification.multiplier - 1) * +curValue;
     205        else if (modification.add)
     206            retValue += modification.add;
     207        else if (modification.replace) // This will depend on ordering because there is no choice
     208            retValue = modification.replace;
     209    }
     210   
     211    return retValue;
     212};
     213
     214// Marks a technology as being currently researched
     215TechnologyManager.prototype.StartedResearch = function (tech)
     216{
     217    this.inProgressTech[tech] = true;
     218};
     219
     220// Marks a technology as not being currently researched
     221TechnologyManager.prototype.StoppedResearch = function (tech)
     222{
     223    delete this.inProgressTech[tech];
     224};
     225
     226// Checks whether a technology is being currently researched
     227TechnologyManager.prototype.IsInProgress = function(tech)
     228{
     229    if (this.inProgressTech[tech])
     230        return this.inProgressTech[tech];
     231    else
     232        return false;
     233}
     234
     235Engine.RegisterComponentType(IID_TechnologyManager, "TechnologyManager", TechnologyManager);
  • binaries/data/mods/public/simulation/components/ResourceGatherer.js

     
    123123        return undefined;
    124124};
    125125
     126// Remove any cached template data which is based on technology data
     127ResourceGatherer.prototype.OnTechnologyModificationChange = function(msg)
     128{
     129    var cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership);
     130    if (!cmpOwnership)
     131        return;
     132   
     133    var player = cmpOwnership.GetOwner();
     134   
     135    if (msg.component === "ResourceGatherer" && msg.player === player)
     136        delete this.gatherRatesCache;
     137};
     138
    126139ResourceGatherer.prototype.GetGatherRates = function()
    127140{
    128     var ret = {};
    129     for (var r in this.template.Rates)
    130         ret[r] = this.template.Rates[r] * this.template.BaseSpeed;
    131     return ret;
     141    if (!this.gatherRatesCache){
     142        this.gatherRatesCache = {};
     143        var cmpTechManager = QueryOwnerInterface(this.entity, IID_TechnologyManager);
     144        var baseSpeed = cmpTechManager.ApplyModifications("ResourceGatherer/BaseSpeed", this.template.BaseSpeed, this.entity);
     145        for (var r in this.template.Rates)
     146        {
     147            var rate = cmpTechManager.ApplyModifications("ResourceGatherer/Rates/" + r, this.template.Rates[r], this.entity);
     148            this.gatherRatesCache[r] = rate * baseSpeed;
     149        }
     150    }
     151   
     152    return this.gatherRatesCache;
    132153};
    133154
    134155ResourceGatherer.prototype.GetRange = function()
    135156{
    136157    return { "max": +this.template.MaxDistance, "min": 0 };
    137158    // maybe this should depend on the unit or target or something?
    138 }
     159};
    139160
    140161/**
    141162 * Try to gather treasure
     
    219240    var type = cmpResourceSupply.GetType();
    220241
    221242    var rate;
    222     if (type.specific && this.template.Rates[type.generic+"."+type.specific])
    223         rate = this.template.Rates[type.generic+"."+type.specific];
     243    if (type.specific && this.GetGatherRates()[type.generic+"."+type.specific])
     244        rate = this.GetGatherRates()[type.generic+"."+type.specific];
    224245    else
    225         rate = this.template.Rates[type.generic];
     246        rate = this.GetGatherRates()[type.generic];
    226247
    227     return (rate || 0) * this.template.BaseSpeed;
    228 }
     248    return (rate || 0);
     249};
    229250
    230251/**
    231252 * Returns whether this unit can carry more of the given type of resource.
  • 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/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/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/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);
     
    802858    "ClearRenamedEntities": 1,
    803859    "GetEntityState": 1,
    804860    "GetTemplateData": 1,
     861    "GetTechnologyData": 1,
     862    "IsTechnologyResearched": 1,
     863    "CheckTechnologyRequirements": 1,
    805864    "GetNextNotification": 1,
    806865
    807866    "GetFormationRequirements": 1,
  • binaries/data/mods/public/simulation/components/AIProxy.js

     
    119119    this.changes.unitAIOrderData = msg.to;
    120120};
    121121
    122 AIProxy.prototype.OnTrainingQueueChanged = function(msg)
     122AIProxy.prototype.OnProductionQueueChanged = function(msg)
    123123{
    124124    this.NotifyChange();
    125125
    126     var cmpTrainingQueue = Engine.QueryInterface(this.entity, IID_TrainingQueue);
    127     this.changes.trainingQueue = cmpTrainingQueue.GetQueue();
     126    var cmpProductionQueue = Engine.QueryInterface(this.entity, IID_ProductionQueue);
     127    this.changes.trainingQueue = cmpProductionQueue.GetQueue();
    128128}
    129129
    130130AIProxy.prototype.OnGarrisonedUnitsChanged = function(msg)
     
    188188        ret.unitAIOrderData = cmpUnitAI.GetOrderData();
    189189    }
    190190
    191     var cmpTrainingQueue = Engine.QueryInterface(this.entity, IID_TrainingQueue);
    192     if (cmpTrainingQueue)
     191    var cmpProductionQueue = Engine.QueryInterface(this.entity, IID_ProductionQueue);
     192    if (cmpProductionQueue)
    193193    {
    194         // Updated by OnTrainingQueueChanged
    195         ret.trainingQueue = cmpTrainingQueue.GetQueue();
     194        // Updated by OnProductionQueueChanged
     195        ret.trainingQueue = cmpProductionQueue.GetQueue();
    196196    }
    197197
    198198    var cmpFoundation = Engine.QueryInterface(this.entity, IID_Foundation);
  • binaries/data/mods/public/simulation/ai/common-api-v2/entity.js

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

     
    2020// CCmpTemplateManager::CopyFoundationSubset and only includes components
    2121// that our EntityTemplate class currently uses.)
    2222var g_FoundationForbiddenComponents = {
    23     "TrainingQueue": 1,
     23    "ProductionQueue": 1,
    2424    "ResourceSupply": 1,
    2525    "ResourceDropsite": 1,
    2626    "GarrisonHolder": 1,
  • binaries/data/mods/public/simulation/ai/common-api/entity.js

     
    126126    },
    127127
    128128    trainableEntities: function() {
    129         if (!this._template.TrainingQueue)
     129        if (!this._template.ProductionQueue)
    130130            return undefined;
    131131        var civ = this.civ();
    132         var templates = this._template.TrainingQueue.Entities._string.replace(/\{civ\}/g, civ).split(/\s+/);
     132        var templates = this._template.ProductionQueue.Entities._string.replace(/\{civ\}/g, civ).split(/\s+/);
    133133        return templates;
    134134    },
    135135
  • binaries/data/mods/public/simulation/ai/common-api/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/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)
     
    364415        }
    365416        else if (template.icon)
    366417        {
    367             icon.sprite = "stretched:session/portraits/" + template.icon;
     418            var grayscale = "";
     419            button.enabled = true;
     420           
     421            if (template.requiredTechnology && !Engine.GuiInterfaceCall("IsTechnologyResearched", template.requiredTechnology))
     422            {
     423                button.enabled = false;
     424                var techName = getEntityName(GetTechnologyData(template.requiredTechnology));
     425                button.tooltip += "\nRequires " + techName;
     426                grayscale = "grayscale:";
     427            }
     428           
     429            if (guiName == RESEARCH && !Engine.GuiInterfaceCall("CheckTechnologyRequirements", entType))
     430            {
     431                button.enabled = false;
     432                button.tooltip += "\n" + GetTechnologyData(entType).requirementsTooltip;
     433                grayscale = "grayscale:";
     434            }
     435           
     436            icon.sprite = "stretched:" + grayscale + "session/portraits/" + template.icon;
    368437        }
    369438        else
    370439        {
     
    559628            setupUnitPanel("Construction", usedPanels, entState, entState.buildEntities, startBuildingPlacement);
    560629//          isInvisible = false;
    561630        }
    562 
    563         if (entState.training && entState.training.entities.length)
     631       
     632        if (entState.production && entState.production.entities.length)
    564633        {
    565             setupUnitPanel("Training", usedPanels, entState, entState.training.entities,
    566                 function (trainEntType) { addToTrainingQueue(entState.id, trainEntType); } );
     634            setupUnitPanel("Training", usedPanels, entState, entState.production.entities,
     635                function (trainEntType) { addTrainingToQueue(entState.id, trainEntType); } );
    567636//          isInvisible = false;
    568637        }
     638       
     639        if (entState.production && entState.production.technologies.length)
     640        {
     641            setupUnitPanel("Research", usedPanels, entState, entState.production.technologies,
     642                function (researchType) { addResearchToQueue(entState.id, researchType); } );
     643//          isInvisible = false;
     644        }
    569645
    570         if (entState.training && entState.training.queue.length)
    571             setupUnitPanel("Queue", usedPanels, entState, entState.training.queue,
    572                 function (item) { removeFromTrainingQueue(entState.id, item.id); } );
     646        if (entState.production && entState.production.queue.length)
     647            setupUnitPanel("Queue", usedPanels, entState, entState.production.queue,
     648                function (item) { removeFromProductionQueue(entState.id, item.id); } );
    573649
    574650        if (entState.trader)
    575651        {
  • 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/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/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/internal/simulation/templates/structures/spart_syssiton.xml

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

     
    3434      <death>attack/destruction/building_collapse_large.xml</death>
    3535    </SoundGroups>
    3636  </Sound>
    37   <TrainingQueue>
     37  <ProductionQueue>
    3838    <Entities datatype="tokens">
    3939      units/hele_hero_leonidas
    4040    </Entities>
    41   </TrainingQueue>
     41  </ProductionQueue>
    4242  <VisualActor>
    4343    <Actor>structures/hellenes/tholos.xml</Actor>
    4444  </VisualActor>
  • binaries/data/mods/internal/simulation/templates/structures/spart_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    </Entities>
    27   </TrainingQueue>
     27  </ProductionQueue>
    2828  <VisualActor>
    2929    <Actor>structures/hellenes/fortress_new.xml</Actor>
    3030  </VisualActor>
  • binaries/data/mods/internal/simulation/templates/structures/spart_dock.xml

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

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

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

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

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

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

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

     
    1111    <SpecificName>Agorā́</SpecificName>
    1212    <History>The most important place in most Classical Greek poleis, the Agora served many purposes; it was a place for public speeches and was the stage for civic life and commercial interests.</History>
    1313  </Identity>
    14   <TrainingQueue>
     14  <ProductionQueue>
    1515    <Entities datatype="tokens">
    1616      units/mace_infantry_spearman_b
    1717      units/mace_infantry_javelinist_b
    1818      units/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/internal/simulation/templates/structures/mace_barracks.xml

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

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

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

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