Ticket #3: technology_07-04-12.2.diff

File technology_07-04-12.2.diff, 139.3 KB (added by quantumstate, 14 months 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>