Ticket #2577: turrets.diff
File turrets.diff, 16.9 KB (added by , 10 years ago) |
---|
-
binaries/data/mods/public/simulation/components/TurretHolder.js
1 function TurretHolder() {} 2 3 TurretHolder.prototype.Schema = 4 "<zeroOrMore>" + 5 "<element>" + 6 "<anyName/>" + 7 "<interleave>" + 8 "<optional>" + 9 "<element name='Template'>" + 10 "<text/>" + 11 "</element>" + 12 "</optional>" + 13 "<element name='Offset'>" + 14 "<interleave>" + 15 "<element name='X'>" + 16 "<data type='decimal'/>" + 17 "</element>" + 18 "<element name='Y'>" + 19 "<data type='decimal'/>" + 20 "</element>" + 21 "<element name='Z'>" + 22 "<data type='decimal'/>" + 23 "</element>" + 24 "</interleave>" + 25 "</element>" + 26 "</interleave>" + 27 "</element>" + 28 "</zeroOrMore>"; 29 30 TurretHolder.prototype.Init = function() 31 { 32 this.turrets = {}; 33 var cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer); 34 cmpTimer.SetTimeout(this.entity, IID_TurretHolder, "InitReal", 0, null); 35 36 }; 37 38 /** 39 * The real init function. But this should not be loaded in Atlas, 40 * unless a simulation is started. 41 */ 42 TurretHolder.prototype.InitReal = function(msg) 43 { 44 var cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership); 45 for (var positionCode in this.template) 46 { 47 if (!this.template[positionCode].Template) 48 continue; 49 var ent = Engine.AddEntity(this.template[positionCode].Template); 50 var cmpTurretOwnership = Engine.QueryInterface(ent, IID_Ownership); 51 cmpTurretOwnership.SetOwner(cmpOwnership.GetOwner()); 52 this.AddTurret(positionCode, ent); 53 } 54 }; 55 56 /** 57 * Bind an existing entity to a positionCode of this turretHolder 58 * Some components will be notified that this entity shouldn't move on its own anymore 59 */ 60 TurretHolder.prototype.AddTurret = function(positionCode, ent) 61 { 62 if (!this.template[positionCode]) 63 { 64 warn("TurretHolder.JS: entity assigned to unknown turret positionCode"); 65 return; 66 } 67 if (this.turrets[positionCode]) 68 { 69 warn("TurretHolder.JS: entity assigned to occupied turret positionCode"); 70 return; 71 } 72 73 var cmpPosition = Engine.QueryInterface(ent, IID_Position); 74 if (cmpPosition) 75 { 76 var offset = this.template[positionCode].Offset; 77 var pos = new Vector3D(+offset.X, +offset.Y, +offset.Z); 78 cmpPosition.SetTurretParent(this.entity, pos); 79 } 80 81 var cmpUnitAI = Engine.QueryInterface(ent, IID_UnitAI); 82 if (cmpUnitAI) 83 cmpUnitAI.SetTurret(true); 84 this.turrets[positionCode] = ent; 85 }; 86 87 /** 88 * Remove a turret from the turret holder 89 * This does not reset its position, nor does it kill the turret 90 * It just unbinds it from its turret holder 91 */ 92 TurretHolder.prototype.RemoveTurret = function(positionCode) 93 { 94 var ent = this.turrets[positionCode]; 95 if (!ent) 96 return; 97 var cmpPosition = Engine.QueryInterface(ent, IID_Position); 98 if (cmpPosition) 99 cmpPosition.SetTurretParent(INVALID_ENTITY, new Vector3D()); 100 var cmpUnitAI = Engine.QueryInterface(ent, IID_UnitAI); 101 if (cmpUnitAI) 102 cmpUnitAI.SetTurret(false); 103 delete this.turrets[positionCode]; 104 }; 105 106 TurretHolder.prototype.GetAllTurretPositions = function() 107 { 108 return Object.keys(this.template); 109 }; 110 111 TurretHolder.prototype.GetOccupiedTurretPositions = function() 112 { 113 return Object.keys(this.turrets); 114 }; 115 116 TurretHolder.prototype.GetFreeTurretPositions = function() 117 { 118 var r = []; 119 for (var positionCode in this.template) 120 if (!(positionCode in this.turrets)) 121 r.push(positionCode); 122 return r; 123 }; 124 125 TurretHolder.prototype.GetTurretOnPosition = function(positionCode) 126 { 127 return this.turrets[positionCode]; 128 }; 129 130 TurretHolder.prototype.OnOwnershipChanged = function(msg) 131 { 132 for each (var ent in this.turrets) 133 { 134 var cmpOwnership = Engine.QueryInterface(ent, IID_Ownership); 135 cmpOwnership.SetOwner(msg.to); 136 } 137 } 138 139 /** 140 * Also destroy all turrets 141 */ 142 TurretHolder.prototype.OnDestroy = function(msg) 143 { 144 for each (var ent in this.turrets) 145 Engine.DestroyEntity(ent); 146 } 147 148 Engine.RegisterComponentType(IID_TurretHolder, "TurretHolder", TurretHolder); -
binaries/data/mods/public/simulation/components/UnitAI.js
179 179 // Called when being told to walk as part of a formation 180 180 "Order.FormationWalk": function(msg) { 181 181 // Let players move captured domestic animals around 182 if (this.IsAnimal() && !this.IsDomestic() )182 if (this.IsAnimal() && !this.IsDomestic() || this.IsTurret()) 183 183 { 184 184 this.FinishOrder(); 185 185 return; … … 207 207 "Order.LeaveFoundation": function(msg) { 208 208 // If foundation is not ally of entity, or if entity is unpacked siege, 209 209 // ignore the order 210 if (!IsOwnedByAllyOfEntity(this.entity, msg.data.target) || this.IsPacking() || this.CanPack() )210 if (!IsOwnedByAllyOfEntity(this.entity, msg.data.target) || this.IsPacking() || this.CanPack() || this.IsTurret()) 211 211 { 212 212 this.FinishOrder(); 213 213 return; … … 252 252 253 253 "Order.Walk": function(msg) { 254 254 // Let players move captured domestic animals around 255 if (this.IsAnimal() && !this.IsDomestic() )255 if (this.IsAnimal() && !this.IsDomestic() || this.IsTurret()) 256 256 { 257 257 this.FinishOrder(); 258 258 return; … … 278 278 279 279 "Order.WalkAndFight": function(msg) { 280 280 // Let players move captured domestic animals around 281 if (this.IsAnimal() && !this.IsDomestic() )281 if (this.IsAnimal() && !this.IsDomestic() || this.IsTurret()) 282 282 { 283 283 this.FinishOrder(); 284 284 return; … … 305 305 306 306 "Order.WalkToTarget": function(msg) { 307 307 // Let players move captured domestic animals around 308 if (this.IsAnimal() && !this.IsDomestic() )308 if (this.IsAnimal() && !this.IsDomestic() || this.IsTurret()) 309 309 { 310 310 this.FinishOrder(); 311 311 return; … … 486 486 487 487 // If we can't reach the target, but are standing ground, then abandon this attack order. 488 488 // Unless we're hunting, that's a special case where we should continue attacking our target. 489 if (this.GetStance().respondStandGround && !this.order.data.force && !this.order.data.hunting )489 if (this.GetStance().respondStandGround && !this.order.data.force && !this.order.data.hunting || this.IsTurret()) 490 490 { 491 491 this.FinishOrder(); 492 492 return; … … 685 685 }, 686 686 687 687 "Order.Garrison": function(msg) { 688 if (this.IsTurret()) 689 { 690 this.FinishOrder(); 691 return; 692 } 688 693 // For packable units: 689 694 // 1. If packed, we can move to the garrison target. 690 695 // 2. If unpacked, we first need to pack, then follow case 1. … … 1242 1247 "Order.LeaveFoundation": function(msg) { 1243 1248 // If foundation is not ally of entity, or if entity is unpacked siege, 1244 1249 // ignore the order 1245 if (!IsOwnedByAllyOfEntity(this.entity, msg.data.target) || this.IsPacking() || this.CanPack() )1250 if (!IsOwnedByAllyOfEntity(this.entity, msg.data.target) || this.IsPacking() || this.CanPack() || this.IsTurret()) 1246 1251 { 1247 1252 this.FinishOrder(); 1248 1253 return; … … 3119 3124 this.lastHealed = undefined; 3120 3125 3121 3126 this.SetStance(this.template.DefaultStance); 3127 this.SetTurret(false); 3122 3128 }; 3123 3129 3130 /** 3131 * Set the flag to true to use this unit as a turret 3132 * This means no moving is allowed, only turning 3133 */ 3134 UnitAI.prototype.SetTurret = function(flag) 3135 { 3136 this.isTurret = flag; 3137 }; 3138 3139 UnitAI.prototype.IsTurret = function() 3140 { 3141 return this.isTurret; 3142 }; 3143 3124 3144 UnitAI.prototype.ReactsToAlert = function(level) 3125 3145 { 3126 3146 return this.template.AlertReactiveLevel <= level; … … 4152 4172 4153 4173 UnitAI.prototype.MoveToTargetRange = function(target, iid, type) 4154 4174 { 4155 if (!this.CheckTargetVisible(target) )4175 if (!this.CheckTargetVisible(target) || this.IsTurret()) 4156 4176 return false; 4157 4177 4158 4178 var cmpRanged = Engine.QueryInterface(this.entity, iid); … … 4583 4603 */ 4584 4604 UnitAI.prototype.ShouldChaseTargetedEntity = function(target, force) 4585 4605 { 4606 if (this.IsTurret()) 4607 return false; 4608 4586 4609 // TODO: use special stances instead? 4587 4610 var cmpPack = Engine.QueryInterface(this.entity, IID_Pack); 4588 4611 if (cmpPack) -
binaries/data/mods/public/simulation/components/interfaces/TurretHolder.js
1 Engine.RegisterInterface("TurretHolder"); 2 -
binaries/data/mods/public/simulation/templates/template_structure_civic_house.xml
69 69 <Radius>20</Radius> 70 70 <Weight>40000</Weight> 71 71 </TerritoryInfluence> 72 <TurretHolder> 73 <tree> 74 <Template>units/athen_infantry_archer_a</Template> 75 <Offset> 76 <X>5</X> 77 <Y>5</Y> 78 <Z>5</Z> 79 </Offset> 80 </tree> 81 </TurretHolder> 72 82 <Vision> 73 83 <Range>20</Range> 74 84 </Vision> -
source/simulation2/components/CCmpPosition.cpp
75 75 entity_pos_t m_YOffset, m_LastYOffset; 76 76 bool m_RelativeToGround; // whether m_YOffset is relative to terrain/water plane, or an absolute height 77 77 78 // when the entity is a turret, only m_RotY is used, and this is the rotation 79 // relative to the parent entity 78 80 entity_angle_t m_RotX, m_RotY, m_RotZ; 79 81 80 82 player_id_t m_Territory; 81 83 84 entity_id_t m_TurretParent; 85 CFixedVector3D m_TurretPosition; 86 std::set<entity_id_t> m_Turrets; 87 82 88 // not serialized: 83 89 float m_InterpolatedRotX, m_InterpolatedRotY, m_InterpolatedRotZ; 84 90 float m_LastInterpolatedRotX, m_LastInterpolatedRotZ; // not serialized … … 140 146 m_Territory = INVALID_PLAYER; 141 147 142 148 m_NeedInitialXZRotation = false; 149 m_TurretParent = INVALID_ENTITY; 150 m_TurretPosition = CFixedVector3D(); 143 151 } 144 152 145 153 virtual void Deinit() … … 217 225 UpdateXZRotation(); 218 226 } 219 227 228 virtual void UpdateTurretPosition() 229 { 230 if (m_TurretParent == INVALID_ENTITY) 231 return; 232 CmpPtr<ICmpPosition> cmpPosition(GetSimContext(), m_TurretParent); 233 if (!cmpPosition) 234 { 235 LOGERROR(L"Turret with parent without position component"); 236 return; 237 } 238 if (!cmpPosition->IsInWorld()) 239 MoveOutOfWorld(); 240 else 241 { 242 CFixedVector2D rotatedPosition = CFixedVector2D(m_TurretPosition.X, m_TurretPosition.Z); 243 rotatedPosition = rotatedPosition.Rotate(cmpPosition->GetRotation().Y); 244 CFixedVector2D rootPosition = cmpPosition->GetPosition2D(); 245 entity_pos_t x = rootPosition.X + rotatedPosition.X; 246 entity_pos_t z = rootPosition.Y + rotatedPosition.Y; 247 if (!m_InWorld || m_X != x || m_Z != z) 248 MoveTo(x, z); 249 entity_pos_t y = cmpPosition->GetHeightOffset() + m_TurretPosition.Y; 250 if (!m_InWorld || m_YOffset != y) 251 SetHeightOffset(y); 252 } 253 } 254 255 virtual std::set<entity_id_t>* GetTurrets() 256 { 257 return &m_Turrets; 258 } 259 260 virtual void SetTurretParent(entity_id_t id, CFixedVector3D offset) 261 { 262 if (m_TurretParent != INVALID_ENTITY) 263 { 264 CmpPtr<ICmpPosition> cmpPosition(GetSimContext(), m_TurretParent); 265 if (cmpPosition) 266 cmpPosition->GetTurrets()->erase(GetEntityId()); 267 } 268 269 m_TurretParent = id; 270 m_TurretPosition = offset; 271 272 if (m_TurretParent != INVALID_ENTITY) 273 { 274 CmpPtr<ICmpPosition> cmpPosition(GetSimContext(), m_TurretParent); 275 if (cmpPosition) 276 cmpPosition->GetTurrets()->insert(GetEntityId()); 277 } 278 UpdateTurretPosition(); 279 } 280 220 281 virtual bool IsInWorld() 221 282 { 222 283 return m_InWorld; … … 249 310 { 250 311 m_X = x; 251 312 m_Z = z; 252 m_RotY = ry;253 313 254 314 if (!m_InWorld) 255 315 { … … 259 319 m_LastYOffset = m_YOffset; 260 320 } 261 321 262 AdvertisePositionChanges(); 322 // TurnTo will advertise the position changes 323 TurnTo(ry); 263 324 } 264 325 265 326 virtual void JumpTo(entity_pos_t x, entity_pos_t z) … … 392 453 393 454 virtual void TurnTo(entity_angle_t y) 394 455 { 456 if (m_TurretParent != INVALID_ENTITY) 457 { 458 CmpPtr<ICmpPosition> cmpPosition(GetSimContext(), m_TurretParent); 459 if (cmpPosition) 460 y -= cmpPosition->GetRotation().Y; 461 } 395 462 m_RotY = y; 396 463 397 464 AdvertisePositionChanges(); … … 399 466 400 467 virtual void SetYRotation(entity_angle_t y) 401 468 { 469 if (m_TurretParent != INVALID_ENTITY) 470 { 471 CmpPtr<ICmpPosition> cmpPosition(GetSimContext(), m_TurretParent); 472 if (cmpPosition) 473 y -= cmpPosition->GetRotation().Y; 474 } 402 475 m_RotY = y; 403 476 m_InterpolatedRotY = m_RotY.ToFloat(); 404 477 … … 431 504 432 505 virtual CFixedVector3D GetRotation() 433 506 { 507 entity_angle_t y = m_RotY; 508 if (m_TurretParent != INVALID_ENTITY) 509 { 510 CmpPtr<ICmpPosition> cmpPosition(GetSimContext(), m_TurretParent); 511 if (cmpPosition) 512 y += cmpPosition->GetRotation().Y; 513 } 434 514 return CFixedVector3D(m_RotX, m_RotY, m_RotZ); 435 515 } 436 516 … … 461 541 462 542 virtual CMatrix3D GetInterpolatedTransform(float frameOffset, bool forceFloating) 463 543 { 544 if (m_TurretParent != INVALID_ENTITY) 545 { 546 CmpPtr<ICmpPosition> cmpPosition(GetSimContext(), m_TurretParent); 547 if (!cmpPosition) 548 { 549 LOGERROR(L"Turret with parent without position component"); 550 CMatrix3D m; 551 m.SetIdentity(); 552 return m; 553 } 554 if (!cmpPosition->IsInWorld()) 555 { 556 LOGERROR(L"CCmpPosition::GetInterpolatedTransform called on turret entity when IsInWorld is false"); 557 CMatrix3D m; 558 m.SetIdentity(); 559 return m; 560 } 561 else 562 { 563 CMatrix3D parentTransformMatrix = cmpPosition->GetInterpolatedTransform(frameOffset, forceFloating); 564 CMatrix3D ownTransformation = CMatrix3D(); 565 ownTransformation.SetYRotation(m_InterpolatedRotY); 566 ownTransformation.Translate(-m_TurretPosition.X.ToFloat(), m_TurretPosition.Y.ToFloat(), -m_TurretPosition.Z.ToFloat()); 567 return parentTransformMatrix * ownTransformation; 568 } 569 } 464 570 if (!m_InWorld) 465 571 { 466 572 LOGERROR(L"CCmpPosition::GetInterpolatedTransform called on entity when IsInWorld is false"); … … 548 654 } 549 655 case MT_TurnStart: 550 656 { 657 551 658 m_LastInterpolatedRotX = m_InterpolatedRotX; 552 659 m_LastInterpolatedRotZ = m_InterpolatedRotZ; 553 660 … … 592 699 private: 593 700 void AdvertisePositionChanges() 594 701 { 702 for (std::set<entity_id_t>::const_iterator it = m_Turrets.begin(); it != m_Turrets.end(); ++it) 703 { 704 CmpPtr<ICmpPosition> cmpPosition(GetSimContext(), *it); 705 if (cmpPosition) 706 cmpPosition->UpdateTurretPosition(); 707 } 595 708 if (m_InWorld) 596 709 { 597 710 CMessagePositionChanged msg(GetEntityId(), true, m_X, m_Z, m_RotY); -
source/simulation2/components/ICmpPosition.cpp
22 22 #include "simulation2/system/InterfaceScripted.h" 23 23 24 24 BEGIN_INTERFACE_WRAPPER(Position) 25 DEFINE_INTERFACE_METHOD_2("SetTurretParent", void, ICmpPosition, SetTurretParent, entity_id_t, CFixedVector3D) 25 26 DEFINE_INTERFACE_METHOD_0("IsInWorld", bool, ICmpPosition, IsInWorld) 26 27 DEFINE_INTERFACE_METHOD_0("MoveOutOfWorld", void, ICmpPosition, MoveOutOfWorld) 27 28 DEFINE_INTERFACE_METHOD_2("MoveTo", void, ICmpPosition, MoveTo, entity_pos_t, entity_pos_t) -
source/simulation2/components/ICmpPosition.h
59 59 { 60 60 public: 61 61 /** 62 * Set this as a turret of an other entity 63 */ 64 virtual void SetTurretParent(entity_id_t parent, CFixedVector3D offset) = 0; 65 66 /** 67 * Has to be called to update the simulation position of the turret 68 */ 69 virtual void UpdateTurretPosition() = 0; 70 71 /** 72 * Get the list of turrets to read or edit 73 */ 74 virtual std::set<entity_id_t>* GetTurrets() = 0; 75 76 /** 62 77 * Returns true if the entity currently exists at a defined position in the world. 63 78 */ 64 79 virtual bool IsInWorld() = 0; -
source/simulation2/components/tests/test_RangeManager.h
40 40 public: 41 41 DEFAULT_MOCK_COMPONENT() 42 42 43 virtual void SetTurretParent(entity_id_t UNUSED(id), CFixedVector3D UNUSED(pos)) {} 44 virtual void UpdateTurretPosition() {} 45 virtual std::set<entity_id_t>* GetTurrets() { return NULL; } 43 46 virtual bool IsInWorld() { return true; } 44 47 virtual void MoveOutOfWorld() { } 45 48 virtual void MoveTo(entity_pos_t UNUSED(x), entity_pos_t UNUSED(z)) { }