LCOV - code coverage report
Current view: top level - simulation/components - Builder.js (source / functions) Hit Total Coverage
Test: lcov.info Lines: 79 95 83.2 %
Date: 2023-04-02 12:52:40 Functions: 11 13 84.6 %

          Line data    Source code
       1             : function Builder() {}
       2             : 
       3           1 : Builder.prototype.Schema =
       4             :         "<a:help>Allows the unit to construct and repair buildings.</a:help>" +
       5             :         "<a:example>" +
       6             :                 "<Rate>1.0</Rate>" +
       7             :                 "<Entities datatype='tokens'>" +
       8             :                         "\n    structures/{civ}/barracks\n    structures/{native}/civil_centre\n    structures/pers/apadana\n  " +
       9             :                 "</Entities>" +
      10             :         "</a:example>" +
      11             :         "<element name='Rate' a:help='Construction speed multiplier (1.0 is normal speed, higher values are faster).'>" +
      12             :                 "<ref name='positiveDecimal'/>" +
      13             :         "</element>" +
      14             :         "<element name='Entities' a:help='Space-separated list of entity template names that this unit can build. The special string \"{civ}\" will be automatically replaced by the civ code of the unit&apos;s owner, while the string \"{native}\" will be automatically replaced by the unit&apos;s civ code. This element can also be empty, in which case no new foundations may be placed by the unit, but they can still repair existing buildings.'>" +
      15             :                 "<attribute name='datatype'>" +
      16             :                         "<value>tokens</value>" +
      17             :                 "</attribute>" +
      18             :                 "<text/>" +
      19             :         "</element>";
      20             : 
      21             : /*
      22             :  * Build interval and repeat time, in ms.
      23             :  */
      24           1 : Builder.prototype.BUILD_INTERVAL = 1000;
      25             : 
      26           1 : Builder.prototype.Init = function()
      27             : {
      28             : };
      29             : 
      30           1 : Builder.prototype.GetEntitiesList = function()
      31             : {
      32           6 :         let string = this.template.Entities._string;
      33           6 :         if (!string)
      34           0 :                 return [];
      35             : 
      36           6 :         let cmpPlayer = QueryOwnerInterface(this.entity);
      37           6 :         if (!cmpPlayer)
      38           1 :                 return [];
      39             : 
      40           5 :         string = ApplyValueModificationsToEntity("Builder/Entities/_string", string, this.entity);
      41             : 
      42           5 :         let cmpIdentity = Engine.QueryInterface(this.entity, IID_Identity);
      43           5 :         if (cmpIdentity)
      44           5 :                 string = string.replace(/\{native\}/g, cmpIdentity.GetCiv());
      45             : 
      46           5 :         const entities = string.replace(/\{civ\}/g, QueryOwnerInterface(this.entity, IID_Identity).GetCiv()).split(/\s+/);
      47             : 
      48           5 :         let disabledTemplates = cmpPlayer.GetDisabledTemplates();
      49             : 
      50           5 :         let cmpTemplateManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_TemplateManager);
      51             : 
      52          15 :         return entities.filter(ent => !disabledTemplates[ent] && cmpTemplateManager.TemplateExists(ent));
      53             : };
      54             : 
      55           1 : Builder.prototype.GetRange = function()
      56             : {
      57           8 :         let max = 2;
      58           8 :         let cmpObstruction = Engine.QueryInterface(this.entity, IID_Obstruction);
      59           8 :         if (cmpObstruction)
      60           7 :                 max += cmpObstruction.GetSize();
      61             : 
      62           8 :         return { "max": max, "min": 0 };
      63             : };
      64             : 
      65           1 : Builder.prototype.GetRate = function()
      66             : {
      67           8 :         return ApplyValueModificationsToEntity("Builder/Rate", +this.template.Rate, this.entity);
      68             : };
      69             : 
      70             : /**
      71             :  * @param {number} target - The target to check.
      72             :  * @return {boolean} - Whether we can build/repair the given target.
      73             :  */
      74           1 : Builder.prototype.CanRepair = function(target)
      75             : {
      76          10 :         let cmpFoundation = QueryMiragedInterface(target, IID_Foundation);
      77          10 :         let cmpRepairable = QueryMiragedInterface(target, IID_Repairable);
      78          10 :         if (!cmpFoundation && (!cmpRepairable || !cmpRepairable.IsRepairable()))
      79           1 :                 return false;
      80             : 
      81           9 :         let cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership);
      82           9 :         return cmpOwnership && IsOwnedByAllyOfPlayer(cmpOwnership.GetOwner(), target);
      83             : };
      84             : 
      85             : /**
      86             :  * @param {number} target - The target to repair.
      87             :  * @param {number} callerIID - The IID to notify on specific events.
      88             :  * @return {boolean} - Whether we started repairing.
      89             :  */
      90           1 : Builder.prototype.StartRepairing = function(target, callerIID)
      91             : {
      92           3 :         if (this.target)
      93           0 :                 this.StopRepairing();
      94             : 
      95           3 :         if (!this.CanRepair(target))
      96           0 :                 return false;
      97             : 
      98           3 :         let cmpBuilderList = QueryBuilderListInterface(target);
      99           3 :         if (cmpBuilderList)
     100           3 :                 cmpBuilderList.AddBuilder(this.entity);
     101             : 
     102           3 :         let cmpVisual = Engine.QueryInterface(this.entity, IID_Visual);
     103           3 :         if (cmpVisual)
     104           0 :                 cmpVisual.SelectAnimation("build", false, 1.0);
     105             : 
     106           3 :         this.target = target;
     107           3 :         this.callerIID = callerIID;
     108             : 
     109           3 :         let cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
     110           3 :         this.timer = cmpTimer.SetInterval(this.entity, IID_Builder, "PerformBuilding", this.BUILD_INTERVAL, this.BUILD_INTERVAL, null);
     111             : 
     112           3 :         return true;
     113             : };
     114             : 
     115             : /**
     116             :  * @param {string} reason - The reason why we stopped repairing.
     117             :  */
     118           1 : Builder.prototype.StopRepairing = function(reason)
     119             : {
     120           1 :         if (!this.target)
     121           0 :                 return;
     122             : 
     123           1 :         let cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
     124           1 :         cmpTimer.CancelTimer(this.timer);
     125           1 :         delete this.timer;
     126             : 
     127           1 :         let cmpBuilderList = QueryBuilderListInterface(this.target);
     128           1 :         if (cmpBuilderList)
     129           1 :                 cmpBuilderList.RemoveBuilder(this.entity);
     130             : 
     131           1 :         delete this.target;
     132             : 
     133           1 :         let cmpVisual = Engine.QueryInterface(this.entity, IID_Visual);
     134           1 :         if (cmpVisual)
     135           0 :                 cmpVisual.SelectAnimation("idle", false, 1.0);
     136             : 
     137             :         // The callerIID component may start again,
     138             :         // replacing the callerIID, hence save that.
     139           1 :         let callerIID = this.callerIID;
     140           1 :         delete this.callerIID;
     141             : 
     142           1 :         if (reason && callerIID)
     143             :         {
     144           0 :                 let component = Engine.QueryInterface(this.entity, callerIID);
     145           0 :                 if (component)
     146           0 :                         component.ProcessMessage(reason, null);
     147             :         }
     148             : };
     149             : 
     150             : /**
     151             :  * Repair our target entity.
     152             :  * @params - data and lateness are unused.
     153             :  */
     154           1 : Builder.prototype.PerformBuilding = function(data, lateness)
     155             : {
     156           7 :         if (!this.CanRepair(this.target))
     157             :         {
     158           1 :                 this.StopRepairing("TargetInvalidated");
     159           1 :                 return;
     160             :         }
     161             : 
     162           6 :         if (!this.IsTargetInRange(this.target))
     163             :         {
     164           0 :                 this.StopRepairing("OutOfRange");
     165           0 :                 return;
     166             :         }
     167             : 
     168             :         // ToDo: Enable entities to keep facing a target.
     169           6 :         Engine.QueryInterface(this.entity, IID_UnitAI)?.FaceTowardsTarget(this.target);
     170             : 
     171           6 :         let cmpFoundation = Engine.QueryInterface(this.target, IID_Foundation);
     172           6 :         if (cmpFoundation)
     173             :         {
     174           3 :                 cmpFoundation.Build(this.entity, this.GetRate());
     175           3 :                 return;
     176             :         }
     177             : 
     178           3 :         let cmpRepairable = Engine.QueryInterface(this.target, IID_Repairable);
     179           3 :         if (cmpRepairable)
     180             :         {
     181           3 :                 cmpRepairable.Repair(this.entity, this.GetRate());
     182           3 :                 return;
     183             :         }
     184             : };
     185             : 
     186             : /**
     187             :  * @param {number} - The entity ID of the target to check.
     188             :  * @return {boolean} - Whether this entity is in range of its target.
     189             :  */
     190           1 : Builder.prototype.IsTargetInRange = function(target)
     191             : {
     192           6 :         let range = this.GetRange();
     193           6 :         let cmpObstructionManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_ObstructionManager);
     194           6 :         return cmpObstructionManager.IsInTargetRange(this.entity, target, range.min, range.max, false);
     195             : };
     196             : 
     197           1 : Builder.prototype.OnValueModification = function(msg)
     198             : {
     199           0 :         if (msg.component != "Builder" || !msg.valueNames.some(name => name.endsWith('_string')))
     200           0 :                 return;
     201             : 
     202             :         // Token changes may require selection updates.
     203           0 :         let cmpPlayer = QueryOwnerInterface(this.entity, IID_Player);
     204           0 :         if (cmpPlayer)
     205           0 :                 Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface).SetSelectionDirty(cmpPlayer.GetPlayerID());
     206             : };
     207             : 
     208           1 : Engine.RegisterComponentType(IID_Builder, "Builder", Builder);

Generated by: LCOV version 1.14