LCOV - code coverage report
Current view: top level - simulation/components - Upgrade.js (source / functions) Hit Total Coverage
Test: lcov.info Lines: 111 173 64.2 %
Date: 2023-04-02 12:52:40 Functions: 16 21 76.2 %

          Line data    Source code
       1             : function Upgrade() {}
       2             : 
       3           1 : const UPGRADING_PROGRESS_INTERVAL = 250;
       4             : 
       5           1 : Upgrade.prototype.Schema =
       6             :         "<oneOrMore>" +
       7             :                 "<element>" +
       8             :                         "<anyName />" +
       9             :                         "<interleave>" +
      10             :                                 "<element name='Entity' a:help='Entity to upgrade to'>" +
      11             :                                         "<text/>" +
      12             :                                 "</element>" +
      13             :                                 "<optional>" +
      14             :                                         "<element name='Icon' a:help='Icon to show in the GUI'>" +
      15             :                                                 "<text/>" +
      16             :                                         "</element>" +
      17             :                                 "</optional>" +
      18             :                                 "<optional>" +
      19             :                                         "<element name='Variant' a:help='The name of the variant to switch to when upgrading'>" +
      20             :                                                 "<text/>" +
      21             :                                         "</element>" +
      22             :                                 "</optional>" +
      23             :                                 "<optional>" +
      24             :                                         "<element name='Tooltip' a:help='This will be added to the tooltip to help the player choose why to upgrade.'>" +
      25             :                                                 "<text/>" +
      26             :                                         "</element>" +
      27             :                                 "</optional>" +
      28             :                                 "<optional>" +
      29             :                                         "<element name='Time' a:help='Time required to upgrade this entity, in seconds'>" +
      30             :                                                 "<data type='nonNegativeInteger'/>" +
      31             :                                         "</element>" +
      32             :                                 "</optional>" +
      33             :                                 "<optional>" +
      34             :                                         "<element name='Cost' a:help='Resource cost to upgrade this unit'>" +
      35             :                                                 "<oneOrMore>" +
      36             :                                                         "<choice>" +
      37             :                                                                 Resources.BuildSchema("nonNegativeInteger") +
      38             :                                                         "</choice>" +
      39             :                                                 "</oneOrMore>" +
      40             :                                         "</element>" +
      41             :                                 "</optional>" +
      42             :                                 "<optional>" +
      43             :                                         RequirementsHelper.BuildSchema() +
      44             :                                 "</optional>" +
      45             :                                 "<optional>" +
      46             :                                         "<element name='CheckPlacementRestrictions' a:help='Upgrading will check for placement restrictions (nb:GUI only)'><empty/></element>" +
      47             :                                 "</optional>" +
      48             :                         "</interleave>" +
      49             :                 "</element>" +
      50             :         "</oneOrMore>";
      51             : 
      52           1 : Upgrade.prototype.Init = function()
      53             : {
      54           1 :         this.elapsedTime = 0;
      55           1 :         this.expendedResources = {};
      56             : };
      57             : 
      58             : // This will also deal with the "OnDestroy" case.
      59           1 : Upgrade.prototype.OnOwnershipChanged = function(msg)
      60             : {
      61           1 :         if (!this.completed)
      62           1 :                 this.CancelUpgrade(msg.from);
      63             : 
      64           1 :         if (msg.to != INVALID_PLAYER)
      65             :         {
      66           1 :                 this.owner = msg.to;
      67           1 :                 this.DetermineUpgrades();
      68             :         }
      69             : };
      70             : 
      71           1 : Upgrade.prototype.DetermineUpgrades = function()
      72             : {
      73           1 :         this.upgradeTemplates = {};
      74             : 
      75           1 :         for (const choice in this.template)
      76             :         {
      77           1 :                 const nativeCiv = Engine.QueryInterface(this.entity, IID_Identity).GetCiv();
      78           1 :                 const playerCiv = QueryPlayerIDInterface(this.owner, IID_Identity).GetCiv();
      79           1 :                 const name = this.template[choice].Entity.
      80             :                         replace(/\{native\}/g, nativeCiv).
      81             :                         replace(/\{civ\}/g, playerCiv);
      82             : 
      83           1 :                 if (!Engine.QueryInterface(SYSTEM_ENTITY, IID_TemplateManager).TemplateExists(name))
      84           0 :                         continue;
      85             : 
      86           1 :                 if (this.upgradeTemplates[name])
      87           0 :                         warn("Upgrade Component: entity " + this.entity + " has two upgrades to the same entity, only the last will be used.");
      88             : 
      89           1 :                 this.upgradeTemplates[name] = choice;
      90             :         }
      91             : };
      92             : 
      93           1 : Upgrade.prototype.ChangeUpgradedEntityCount = function(amount)
      94             : {
      95           2 :         if (!this.IsUpgrading())
      96           0 :                 return;
      97             : 
      98           2 :         let cmpTempMan = Engine.QueryInterface(SYSTEM_ENTITY, IID_TemplateManager);
      99           2 :         let template = cmpTempMan.GetTemplate(this.upgrading);
     100             : 
     101             :         let categoryTo;
     102           2 :         if (template.TrainingRestrictions)
     103           0 :                 categoryTo = template.TrainingRestrictions.Category;
     104           2 :         else if (template.BuildRestrictions)
     105           0 :                 categoryTo = template.BuildRestrictions.Category;
     106             : 
     107           2 :         if (!categoryTo)
     108           2 :                 return;
     109             : 
     110             :         let categoryFrom;
     111           0 :         let cmpTrainingRestrictions = Engine.QueryInterface(this.entity, IID_TrainingRestrictions);
     112           0 :         let cmpBuildRestrictions = Engine.QueryInterface(this.entity, IID_BuildRestrictions);
     113           0 :         if (cmpTrainingRestrictions)
     114           0 :                 categoryFrom = cmpTrainingRestrictions.GetCategory();
     115           0 :         else if (cmpBuildRestrictions)
     116           0 :                 categoryFrom = cmpBuildRestrictions.GetCategory();
     117             : 
     118           0 :         if (categoryTo == categoryFrom)
     119           0 :                 return;
     120             : 
     121           0 :         let cmpEntityLimits = QueryPlayerIDInterface(this.owner, IID_EntityLimits);
     122           0 :         if (cmpEntityLimits)
     123           0 :                 cmpEntityLimits.ChangeCount(categoryTo, amount);
     124             : };
     125             : 
     126           1 : Upgrade.prototype.CanUpgradeTo = function(template)
     127             : {
     128           0 :         return this.upgradeTemplates[template] !== undefined;
     129             : };
     130             : 
     131           1 : Upgrade.prototype.GetUpgrades = function()
     132             : {
     133           3 :         let ret = [];
     134             : 
     135           3 :         for (const option in this.upgradeTemplates)
     136             :         {
     137           3 :                 const choice = this.template[this.upgradeTemplates[option]];
     138             : 
     139           3 :                 let cost = {};
     140           3 :                 if (choice.Cost)
     141           3 :                         cost = this.GetResourceCosts(option);
     142           3 :                 if (choice.Time)
     143           3 :                         cost.time = this.GetUpgradeTime(option);
     144             : 
     145           3 :                 let hasCost = choice.Cost || choice.Time;
     146           3 :                 ret.push({
     147             :                         "entity": option,
     148             :                         "icon": choice.Icon || undefined,
     149             :                         "cost": hasCost ? cost : undefined,
     150             :                         "tooltip": choice.Tooltip || undefined,
     151             :                         "requirements": this.GetRequirements(option),
     152             :                 });
     153             :         }
     154             : 
     155           3 :         return ret;
     156             : };
     157             : 
     158           1 : Upgrade.prototype.CancelTimer = function()
     159             : {
     160           1 :         if (!this.timer)
     161           0 :                 return;
     162             : 
     163           1 :         let cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
     164           1 :         cmpTimer.CancelTimer(this.timer);
     165           1 :         delete this.timer;
     166             : };
     167             : 
     168           1 : Upgrade.prototype.IsUpgrading = function()
     169             : {
     170           9 :         return !!this.upgrading;
     171             : };
     172             : 
     173           1 : Upgrade.prototype.GetUpgradingTo = function()
     174             : {
     175           1 :         return this.upgrading;
     176             : };
     177             : 
     178           1 : Upgrade.prototype.WillCheckPlacementRestrictions = function(template)
     179             : {
     180           0 :         if (!this.upgradeTemplates[template])
     181           0 :                 return undefined;
     182             : 
     183             :         // is undefined by default so use X in Y
     184           0 :         return "CheckPlacementRestrictions" in this.template[this.upgradeTemplates[template]];
     185             : };
     186             : 
     187           1 : Upgrade.prototype.GetRequirements = function(templateArg)
     188             : {
     189           3 :         let choice = this.upgradeTemplates[templateArg] || templateArg;
     190             : 
     191           3 :         if (this.template[choice].Requirements)
     192           0 :                 return this.template[choice].Requirements;
     193             : 
     194           3 :         if (!("Requirements" in this.template[choice]))
     195           3 :                 return undefined;
     196             : 
     197           0 :         let cmpTemplateManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_TemplateManager);
     198           0 :         let cmpIdentity = Engine.QueryInterface(this.entity, IID_Identity);
     199             : 
     200           0 :         let entType = this.template[choice].Entity;
     201           0 :         if (cmpIdentity)
     202           0 :                 entType = entType.replace(/\{civ\}/g, cmpIdentity.GetCiv());
     203             : 
     204           0 :         let template = cmpTemplateManager.GetTemplate(entType);
     205           0 :         return template.Identity.Requirements || undefined;
     206             : };
     207             : 
     208           1 : Upgrade.prototype.GetResourceCosts = function(template)
     209             : {
     210           4 :         if (!this.upgradeTemplates[template])
     211           0 :                 return undefined;
     212             : 
     213           4 :         if (this.IsUpgrading() && template == this.GetUpgradingTo())
     214           1 :                 return clone(this.expendedResources);
     215             : 
     216           3 :         let choice = this.upgradeTemplates[template];
     217           3 :         if (!this.template[choice].Cost)
     218           0 :                 return {};
     219             : 
     220           3 :         let costs = {};
     221           3 :         for (let r in this.template[choice].Cost)
     222           6 :                 costs[r] = ApplyValueModificationsToEntity("Upgrade/Cost/"+r, +this.template[choice].Cost[r], this.entity);
     223             : 
     224           3 :         return costs;
     225             : };
     226             : 
     227           1 : Upgrade.prototype.Upgrade = function(template)
     228             : {
     229           1 :         if (this.IsUpgrading() || !this.upgradeTemplates[template])
     230           0 :                 return false;
     231             : 
     232           1 :         let cmpPlayer = QueryOwnerInterface(this.entity, IID_Player);
     233           1 :         if (!cmpPlayer)
     234           0 :                 return false;
     235             : 
     236           1 :         let cmpProductionQueue = Engine.QueryInterface(this.entity, IID_ProductionQueue);
     237           1 :         if (cmpProductionQueue && cmpProductionQueue.HasQueuedProduction())
     238             :         {
     239           0 :                 let cmpGUIInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface);
     240           0 :                 cmpGUIInterface.PushNotification({
     241             :                         "players": [cmpPlayer.GetPlayerID()],
     242             :                         "message": markForTranslation("Entity is producing. Cannot start upgrading."),
     243             :                         "translateMessage": true
     244             :                 });
     245           0 :                 return false;
     246             :         }
     247             : 
     248           1 :         this.expendedResources = this.GetResourceCosts(template);
     249           1 :         if (!cmpPlayer || !cmpPlayer.TrySubtractResources(this.expendedResources))
     250             :         {
     251           0 :                 this.expendedResources = {};
     252           0 :                 return false;
     253             :         }
     254             : 
     255           1 :         this.upgrading = template;
     256           1 :         this.SetUpgradeAnimationVariant();
     257             : 
     258             :         // Prevent cheating
     259           1 :         this.ChangeUpgradedEntityCount(1);
     260             : 
     261           1 :         if (this.GetUpgradeTime(template) !== 0)
     262             :         {
     263           1 :                 let cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
     264           1 :                 this.timer = cmpTimer.SetInterval(this.entity, IID_Upgrade, "UpgradeProgress", 0, UPGRADING_PROGRESS_INTERVAL, { "upgrading": template });
     265             :         }
     266             :         else
     267           0 :                 this.UpgradeProgress();
     268             : 
     269           1 :         return true;
     270             : };
     271             : 
     272           1 : Upgrade.prototype.CancelUpgrade = function(owner)
     273             : {
     274           2 :         if (!this.IsUpgrading())
     275           1 :                 return;
     276             : 
     277           1 :         let cmpPlayer = QueryPlayerIDInterface(owner, IID_Player);
     278           1 :         if (cmpPlayer)
     279           1 :                 cmpPlayer.AddResources(this.expendedResources);
     280             : 
     281           1 :         this.expendedResources = {};
     282           1 :         this.ChangeUpgradedEntityCount(-1);
     283             : 
     284             :         // Do not update visual actor if the animation didn't change.
     285           1 :         let choice = this.upgradeTemplates[this.upgrading];
     286           1 :         if (choice && this.template[choice].Variant)
     287             :         {
     288           0 :                 let cmpVisual = Engine.QueryInterface(this.entity, IID_Visual);
     289           0 :                 if (cmpVisual)
     290           0 :                         cmpVisual.SelectAnimation("idle", false, 1.0);
     291             :         }
     292             : 
     293           1 :         delete this.upgrading;
     294           1 :         this.CancelTimer();
     295           1 :         this.SetElapsedTime(0);
     296             : };
     297             : 
     298           1 : Upgrade.prototype.GetUpgradeTime = function(templateArg)
     299             : {
     300           4 :         let template = this.upgrading || templateArg;
     301           4 :         let choice = this.upgradeTemplates[template];
     302             : 
     303           4 :         if (!choice)
     304           0 :                 return undefined;
     305             : 
     306           4 :         if (!this.template[choice].Time)
     307           0 :                 return 0;
     308             : 
     309           4 :         return ApplyValueModificationsToEntity("Upgrade/Time", +this.template[choice].Time, this.entity);
     310             : };
     311             : 
     312           1 : Upgrade.prototype.GetElapsedTime = function()
     313             : {
     314           0 :         return this.elapsedTime;
     315             : };
     316             : 
     317           1 : Upgrade.prototype.GetProgress = function()
     318             : {
     319           0 :         if (!this.IsUpgrading())
     320           0 :                 return undefined;
     321           0 :         return this.GetUpgradeTime() == 0 ? 1 : Math.min(this.elapsedTime / 1000.0 / this.GetUpgradeTime(), 1.0);
     322             : };
     323             : 
     324           1 : Upgrade.prototype.SetElapsedTime = function(time)
     325             : {
     326           1 :         this.elapsedTime = time;
     327           1 :         Engine.PostMessage(this.entity, MT_UpgradeProgressUpdate, null);
     328             : };
     329             : 
     330           1 : Upgrade.prototype.SetUpgradeAnimationVariant = function()
     331             : {
     332           1 :         let choice = this.upgradeTemplates[this.upgrading];
     333             : 
     334           1 :         if (!choice || !this.template[choice].Variant)
     335           1 :                 return;
     336             : 
     337           0 :         let cmpVisual = Engine.QueryInterface(this.entity, IID_Visual);
     338           0 :         if (!cmpVisual)
     339           0 :                 return;
     340             : 
     341           0 :         cmpVisual.SelectAnimation(this.template[choice].Variant, false, 1.0);
     342             : };
     343             : 
     344           1 : Upgrade.prototype.UpgradeProgress = function(data, lateness)
     345             : {
     346           0 :         if (this.elapsedTime/1000.0 < this.GetUpgradeTime())
     347             :         {
     348           0 :                 this.SetElapsedTime(this.GetElapsedTime() + UPGRADING_PROGRESS_INTERVAL + lateness);
     349           0 :                 return;
     350             :         }
     351             : 
     352           0 :         this.CancelTimer();
     353             : 
     354           0 :         this.completed = true;
     355           0 :         this.ChangeUpgradedEntityCount(-1);
     356           0 :         this.expendedResources = {};
     357             : 
     358           0 :         let newEntity = ChangeEntityTemplate(this.entity, this.upgrading);
     359             : 
     360           0 :         if (newEntity)
     361           0 :                 PlaySound("upgraded", newEntity);
     362             : };
     363             : 
     364           1 : Engine.RegisterComponentType(IID_Upgrade, "Upgrade", Upgrade);

Generated by: LCOV version 1.14