Line data Source code
1 : function Garrisonable() {} 2 : 3 3 : Garrisonable.prototype.Schema = 4 : "<a:help>Controls the garrisonability of an entity.</a:help>" + 5 : "<a:example>" + 6 : "<Size>10</Size>" + 7 : "</a:example>" + 8 : "<element name='Size' a:help='Number of garrison slots the entity occupies.'>" + 9 : "<data type='nonNegativeInteger'/>" + 10 : "</element>"; 11 : 12 3 : Garrisonable.prototype.Init = function() 13 : { 14 : }; 15 : 16 : /** 17 : * @param {string} type - Unused. 18 : * @param {number} target - The entity ID of the target to check. 19 : * @return {Object} - Min and max ranges this entity needs to be in in order to garrison the target. 20 : */ 21 3 : Garrisonable.prototype.GetRange = function(type, target) 22 : { 23 0 : let cmpGarrisonHolder = Engine.QueryInterface(target, IID_GarrisonHolder); 24 0 : return cmpGarrisonHolder ? cmpGarrisonHolder.LoadingRange() : { "min": 0, "max": 1 }; 25 : }; 26 : 27 : /** 28 : * @return {number} - The number of slots this unit takes in a garrisonHolder. 29 : */ 30 3 : Garrisonable.prototype.UnitSize = function() 31 : { 32 28 : return ApplyValueModificationsToEntity("Garrisonable/Size", +this.template.Size, this.entity); 33 : }; 34 : 35 : /** 36 : * Calculates the number of slots this unit takes in a garrisonHolder by 37 : * adding the number of garrisoned slots to the equation. 38 : * 39 : * @return {number} - The number of slots this unit and its garrison takes in a garrisonHolder. 40 : */ 41 3 : Garrisonable.prototype.TotalSize = function() 42 : { 43 26 : let size = this.UnitSize(); 44 26 : let cmpGarrisonHolder = Engine.QueryInterface(this.entity, IID_GarrisonHolder); 45 26 : if (cmpGarrisonHolder) 46 1 : size += cmpGarrisonHolder.OccupiedSlots(); 47 26 : return size; 48 : }; 49 : 50 : /** 51 : * @return {number} - The entity ID of the entity this entity is garrisoned in. 52 : */ 53 3 : Garrisonable.prototype.HolderID = function() 54 : { 55 5 : return this.holder || INVALID_ENTITY; 56 : }; 57 : 58 : /** 59 : * @return {boolean} - Whether we're garrisoned. 60 : */ 61 3 : Garrisonable.prototype.IsGarrisoned = function() 62 : { 63 0 : return !!this.holder; 64 : }; 65 : 66 : /** 67 : * @param {number} target - The entity ID to check. 68 : * @return {boolean} - Whether we can garrison. 69 : */ 70 3 : Garrisonable.prototype.CanGarrison = function(target) 71 : { 72 11 : if (this.holder) 73 2 : return false; 74 : 75 9 : let cmpGarrisonHolder = Engine.QueryInterface(target, IID_GarrisonHolder); 76 9 : return cmpGarrisonHolder && cmpGarrisonHolder.IsAllowedToGarrison(this.entity); 77 : }; 78 : 79 : /** 80 : * @param {number} target - The entity ID of the entity this entity is being garrisoned in. 81 : * @return {boolean} - Whether garrisoning succeeded. 82 : */ 83 3 : Garrisonable.prototype.Garrison = function(target) 84 : { 85 11 : if (!this.CanGarrison(target)) 86 2 : return false; 87 : 88 9 : let cmpGarrisonHolder = Engine.QueryInterface(target, IID_GarrisonHolder); 89 9 : if (!cmpGarrisonHolder || !cmpGarrisonHolder.Garrison(this.entity)) 90 0 : return false; 91 : 92 9 : this.holder = target; 93 : 94 9 : let cmpUnitAI = Engine.QueryInterface(this.entity, IID_UnitAI); 95 9 : if (cmpUnitAI) 96 0 : cmpUnitAI.SetGarrisoned(); 97 : 98 9 : let cmpPosition = Engine.QueryInterface(this.entity, IID_Position); 99 9 : if (cmpPosition) 100 6 : cmpPosition.MoveOutOfWorld(); 101 : 102 9 : Engine.PostMessage(this.entity, MT_GarrisonedStateChanged, { 103 : "oldHolder": INVALID_ENTITY, 104 : "holderID": target 105 : }); 106 : 107 9 : return true; 108 : }; 109 : 110 : /** 111 : * @param {boolean} forced - Optionally whether the spawning is forced. 112 : * @return {boolean} - Whether the ungarrisoning succeeded. 113 : */ 114 3 : Garrisonable.prototype.UnGarrison = function(forced = false) 115 : { 116 7 : if (!this.holder) 117 0 : return true; 118 : 119 7 : let pos = PositionHelper.GetSpawnPosition(this.holder, this.entity, forced); 120 7 : if (!pos) 121 0 : return false; 122 : 123 7 : let cmpGarrisonHolder = Engine.QueryInterface(this.holder, IID_GarrisonHolder); 124 7 : if (!cmpGarrisonHolder || !cmpGarrisonHolder.Eject(this.entity, forced)) 125 0 : return false; 126 : 127 7 : let cmpPosition = Engine.QueryInterface(this.entity, IID_Position); 128 7 : if (cmpPosition) 129 : { 130 5 : cmpPosition.JumpTo(pos.x, pos.z); 131 5 : cmpPosition.SetHeightOffset(0); 132 : } 133 : 134 7 : let cmpHolderPosition = Engine.QueryInterface(this.holder, IID_Position); 135 7 : if (cmpHolderPosition) 136 0 : cmpPosition.SetYRotation(cmpHolderPosition.GetPosition().horizAngleTo(pos)); 137 : 138 7 : let cmpUnitAI = Engine.QueryInterface(this.entity, IID_UnitAI); 139 7 : if (cmpUnitAI) 140 : { 141 0 : cmpUnitAI.Ungarrison(); 142 0 : cmpUnitAI.UnsetGarrisoned(); 143 : } 144 : 145 7 : Engine.PostMessage(this.entity, MT_GarrisonedStateChanged, { 146 : "oldHolder": this.holder, 147 : "holderID": INVALID_ENTITY 148 : }); 149 : 150 7 : let cmpRallyPoint = Engine.QueryInterface(this.holder, IID_RallyPoint); 151 : 152 : // Need to delete this before ordering to a rally 153 : // point else we may not garrison another entity. 154 7 : delete this.holder; 155 : 156 7 : if (cmpRallyPoint) 157 0 : cmpRallyPoint.OrderToRallyPoint(this.entity, ["garrison"]); 158 : 159 7 : return true; 160 : }; 161 : 162 3 : Garrisonable.prototype.OnEntityRenamed = function(msg) 163 : { 164 2 : if (!this.holder) 165 0 : return; 166 : 167 2 : let holder = this.holder; 168 2 : this.UnGarrison(true, true); 169 2 : let cmpGarrisonable = Engine.QueryInterface(msg.newentity, IID_Garrisonable); 170 2 : if (cmpGarrisonable) 171 1 : cmpGarrisonable.Garrison(holder, true); 172 : }; 173 : 174 3 : Engine.RegisterComponentType(IID_Garrisonable, "Garrisonable", Garrisonable);