Ticket #865: diffStances-05-06-2011.patch
File diffStances-05-06-2011.patch, 26.0 KB (added by , 13 years ago) |
---|
-
source/simulation2/components/ICmpRangeManager.cpp
36 36 BEGIN_INTERFACE_WRAPPER(RangeManager) 37 37 DEFINE_INTERFACE_METHOD_5("ExecuteQuery", std::vector<entity_id_t>, ICmpRangeManager, ExecuteQuery, entity_id_t, entity_pos_t, entity_pos_t, std::vector<int>, int) 38 38 DEFINE_INTERFACE_METHOD_5("CreateActiveQuery", ICmpRangeManager::tag_t, ICmpRangeManager, CreateActiveQuery, entity_id_t, entity_pos_t, entity_pos_t, std::vector<int>, int) 39 DEFINE_INTERFACE_METHOD_3("ModifyRangeActiveQuery", std::vector<entity_id_t>, ICmpRangeManager, ModifyRangeActiveQuery, ICmpRangeManager::tag_t, entity_pos_t, entity_pos_t) 39 40 DEFINE_INTERFACE_METHOD_1("DestroyActiveQuery", void, ICmpRangeManager, DestroyActiveQuery, ICmpRangeManager::tag_t) 40 41 DEFINE_INTERFACE_METHOD_1("EnableActiveQuery", void, ICmpRangeManager, EnableActiveQuery, ICmpRangeManager::tag_t) 41 42 DEFINE_INTERFACE_METHOD_1("DisableActiveQuery", void, ICmpRangeManager, DisableActiveQuery, ICmpRangeManager::tag_t) -
source/simulation2/components/ICmpRangeManager.h
102 102 entity_pos_t minRange, entity_pos_t maxRange, std::vector<int> owners, int requiredInterface) = 0; 103 103 104 104 /** 105 * Modify an active query's range parameters and execute a ResetActiveQuery. 106 * @param tag identifier of query. 107 * @param minRange non-negative minimum distance in metres (inclusive). 108 * @param maxRange non-negative maximum distance in metres (inclusive); or -1.0 to ignore distance. 109 * @return list of entities matching the query, ordered by increasing distance from the source entity. 110 */ 111 virtual std::vector<entity_id_t> ModifyRangeActiveQuery(tag_t tag, 112 entity_pos_t minRange, entity_pos_t maxRange) = 0; 113 114 /** 105 115 * Destroy a query and clean up resources. This must be called when an entity no longer needs its 106 116 * query (e.g. when the entity is destroyed). 107 117 * @param tag identifier of query. -
source/simulation2/components/CCmpRangeManager.cpp
459 459 return (tag_t)id; 460 460 } 461 461 462 virtual std::vector<entity_id_t> ModifyRangeActiveQuery(tag_t tag, 463 entity_pos_t minRange, entity_pos_t maxRange) 464 { 465 std::map<tag_t, Query>::iterator it = m_Queries.find(tag); 466 if (it == m_Queries.end()) 467 { 468 LOGERROR(L"CCmpRangeManager: ModifyRangeActiveQuery called with invalid tag %d", tag); 469 std::vector<entity_id_t> r; 470 return r; 471 } 472 473 Query& q = it->second; 474 q.minRange = minRange; 475 q.maxRange = maxRange; 476 return ResetActiveQuery(tag); 477 } 478 462 479 virtual void DestroyActiveQuery(tag_t tag) 463 480 { 464 481 if (m_Queries.find(tag) == m_Queries.end()) -
binaries/data/mods/public/maps/scenarios/Combat_demo.xml
40 40 "Civ": "hele" 41 41 } 42 42 ], 43 "RevealMap": true 43 "RevealMap": true, 44 "DefaultStance": "stand" 44 45 } 45 46 ]]></ScriptSettings> 46 47 <Entities> … … 1285 1286 </Entity> 1286 1287 </Entities> 1287 1288 <Paths/> 1288 </Scenario> 1289 No newline at end of file 1289 </Scenario> -
binaries/data/mods/public/maps/scenarios/Pathfinding_demo.xml
41 41 } 42 42 ], 43 43 "RevealMap": true, 44 "DefaultStance": " holdfire",44 "DefaultStance": "defensive", 45 45 "GameType": "endless" 46 46 } 47 47 ]]></ScriptSettings> … … 684 684 </Entity> 685 685 </Entities> 686 686 <Paths/> 687 </Scenario> 688 No newline at end of file 687 </Scenario> -
binaries/data/mods/public/gui/session/session.xml
408 408 </object> 409 409 410 410 <!-- ================================ ================================ --> 411 <!-- Stance Selection (Temporary location) --> 412 <!-- ================================ ================================ --> 413 <object name="unitStancePanel" 414 sprite="bottomMiddle" 415 size="50 50 300 106" 416 type="text" 417 > 418 <object size="-5 -2 59 62" type="image" sprite="snIconSheetTab" tooltip_style="sessionToolTipBottom" 419 cell_id="4" tooltip="Stances"/> 420 421 <object size="56 12 100% 100%"> 422 <repeat count="5"> 423 <object name="unitStanceButton[n]" hidden="true" style="iconButton" type="button" size="0 0 36 36" tooltip_style="sessionToolTipBottomBold" z="100"> 424 <object name="unitStanceIcon[n]" type="image" ghost="true" size="3 3 33 33"/> 425 </object> 426 </repeat> 427 </object> 428 </object> 429 430 <!-- ================================ ================================ --> 411 431 <!-- Idle Worker Button --> 412 432 <!-- ================================ ================================ --> 413 433 <object type="image" … … 638 658 </object> 639 659 </object> 640 660 641 <object name="unitStancePanel"642 style="goldPanelFrilly"643 size="0 100%-56 100% 100%"644 type="text"645 >646 <object size="-5 -2 59 62" type="image" sprite="snIconSheetTab" tooltip_style="sessionToolTipBottom"647 cell_id="4" tooltip="Stances"/>648 649 [stance commands]650 </object>651 652 661 <object name="unitResearchPanel" 653 662 style="goldPanelFrilly" 654 663 size="0 100%-56 100% 100%" -
binaries/data/mods/public/gui/session/input.js
1145 1145 } 1146 1146 } 1147 1147 1148 // Performs the specified stance 1149 function performStance(entity, stanceName) 1150 { 1151 if (entity) 1152 { 1153 var selection = g_Selection.toList(); 1154 Engine.PostNetworkCommand({ 1155 "type": "stance", 1156 "entities": selection, 1157 "name": stanceName 1158 }); 1159 } 1160 } 1161 1148 1162 // Set the camera to follow the given unit 1149 1163 function setCameraFollow(entity) 1150 1164 { -
binaries/data/mods/public/gui/session/unit_commands.js
6 6 const TRAINING = "Training"; 7 7 const CONSTRUCTION = "Construction"; 8 8 const COMMAND = "Command"; 9 const STANCE = "Stance"; 9 10 10 11 // Constants 11 12 const COMMANDS_PANEL_WIDTH = 228; … … 13 14 const UNIT_PANEL_HEIGHT = 44; // QUEUE: The height needed for a row of buttons 14 15 15 16 // The number of currently visible buttons (used to optimise showing/hiding) 16 var g_unitPanelButtons = {"Selection": 0, "Queue": 0, "Formation": 0, "Garrison": 0, "Training": 0, "Construction": 0, "Command": 0 };17 var g_unitPanelButtons = {"Selection": 0, "Queue": 0, "Formation": 0, "Garrison": 0, "Training": 0, "Construction": 0, "Command": 0, "Stance": 0}; 17 18 18 19 // Unit panels are panels with row(s) of buttons 19 20 var g_unitPanels = ["Selection", "Queue", "Formation", "Garrison", "Training", "Construction", "Research", "Stance", "Command"]; … … 120 121 if (numberOfItems > 16) 121 122 numberOfItems = 16; 122 123 } 123 if (guiName == "Formation")124 else if (guiName == "Formation") 124 125 { 125 126 if (numberOfItems > 16) 126 127 numberOfItems = 16; 128 } 129 else if (guiName == "Stance") 130 { 131 if (numberOfItems > 5) 132 numberOfItems = 5; 127 133 } 128 134 else if (guiName == "Queue") 129 135 { … … 153 159 var item = items[i]; 154 160 var entType = ((guiName == "Queue")? item.template : item); 155 161 var template; 156 if (guiName != "Formation" && guiName != "Command" )162 if (guiName != "Formation" && guiName != "Command" && guiName != "Stance") 157 163 { 158 164 template = GetTemplateData(entType); 159 165 if (!template) … … 190 196 getGUIObjectByName("unit"+guiName+"Count["+i+"]").caption = (count > 1 ? count : ""); 191 197 break; 192 198 199 case STANCE: 193 200 case FORMATION: 194 201 var tooltip = toTitleCase(item); 195 202 break; … … 265 272 icon.sprite = "formation"; 266 273 } 267 274 } 275 else if (guiName == "Stance") 276 { 277 var stanceSelected = Engine.GuiInterfaceCall("StanceSelected", { 278 "ents": g_Selection.toList(), 279 "stance": item 280 }); 281 282 icon.cell_id = i; 283 if (stanceSelected) 284 icon.sprite = "snIconSheetStanceButton"; 285 else 286 icon.sprite = "snIconSheetStanceButtonDisabled"; 287 } 268 288 else if (guiName == "Command") 269 289 { 270 290 //icon.cell_id = i; … … 368 388 setupUnitPanel("Formation", usedPanels, entState, formations, 369 389 function (item) { performFormation(entState.id, item); } ); 370 390 391 var stances = ["violent","aggressive","passive","defensive","stand"]; 392 if (isUnit(entState) && !isAnimal(entState) && !entState.garrisonHolder && stances.length) 393 setupUnitPanel("Stance", usedPanels, entState, stances, 394 function (item) { performStance(entState.id, item); } ); 395 371 396 if (entState.buildEntities && entState.buildEntities.length) 372 397 { 373 398 setupUnitPanel("Construction", usedPanels, entState, entState.buildEntities, startBuildingPlacement); -
binaries/data/mods/public/gui/session/session.js
235 235 function updateGroups() 236 236 { 237 237 var guiName = "Group"; 238 g_Groups.update(); 238 239 for (var i = 0; i < 10; i++) 239 240 { 240 241 var button = getGUIObjectByName("unit"+guiName+"Button["+i+"]"); 241 242 var label = getGUIObjectByName("unit"+guiName+"Label["+i+"]").caption = i; 242 g_Groups.update();243 243 if (g_Groups.groups[i].getTotalCount() == 0) 244 244 button.hidden = true; 245 245 else -
binaries/data/mods/public/simulation/helpers/Setup.js
14 14 for each (var ent in Engine.GetEntitiesWithInterface(IID_UnitAI)) 15 15 { 16 16 var cmpUnitAI = Engine.QueryInterface(ent, IID_UnitAI); 17 cmpUnitAI.S etStance(settings.DefaultStance);17 cmpUnitAI.SwitchToStance(settings.DefaultStance); 18 18 } 19 19 } 20 20 -
binaries/data/mods/public/simulation/helpers/Commands.js
261 261 } 262 262 break; 263 263 264 case "stance": 265 for each (var ent in cmd.entities) 266 { 267 var cmpUnitAI = Engine.QueryInterface(ent, IID_UnitAI); 268 if (cmpUnitAI) 269 cmpUnitAI.SwitchToStance(cmd.name); 270 } 271 break; 272 264 273 default: 265 274 error("Ignoring unrecognised command type '" + cmd.type + "'"); 266 275 } -
binaries/data/mods/public/simulation/components/GuiInterface.js
288 288 return CanMoveEntsIntoFormation(data.ents, data.formationName); 289 289 }; 290 290 291 GuiInterface.prototype.StanceSelected = function(player, data) 292 { 293 for each (var ent in data.ents) 294 { 295 var cmpUnitAI = Engine.QueryInterface(ent, IID_UnitAI); 296 if (cmpUnitAI) 297 { 298 if (cmpUnitAI.GetStanceName() == data.stance) 299 return true; 300 } 301 } 302 return false; 303 }; 304 291 305 GuiInterface.prototype.SetSelectionHighlight = function(player, cmd) 292 306 { 293 307 var cmpPlayerMan = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager); … … 543 557 "GetNextNotification": 1, 544 558 545 559 "CanMoveEntsIntoFormation": 1, 560 "StanceSelected": 1, 546 561 547 562 "SetSelectionHighlight": 1, 548 563 "SetStatusBars": 1, -
binaries/data/mods/public/simulation/components/UnitAI.js
6 6 "<element name='DefaultStance'>" + 7 7 "<choice>" + 8 8 "<value>aggressive</value>" + 9 "<value> holdfire</value>" +10 "<value> noncombat</value>" +9 "<value>defensive</value>" + 10 "<value>passive</value>" + 11 11 "</choice>" + 12 12 "</element>" + 13 13 "<element name='FormationController'>" + … … 59 59 // TODO: even this limited version isn't implemented properly yet (e.g. it can't handle 60 60 // dynamic stance changes). 61 61 var g_Stances = { 62 " aggressive": {62 "violent": { 63 63 targetVisibleEnemies: true, 64 64 targetAttackers: true, 65 65 respondFlee: false, 66 66 respondChase: true, 67 respondStandGround : false, 68 respondHoldGround : false, 67 69 }, 68 " holdfire": {69 targetVisibleEnemies: false,70 "aggressive": { 71 targetVisibleEnemies: true, 70 72 targetAttackers: true, 71 73 respondFlee: false, 72 74 respondChase: true, 75 respondStandGround : false, 76 respondHoldGround : false, 73 77 }, 74 "noncombat": { 78 "defensive": { 79 targetVisibleEnemies: true, 80 targetAttackers: true, 81 respondFlee: false, 82 respondChase: false, 83 respondStandGround : false, 84 respondHoldGround : true, 85 }, 86 "passive": { 75 87 targetVisibleEnemies: false, 76 88 targetAttackers: true, 77 89 respondFlee: true, 78 90 respondChase: false, 91 respondStandGround : false, 92 respondHoldGround : false, 79 93 }, 94 "stand": { 95 targetVisibleEnemies: true, 96 targetAttackers: true, 97 respondFlee: false, 98 respondChase: false, 99 respondStandGround : true, 100 respondHoldGround : false, 101 }, 80 102 }; 81 103 82 104 // See ../helpers/FSM.js for some documentation of this FSM specification syntax … … 114 136 // ignore 115 137 }, 116 138 139 "StanceChanged": function(msg) { 140 if (this.StanceSpecificQuery(this.stance,true)) 141 return; 142 }, 143 117 144 // Formation handlers: 118 145 119 146 "FormationLeave": function(msg) { … … 154 181 return; 155 182 } 156 183 184 this.SetHeldPosition({"x": this.order.data.x, "z": this.order.data.z}); 157 185 this.MoveToPoint(this.order.data.x, this.order.data.z); 158 186 this.SetNextState("INDIVIDUAL.WALKING"); 159 187 }, … … 217 245 } 218 246 this.attackType = type; 219 247 248 if (this.CheckTargetRange(this.order.data.target, IID_Attack, this.attackType)) 249 { 250 // We are already at the target 251 // so try attacking it from here. 252 this.StopMoving(); 253 if (this.IsAnimal()) 254 this.SetNextState("ANIMAL.COMBAT.ATTACKING"); 255 else 256 this.SetNextState("INDIVIDUAL.COMBAT.ATTACKING"); 257 } 220 258 // Try to move within attack range 221 if (this.MoveToTargetRange(this.order.data.target, IID_Attack, this.attackType))259 else if (!this.order.data.stand && this.MoveToTargetRange(this.order.data.target, IID_Attack, this.attackType)) 222 260 { 223 261 // We've started walking to the given point 224 262 if (this.IsAnimal()) … … 227 265 this.SetNextState("INDIVIDUAL.COMBAT.APPROACHING"); 228 266 } 229 267 else 230 { 231 // We are already at the target, or can't move at all, 232 // so try attacking it from here. 233 // TODO: need better handling of the can't-reach-target case 234 this.StopMoving(); 235 if (this.IsAnimal()) 236 this.SetNextState("ANIMAL.COMBAT.ATTACKING"); 237 else 238 this.SetNextState("INDIVIDUAL.COMBAT.ATTACKING"); 239 } 268 this.FinisOrder(); 240 269 }, 241 270 242 271 "Order.Gather": function(msg) { … … 484 513 // If we entered the idle state we must have nothing better to do, 485 514 // so immediately check whether there's anybody nearby to attack. 486 515 // (If anyone approaches later, it'll be handled via LosRangeUpdate.) 487 if (this.losRangeQuery) 488 { 489 var rangeMan = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager); 490 var ents = rangeMan.ResetActiveQuery(this.losRangeQuery); 491 if (this.GetStance().targetVisibleEnemies) 492 { 493 if (this.RespondToTargetedEntities(ents)) 494 return true; // (abort the FSM transition since we may have already switched state) 495 } 496 } 516 if (this.StanceSpecificQuery(this.stance)) 517 return true; 497 518 498 519 // Nobody to attack - stay in idle 499 520 return false; … … 551 572 } 552 573 }, 553 574 575 "StanceChanged": function(msg) { 576 if (this.StanceSpecificQuery(this.stance)) 577 return; 578 }, 554 579 }, 555 580 556 581 "WALKING": { … … 605 630 "MoveCompleted": function() { 606 631 this.SetNextState("ATTACKING"); 607 632 }, 633 634 "Attacked": function(msg) { 635 // If we're attacked by a close enemy, we should try to defend ourself 636 if (this.GetStance().targetAttackers && msg.data.type == "Melee") 637 { 638 this.RespondToTargetedEntities([msg.data.attacker]); 639 } 640 }, 608 641 }, 609 642 610 643 "ATTACKING": { … … 638 671 } 639 672 640 673 // Can't reach it - try to chase after it 641 if (this. MoveToTargetRange(this.order.data.target, IID_Attack, this.attackType))674 if (this.GetStance().respondChase && this.MoveToTargetRange(this.order.data.target, IID_Attack, this.attackType)) 642 675 { 643 676 this.SetNextState("COMBAT.CHASING"); 644 677 return; 645 678 } 679 680 if (this.GetStance().respondHoldGround && this.CheckTargetDistanceFromHeldPosition(this.order.data.target, this.attackType, 50)) 681 { 682 if (this.MoveToTargetRange(this.order.data.target, IID_Attack, this.attackType)) 683 { 684 this.SetNextState("COMBAT.CHASING"); 685 return; 686 } 687 } 646 688 } 647 689 648 690 // Can't reach it, or it doesn't exist any more - give up 649 this.FinishOrder(); 691 if (this.FinishOrder()) 692 return; 650 693 651 // TODO: see if we can switch to a new nearby enemy 694 // see if we can switch to a new nearby enemy 695 if (this.StanceSpecificQuery(this.stance, true)) 696 return; 697 698 // we return to our position 699 if (this.GetStance().respondHoldGround && this.heldPosition) 700 { 701 this.Walk(this.heldPosition.x, this.heldPosition.z, false); 702 return; 703 } 652 704 }, 653 705 654 706 // TODO: respond to target deaths immediately, rather than waiting … … 659 711 "enter": function () { 660 712 this.SelectAnimation("move"); 661 713 }, 662 714 663 715 "MoveCompleted": function() { 664 716 this.SetNextState("ATTACKING"); 665 717 }, … … 1303 1355 // This should be called whenever our ownership changes. 1304 1356 UnitAI.prototype.SetupRangeQuery = function(owner) 1305 1357 { 1306 var cmpVision = Engine.QueryInterface(this.entity, IID_Vision);1307 if (!cmpVision)1308 return;1309 1310 1358 var rangeMan = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager); 1311 1359 var playerMan = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager); 1312 1360 1313 1361 if (this.losRangeQuery) 1314 1362 rangeMan.DestroyActiveQuery(this.losRangeQuery); 1315 1363 1316 var range = cmpVision.GetRange();1317 1318 1364 var players = []; 1319 1365 1320 1366 if (owner != -1) 1321 1367 { 1322 1368 // If unit not just killed, get enemy players via diplomacy … … 1334 1380 players.push(i); 1335 1381 } 1336 1382 } 1337 1338 this.losRangeQuery = rangeMan.CreateActiveQuery(this.entity, 0, range, players, IID_DamageReceiver); 1383 1384 var range = this.StanceSpecificRange(); 1385 1386 this.losRangeQuery = rangeMan.CreateActiveQuery(this.entity, 0, range.max, players, IID_DamageReceiver); 1339 1387 rangeMan.EnableActiveQuery(this.losRangeQuery); 1340 } ;1388 } 1341 1389 1342 1390 //// FSM linkage functions //// 1343 1391 … … 1812 1860 return cmpUnitMotion.IsInTargetRange(target, range.min, range.max); 1813 1861 }; 1814 1862 1863 UnitAI.prototype.CheckTargetDistanceFromHeldPosition = function(target, type, distance) 1864 { 1865 var cmpRanged = Engine.QueryInterface(this.entity, IID_Attack); 1866 var range = cmpRanged.GetRange(type); 1867 1868 var cmpPosition = Engine.QueryInterface(target, IID_Position); 1869 if (!cmpPosition || !cmpPosition.IsInWorld()) 1870 return false; 1871 1872 var pos = cmpPosition.GetPosition(); 1873 var dx = this.heldPosition.x - pos.x; 1874 var dz = this.heldPosition.z - pos.z; 1875 var dist = Math.sqrt(dx*dx + dz*dz); 1876 1877 return dist < distance + range.max; 1878 }; 1879 1815 1880 UnitAI.prototype.GetBestAttack = function() 1816 1881 { 1817 1882 var cmpAttack = Engine.QueryInterface(this.entity, IID_Attack); … … 1839 1904 }; 1840 1905 1841 1906 /** 1907 * Try to find one of the given entities which can be attacked, 1908 * without moving. 1909 * Returns true if it found something to attack. 1910 */ 1911 UnitAI.prototype.AttackEntityInRange = function(ents) 1912 { 1913 var type = this.GetBestAttack(); 1914 for each (var target in ents) 1915 { 1916 if (this.CanAttack(target) && this.CheckTargetRange(target, IID_Attack, type)) 1917 { 1918 this.PushOrderFront("Attack", { "target": target, "stand": true }); 1919 return true; 1920 } 1921 } 1922 return false; 1923 }; 1924 1925 /** 1926 * Try to find one of the given entities which can be attacked, 1927 * within zone. 1928 * Returns true if it found something to attack. 1929 */ 1930 UnitAI.prototype.AttackEntityInZone = function(ents) 1931 { 1932 var type = this.GetBestAttack(); 1933 for each (var target in ents) 1934 { 1935 if (this.CanAttack(target) && this.CheckTargetDistanceFromHeldPosition(target, type, 50)) 1936 { 1937 this.PushOrderFront("Attack", { "target": target }); 1938 return true; 1939 } 1940 } 1941 return false; 1942 }; 1943 1944 /** 1842 1945 * Try to respond appropriately given our current stance, 1843 1946 * given a list of entities that match our stance's target criteria. 1844 1947 * Returns true if it responded. … … 1851 1954 if (this.GetStance().respondChase) 1852 1955 return this.AttackVisibleEntity(ents); 1853 1956 1957 if (this.GetStance().respondStandGround) 1958 return this.AttackEntityInRange(ents); 1959 1960 if (this.GetStance().respondHoldGround) 1961 return this.AttackEntityInZone(ents); 1962 1854 1963 if (this.GetStance().respondFlee) 1855 1964 { 1856 1965 this.PushOrderFront("Flee", { "target": ents[0] }); … … 2088 2197 this.stance = stance; 2089 2198 else 2090 2199 error("UnitAI: Setting to invalid stance '"+stance+"'"); 2200 } 2201 2202 UnitAI.prototype.SwitchToStance = function(stance) 2203 { 2204 var cmpPosition = Engine.QueryInterface(this.entity, IID_Position); 2205 if (!cmpPosition || !cmpPosition.IsInWorld()) 2206 return; 2207 var pos = cmpPosition.GetPosition(); 2208 this.SetHeldPosition({"x": pos.x, "z": pos.z}); 2209 2210 this.SetStance(stance); 2211 if (stance == "stand" || stance == "defensive" || stance == "passive") 2212 this.StopMoving(); 2213 2214 UnitFsm.ProcessMessage(this, {"type": "StanceChanged", "stance": stance}); 2215 } 2216 2217 UnitAI.prototype.StanceSpecificQuery = function(stance, disable) 2218 { 2219 if (!g_Stances[stance]) 2220 { 2221 error("UnitAI: Setting to invalid stance '"+stance+"'"); 2222 return false; 2223 } 2224 2225 if (!this.losRangeQuery) 2226 return false; 2227 2228 var range = this.StanceSpecificRange(); 2229 2230 var rangeMan = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager); 2231 var ents = rangeMan.ModifyRangeActiveQuery(this.losRangeQuery, range.min, range.max); 2232 2233 if (disable && !this.IsAnimal()) 2234 rangeMan.DisableActiveQuery(this.losRangeQuery); 2235 2236 return this.RespondToTargetedEntities(ents); 2091 2237 }; 2092 2238 2239 UnitAI.prototype.StanceSpecificRange = function() 2240 { 2241 var ret = { "min": 0, "max": 0 }; 2242 if (this.GetStance().respondStandGround) 2243 { 2244 var cmpRanged = Engine.QueryInterface(this.entity, IID_Attack); 2245 if (!cmpRanged) 2246 return ret; 2247 var range = cmpRanged.GetRange(cmpRanged.GetBestAttack()); 2248 ret.min = range.min; 2249 ret.max = range.max; 2250 } 2251 else if (this.GetStance().respondChase) 2252 { 2253 var cmpVision = Engine.QueryInterface(this.entity, IID_Vision); 2254 if (!cmpVision) 2255 return ret; 2256 var range = cmpVision.GetRange(); 2257 ret.max = range; 2258 } 2259 else if (this.GetStance().respondHoldGround) 2260 { 2261 var cmpRanged = Engine.QueryInterface(this.entity, IID_Attack); 2262 if (!cmpRanged) 2263 return ret; 2264 var range = cmpRanged.GetRange(cmpRanged.GetBestAttack()); 2265 ret.max = range.max + 50; 2266 } 2267 return ret; 2268 }; 2269 2093 2270 UnitAI.prototype.GetStance = function() 2094 2271 { 2095 2272 return g_Stances[this.stance]; 2096 2273 }; 2097 2274 2275 UnitAI.prototype.GetStanceName = function() 2276 { 2277 return this.stance; 2278 }; 2279 2098 2280 //// Helper functions //// 2099 2281 2100 2282 UnitAI.prototype.CanAttack = function(target) … … 2234 2416 cmpMotion.SetSpeed(speed); 2235 2417 }; 2236 2418 2419 UnitAI.prototype.SetHeldPosition = function(pos) 2420 { 2421 this.heldPosition = {"x": pos.x, "z": pos.z}; 2422 }; 2423 2424 UnitAI.prototype.GetHeldPosition = function(pos) 2425 { 2426 return this.heldPosition; 2427 }; 2428 2429 2237 2430 Engine.RegisterComponentType(IID_UnitAI, "UnitAI", UnitAI); -
binaries/data/mods/public/simulation/components/Attack.js
245 245 } 246 246 247 247 Engine.PostMessage(data.target, MT_Attacked, 248 { "attacker": this.entity, "target": data.target });248 { "attacker": this.entity, "target": data.target, "type": data.type }); 249 249 250 250 PlaySound("attack_impact", this.entity); 251 251 }; -
binaries/data/mods/public/simulation/components/Promotion.js
65 65 66 66 var cmpCurrentUnitAI = Engine.QueryInterface(this.entity, IID_UnitAI); 67 67 var cmpPromotedUnitAI = Engine.QueryInterface(promotedUnitEntity, IID_UnitAI); 68 cmpPromotedUnitAI.SetHeldPosition(cmpCurrentUnitAI.GetHeldPosition()); 69 if (cmpCurrentUnitAI.GetStanceName()) 70 cmpPromotedUnitAI.SetStance(cmpCurrentUnitAI.GetStanceName()); 68 71 cmpPromotedUnitAI.Cheer(); 69 72 var orders = cmpCurrentUnitAI.GetOrders(); 70 73 cmpPromotedUnitAI.AddOrders(orders); -
binaries/data/mods/public/simulation/templates/template_unit_support.xml
8 8 <Type>support</Type> 9 9 </Minimap> 10 10 <UnitAI> 11 <DefaultStance> noncombat</DefaultStance>11 <DefaultStance>passive</DefaultStance> 12 12 </UnitAI> 13 13 <Cost> 14 14 <BuildTime>15</BuildTime>