Line data Source code
1 : function Turretable() {} 2 : 3 1 : Turretable.prototype.Schema = 4 : "<empty/>"; 5 : 6 1 : Turretable.prototype.Init = function() 7 : { 8 : }; 9 : 10 : /** 11 : * @param {string} type - Unused. 12 : * @param {number} target - The entity ID of the target to check. 13 : * @return {Object} - The range this entity needs to be in in order to occupy a turret point on the target. 14 : */ 15 1 : Turretable.prototype.GetRange = function(type, target) 16 : { 17 0 : let cmpTurretHolder = Engine.QueryInterface(target, IID_TurretHolder); 18 0 : return cmpTurretHolder ? cmpTurretHolder.LoadingRange() : { "min": 0, "max": 1 }; 19 : }; 20 : 21 : /** 22 : * @return {number} - The entity ID of the entity this entity is turreted on. 23 : */ 24 1 : Turretable.prototype.HolderID = function() 25 : { 26 0 : return this.holder || INVALID_ENTITY; 27 : }; 28 : 29 : /** 30 : * @return {boolean} - Whether we're turreted. 31 : */ 32 1 : Turretable.prototype.IsTurreted = function() 33 : { 34 0 : return !!this.holder; 35 : }; 36 : 37 : /** 38 : * @return {boolean} - Whether we can leave the turret point. 39 : */ 40 1 : Turretable.prototype.IsEjectable = function() 41 : { 42 0 : return this.ejectable; 43 : }; 44 : 45 : /** 46 : * @param {number} target - The entity ID to check. 47 : * @return {boolean} - Whether we can occupy the turret. 48 : */ 49 1 : Turretable.prototype.CanOccupy = function(target) 50 : { 51 6 : if (this.holder) 52 0 : return false; 53 : 54 6 : let cmpTurretHolder = Engine.QueryInterface(target, IID_TurretHolder); 55 6 : return cmpTurretHolder && cmpTurretHolder.CanOccupy(this.entity); 56 : }; 57 : 58 : /** 59 : * @param {number} target - The entity ID of the entity this entity is being turreted on. 60 : * @param {string} turretPointName - Optionally the turret point name to occupy. 61 : * @param {boolean} ejectable - Whether we can leave this turret point (e.g. false for a tank turret). 62 : * 63 : * @return {boolean} - Whether occupying succeeded. 64 : */ 65 1 : Turretable.prototype.OccupyTurret = function(target, turretPointName = "", ejectable = true) 66 : { 67 6 : if (!this.CanOccupy(target)) 68 0 : return false; 69 : 70 6 : let cmpTurretHolder = Engine.QueryInterface(target, IID_TurretHolder); 71 6 : if (!cmpTurretHolder || !cmpTurretHolder.OccupyNamedTurretPoint(this.entity, turretPointName)) 72 0 : return false; 73 : 74 6 : this.holder = target; 75 6 : this.ejectable = ejectable; 76 : 77 6 : let cmpUnitAI = Engine.QueryInterface(this.entity, IID_UnitAI); 78 6 : if (cmpUnitAI) 79 0 : cmpUnitAI.SetTurretStance(); 80 : 81 6 : let cmpUnitMotion = Engine.QueryInterface(this.entity, IID_UnitMotion); 82 6 : if (cmpUnitMotion) 83 0 : cmpUnitMotion.SetFacePointAfterMove(false); 84 : 85 : // Remove the unit's obstruction to avoid interfering with pathing. 86 6 : let cmpObstruction = Engine.QueryInterface(this.entity, IID_Obstruction); 87 6 : if (cmpObstruction) 88 0 : cmpObstruction.SetActive(false); 89 : 90 6 : Engine.PostMessage(this.entity, MT_TurretedStateChanged, { 91 : "oldHolder": INVALID_ENTITY, 92 : "holderID": target 93 : }); 94 : 95 6 : return true; 96 : }; 97 : 98 : /** 99 : * @param {boolean} forced - Optionally whether the leaving the turret is forced. 100 : * @return {boolean} - Whether leaving the turret succeeded. 101 : */ 102 1 : Turretable.prototype.LeaveTurret = function(forced = false) 103 : { 104 4 : if (!this.holder) 105 0 : return true; 106 : 107 4 : if (!this.ejectable && !forced) 108 0 : return false; 109 : 110 4 : let pos = PositionHelper.GetSpawnPosition(this.holder, this.entity, forced); 111 4 : if (!pos) 112 0 : return false; 113 : 114 4 : let cmpTurretHolder = Engine.QueryInterface(this.holder, IID_TurretHolder); 115 4 : if (!cmpTurretHolder || !cmpTurretHolder.LeaveTurretPoint(this.entity, forced)) 116 0 : return false; 117 : 118 4 : let cmpUnitMotionEntity = Engine.QueryInterface(this.entity, IID_UnitMotion); 119 4 : if (cmpUnitMotionEntity) 120 0 : cmpUnitMotionEntity.SetFacePointAfterMove(true); 121 : 122 4 : let cmpPosition = Engine.QueryInterface(this.entity, IID_Position); 123 4 : if (cmpPosition) 124 : { 125 4 : cmpPosition.SetTurretParent(INVALID_ENTITY, new Vector3D()); 126 4 : cmpPosition.JumpTo(pos.x, pos.z); 127 4 : cmpPosition.SetHeightOffset(0); 128 : 129 4 : let cmpHolderPosition = Engine.QueryInterface(this.holder, IID_Position); 130 4 : if (cmpHolderPosition) 131 4 : cmpPosition.SetYRotation(cmpHolderPosition.GetPosition().horizAngleTo(pos)); 132 : } 133 : 134 4 : let cmpUnitAI = Engine.QueryInterface(this.entity, IID_UnitAI); 135 4 : if (cmpUnitAI) 136 : { 137 0 : cmpUnitAI.Ungarrison(); 138 0 : cmpUnitAI.ResetTurretStance(); 139 : } 140 : 141 : // Reset the obstruction flags to template defaults. 142 4 : let cmpObstruction = Engine.QueryInterface(this.entity, IID_Obstruction); 143 4 : if (cmpObstruction) 144 0 : cmpObstruction.SetActive(true); 145 : 146 4 : Engine.PostMessage(this.entity, MT_TurretedStateChanged, { 147 : "oldHolder": this.holder, 148 : "holderID": INVALID_ENTITY 149 : }); 150 : 151 4 : let cmpRallyPoint = Engine.QueryInterface(this.holder, IID_RallyPoint); 152 : 153 : // Need to delete this before ordering to a rally 154 : // point else we may not occupy another turret point. 155 4 : delete this.holder; 156 : 157 4 : if (cmpRallyPoint) 158 0 : cmpRallyPoint.OrderToRallyPoint(this.entity, ["occupy-turret"]); 159 : 160 4 : delete this.ejectable; 161 4 : return true; 162 : }; 163 : 164 1 : Turretable.prototype.OnEntityRenamed = function(msg) 165 : { 166 1 : if (!this.holder) 167 0 : return; 168 : 169 1 : let cmpTurretHolder = Engine.QueryInterface(this.holder, IID_TurretHolder); 170 1 : if (!cmpTurretHolder) 171 0 : return; 172 : 173 1 : let holder = this.holder; 174 1 : let currentPoint = cmpTurretHolder.GetOccupiedTurretPointName(this.entity); 175 1 : this.LeaveTurret(true); 176 1 : let cmpTurretableNew = Engine.QueryInterface(msg.newentity, IID_Turretable); 177 1 : if (cmpTurretableNew) 178 1 : cmpTurretableNew.OccupyTurret(holder, currentPoint); 179 : }; 180 : 181 1 : Turretable.prototype.OnOwnershipChanged = function(msg) 182 : { 183 0 : if (!this.holder) 184 0 : return; 185 : 186 0 : if (msg.to == INVALID_PLAYER) 187 0 : this.LeaveTurret(true); 188 0 : else if (!IsOwnedByMutualAllyOfEntity(this.entity, this.holder)) 189 0 : this.LeaveTurret(); 190 : }; 191 : 192 1 : Engine.RegisterComponentType(IID_Turretable, "Turretable", Turretable);