Ticket #2266: Guard.diff
File Guard.diff, 22.8 KB (added by , 11 years ago) |
---|
-
binaries/data/mods/public/art/textures/cursors/action-guard-disabled.png
Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream
-
binaries/data/mods/public/art/textures/cursors/action-guard-disabled.txt
Property changes on: binaries/data/mods/public/art/textures/cursors/action-guard-disabled.png ___________________________________________________________________ Added: svn:mime-type ## -0,0 +1 ## +application/octet-stream \ No newline at end of property
1 1 1 -
binaries/data/mods/public/art/textures/ui/session/icons/guard.png
Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream
-
binaries/data/mods/public/gui/session/input.js
Property changes on: binaries/data/mods/public/art/textures/ui/session/icons/guard.png ___________________________________________________________________ Added: svn:mime-type ## -0,0 +1 ## +application/octet-stream \ No newline at end of property
15 15 const ACTION_NONE = 0; 16 16 const ACTION_GARRISON = 1; 17 17 const ACTION_REPAIR = 2; 18 const ACTION_GUARD = 3; 18 19 var preSelectedAction = ACTION_NONE; 19 20 20 21 const INPUT_NORMAL = 0; … … 246 247 if (targetState.garrisonHolder.garrisonedEntitiesCount >= targetState.garrisonHolder.capacity) 247 248 tooltip = "[color=\"orange\"]" + tooltip + "[/color]"; 248 249 } 250 if (targetState.guard && (playerOwned || mutualAllyOwned)) 251 { 252 data.command = "guard"; 253 data.target = target; 254 cursor = "action-guard"; 255 tooltip = "Current guard: " + targetState.guard.entities.length 256 + "/" + targetState.guard.capacity; 257 if (targetState.guard.entities.length >= targetState.guard.capacity) 258 tooltip = "[color=\"red\"]" + tooltip + "[/color]"; 259 } 249 260 else if (targetState.resourceSupply) 250 261 { 251 262 var resourceType = targetState.resourceSupply.type; … … 303 314 if (target === selection[i]) 304 315 return {"possible": false}; 305 316 } 317 // Don't allow the rally point to be set on any of the currently selected entities 318 for (var i = 0; i < selection.length; i++) 319 if (target === selection[i]) 320 return {"possible": false}; 306 321 307 322 return {"possible": true, "data": data, "position": targetState.position, "cursor": cursor, "tooltip": tooltip}; 308 323 } … … 347 362 } 348 363 } 349 364 break; 365 case "guard": 366 if (hasClass(entState, "Unit") && targetState.guard && (playerOwned || mutualAllyOwned)) 367 { 368 var tooltip = "Current guarding: " + targetState.guard.entities.length 369 + "/" + targetState.guard.capacity; 370 if (targetState.guard.entities.length >= targetState.guard.capacity) 371 tooltip = "[color=\"orange\"]" + tooltip + "[/color]"; 372 var allowedClasses = targetState.guard.allowedClasses; 373 return {"possible": true, "tooltip": tooltip}; 374 } 375 break; 350 376 case "setup-trade-route": 351 377 // If ground or sea trade possible 352 378 if (!targetState.foundation && ((entState.trader && hasClass(entState, "Organic") && (playerOwned || allyOwned) && hasClass(targetState, "Market")) || … … 502 528 else 503 529 return {"type": "none", "cursor": "action-repair-disabled", "target": undefined}; 504 530 break; 531 case ACTION_GUARD: 532 if ((actionInfo = getActionInfo("guard", target)).possible) 533 return {"type": "guard", "cursor": "action-guard", "tooltip": actionInfo.tooltip, "target": target}; 534 else 535 return {"type": "none", "cursor": "action-guard-disabled", "target": undefined}; 536 break; 505 537 } 506 538 } 507 539 else if (Engine.HotkeyIsPressed("session.attack") && getActionInfo("attack", target).possible) … … 516 548 { 517 549 return {"type": "attack-move", "cursor": "action-attack-move"}; 518 550 } 551 else if (haveUnitAI && Engine.HotkeyIsPressed("session.guard") && getActionInfo("guard", target).possible) 552 { 553 return {"type": "guard", "cursor": "action-guard"}; 554 } 519 555 else 520 556 { 521 557 if ((actionInfo = getActionInfo("setup-trade-route", target)).possible) … … 1373 1409 Engine.PostNetworkCommand({"type": "repair", "entities": selection, "target": action.target, "autocontinue": true, "queued": queued}); 1374 1410 Engine.GuiInterfaceCall("PlaySound", { "name": "order_repair", "entity": selection[0] }); 1375 1411 return true; 1376 1412 case "guard": 1413 Engine.PostNetworkCommand({"type": "guard", "entities": selection, "target": action.target, "queued": queued}); 1414 Engine.GuiInterfaceCall("PlaySound", { "name": "order_guard", "entity": selection[0] }); 1415 return true; 1377 1416 case "gather": 1378 1417 Engine.PostNetworkCommand({"type": "gather", "entities": selection, "target": action.target, "queued": queued}); 1379 1418 Engine.GuiInterfaceCall("PlaySound", { "name": "order_gather", "entity": selection[0] }); … … 1816 1855 inputState = INPUT_PRESELECTEDACTION; 1817 1856 preSelectedAction = ACTION_GARRISON; 1818 1857 break; 1858 case "guard": 1859 inputState = INPUT_PRESELECTEDACTION; 1860 preSelectedAction = ACTION_GUARD; 1861 break; 1819 1862 case "repair": 1820 1863 inputState = INPUT_PRESELECTEDACTION; 1821 1864 preSelectedAction = ACTION_REPAIR; -
binaries/data/mods/public/gui/session/unit_commands.js
2 2 const SELECTION = "Selection"; 3 3 const QUEUE = "Queue"; 4 4 const GARRISON = "Garrison"; 5 const GUARD = "Guard"; 5 6 const FORMATION = "Formation"; 6 7 const TRAINING = "Training"; 7 8 const RESEARCH = "Research"; -
binaries/data/mods/public/gui/session/utility_functions.js
274 274 "tooltip": "Garrison", 275 275 "icon": "garrison.png" 276 276 }); 277 commands.push({ 278 "name": "guard", 279 "tooltip": "Guard", 280 "icon": "guard.png" 281 }); 277 282 } 278 283 279 284 if (entState.buildEntities) -
binaries/data/mods/public/simulation/components/Guard.js
1 function Guard() {} 2 3 Guard.prototype.Schema = 4 "<a:component type='system'/><empty/>"; 5 6 Guard.prototype.Init = function() 7 { 8 this.VIP={}; 9 // Guardian Units 10 this.entities = []; 11 this.timer = undefined; 12 this.allowGuarding = true; 13 this.capacity = 20; 14 }; 15 16 Guard.prototype.GetEntities = function() 17 { 18 return this.entities; 19 }; 20 Guard.prototype.GetCapacity = function() 21 { 22 return this.capacity; 23 }; 24 Guard.prototype.GetVIP = function() 25 { 26 return this.VIP; 27 }; 28 29 Guard.prototype.AllowGuarding = function(allow, callerID) 30 { 31 this.allowGuarding[callerID] = allow; 32 }; 33 Guard.prototype.AddGuards = function(entity) 34 { 35 if (this.entities.length >= this.GetCapacity()) 36 return false; 37 38 var cmpPosition = Engine.QueryInterface(entity, IID_Position); 39 if (!cmpPosition) 40 return false; 41 //code 42 43 this.entities.push(entity); 44 Engine.PostMessage(this.entity, MT_GuardingUnitsChanged, {}); 45 return true; 46 }; 47 Guard.prototype.EntityLeave = function(entity) 48 { 49 var entityIndex = this.entities.indexOf(entity) 50 if (entityIndex != -1) 51 { 52 this.entities.splice(entityIndex, 1); 53 Engine.PostMessage(this.entity, MT_GuardingUnitsChanged, {}); 54 } 55 56 }; 57 Guard.prototype.CanGuard = function(target) 58 { 59 const cmpIdentity = Engine.QueryInterface(target, IID_Identity); 60 if (!cmpIdentity) 61 return undefined; 62 63 const targetClasses = cmpIdentity.GetClassesList(); 64 65 return true; 66 return false; 67 }; 68 Guard.prototype.CheckGuardRange = function(target) 69 { 70 const cmpIdentity = Engine.QueryInterface(target, IID_Identity); 71 if (!cmpIdentity) 72 return undefined; 73 74 const targetClasses = cmpIdentity.GetClassesList(); 75 76 return true; 77 return false; 78 }; 79 Guard.prototype.OnOwnershipChanged = function(msg) 80 { 81 82 }; 83 Guard.prototype.OnDestroy = function(msg) 84 { 85 86 }; 87 /** 88 * If a guarded entity is captured, or about to be killed (so its owner 89 * changes to '-1'), remove it from the building so we only ever contain valid 90 * entities 91 */ 92 Guard.prototype.OnGlobalOwnershipChanged = function(msg) 93 { 94 // the ownership change may be on the VIP 95 if (this.entity == msg.entity) 96 { 97 var entities = []; 98 for each (var entity in this.entities) 99 { 100 if (msg.to == -1 || !IsOwnedByMutualAllyOfEntity(this.entity, entity)) 101 entities.push(entity); 102 } 103 this.EjectOrKill(entities); 104 return; 105 } 106 107 // or on some of its guarded units 108 var entityIndex = this.entities.indexOf(msg.entity); 109 if (entityIndex != -1) 110 { 111 // If the entity is dead, remove it directly instead of ejecting the corpse 112 var cmpHealth = Engine.QueryInterface(msg.entity, IID_Health); 113 if (cmpHealth && cmpHealth.GetHitpoints() == 0) 114 { 115 this.entities.splice(entityIndex, 1); 116 Engine.PostMessage(this.entity, MT_GuardingUnitsChanged, {}); 117 } 118 else if(!IsOwnedByMutualAllyOfEntity(this.entity, this.entities[entityIndex])) 119 this.EjectOrKill([this.entities[entityIndex]]); 120 } 121 }; 122 123 Guard.prototype.OnGlobalEntityRenamed = function(msg) 124 { 125 var entityIndex = this.entities.indexOf(msg.entity); 126 if (entityIndex != -1) 127 { 128 this.entities[entityIndex] = msg.newentity; 129 Engine.PostMessage(this.entity, MT_GuardingUnitsChanged, {}); 130 } 131 }; 132 Guard.prototype.EjectOrKill = function(entities) 133 { 134 135 // And destroy all remaining entities 136 for each (var entity in entities) 137 { 138 var entityIndex = this.entities.indexOf(entity); 139 if (entityIndex == -1) 140 continue; 141 var cmpHealth = Engine.QueryInterface(entity, IID_Health); 142 if (cmpHealth) 143 144 this.entities.splice(entityIndex, 1); 145 } 146 147 Engine.PostMessage(this.entity, MT_GuardingUnitsChanged, {}); 148 }; 149 Guard.prototype.Unload = function(entity, forced) 150 { 151 return this.PerformEject([entity], forced); 152 }; 153 Guard.prototype.OnHealthChanged = function(msg) 154 { 155 }; 156 Guard.prototype.HasEnoughHealth = function() 157 { 158 var cmpHealth = Engine.QueryInterface(this.entity, IID_Health) 159 var hitpoints = cmpHealth.GetHitpoints(); 160 var maxHitpoints = cmpHealth.GetMaxHitpoints(); 161 var ejectHitpoints = Math.floor((+this.template.EjectHealth) * maxHitpoints); 162 return hitpoints > ejectHitpoints; 163 }; 164 /** 165 * Ejects units and orders them to move to the Rally Point. 166 * Returns true if successful, false if not 167 */ 168 Guard.prototype.PerformEject = function(entities, forced) 169 { 170 if (!this.allowGuarding() && !forced) 171 return false; 172 173 var ejectedEntities = []; 174 var success = true; 175 for each (var entity in entities) 176 { 177 if (this.Eject(entity, forced)) 178 { 179 var cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership); 180 var cmpEntOwnership = Engine.QueryInterface(entity, IID_Ownership); 181 if (cmpOwnership && cmpEntOwnership && cmpOwnership.GetOwner() == cmpEntOwnership.GetOwner()) 182 ejectedEntities.push(entity); 183 } 184 else 185 success = false; 186 } 187 188 return success; 189 }; 190 191 Engine.RegisterComponentType(IID_Guard, "Guard", Guard); 192 No newline at end of file -
binaries/data/mods/public/simulation/components/GuiInterface.js
308 308 { 309 309 ret.resourceGatherRates = cmpResourceGatherer.GetGatherRates(); 310 310 ret.resourceCarrying = cmpResourceGatherer.GetCarryingStatus(); 311 } 312 var cmpGuard = Engine.QueryInterface(ent, IID_Guard); 313 if (cmpGuard) 314 { 315 ret.guard = { 316 "entities": cmpGuard.GetEntities(), 317 "capacity": cmpGuard.GetCapacity(), 318 }; 311 319 } 312 313 320 var cmpResourceDropsite = Engine.QueryInterface(ent, IID_ResourceDropsite); 314 321 if (cmpResourceDropsite) 315 322 { -
binaries/data/mods/public/simulation/components/UnitAI.js
331 331 this.FinishOrder(); 332 332 } 333 333 }, 334 334 "Order.WalkToTargetRange": function(msg) { 335 if (this.MoveToTargetRangeExplicit(this.order.data.target, this.order.data.min, this.order.data.max)) 336 this.SetNextState("WALKING"); 337 else 338 this.FinishOrder(); 339 }, 335 340 "Order.PickupUnit": function(msg) { 336 341 var cmpGarrisonHolder = Engine.QueryInterface(this.entity, IID_GarrisonHolder); 337 342 if (!cmpGarrisonHolder || cmpGarrisonHolder.IsFull()) … … 659 664 this.SetNextState("INDIVIDUAL.GARRISON.GARRISONED"); 660 665 } 661 666 }, 662 667 "Order.Guard": function(msg) { 668 // For packable units: 669 // 1. If packed, we can move to the garrison target. 670 // 2. If unpacked, we first need to pack, then follow case 1. 671 this.SetNextState("INDIVIDUAL.GUARD.APPROACHING"); 672 if (this.CanPack()) 673 { 674 // Case 2: pack 675 this.PushOrderFront("Pack", { "force": true }); 676 return; 677 } 678 }, 663 679 "Order.Autogarrison": function(msg) { 664 680 this.SetNextState("INDIVIDUAL.AUTOGARRISON"); 665 681 }, … … 797 813 798 814 this.SetNextState("GARRISON.GARRISONING"); 799 815 }, 816 "Order.Guard": function(msg) { 817 // TODO: on what should we base this range? 818 // Check if we are already in range, otherwise walk there 819 if (!this.CheckTargetRangeExplicit(msg.data.target, 0, 10)) 820 { 821 if (!this.CheckTargetVisible(msg.data.target)) 822 { 823 if (!this.TargetIsAlive(msg.data.target) || !this.CheckTargetVisible(msg.data.target)) 824 // The target was destroyed 825 this.FinishOrder(); 826 } 827 else 828 { 829 // Out of range; move there in formation 830 this.PushOrderFront("WalkToTargetRange", { "target": msg.data.target, "min": 0, "max": 10 }); 831 return; 832 } 833 834 // We don't want to rearrange the formation if the individual units are carrying 835 // out a task and one of the members dies/leaves the formation. 836 } 837 var cmpFormation = Engine.QueryInterface(this.entity, IID_Formation); 838 // We don't want to rearrange the formation if the individual units are carrying 839 // out a task and one of the members dies/leaves the formation. 840 cmpFormation.SetRearrange(false); 841 cmpFormation.CallMemberFunction("Guard", [msg.data.target, false]); 800 842 843 844 845 this.SetNextStateAlwaysEntering("MEMBER"); 846 }, 847 801 848 "Order.Gather": function(msg) { 802 849 if (this.MustKillGatherTarget(msg.data.target)) 803 850 { … … 1097 1144 cmpFormation.FindInPosition(); 1098 1145 } 1099 1146 }, 1100 1101 1147 "MEMBER": { 1102 1148 // Wait for individual members to finish 1103 1149 "enter": function(msg) { … … 2002 2048 }, 2003 2049 }, 2004 2050 }, 2051 "GUARD": { 2052 "APPROACHING": { 2053 "enter": function() { 2054 this.SelectAnimation("move"); 2055 }, 2056 "MoveCompleted": function() { 2057 this.SetNextState("GUARDING"); 2058 }, 2059 2060 "leave": function() { 2061 this.StopTimer(); 2062 } 2063 } 2064 }, 2065 "GUARDING":{ 2066 "enter": function() { 2067 var target = this.order.data.target; 2068 var cmpGuard = Engine.QueryInterface(target, IID_Guard); 2069 this.VIP=cmpGuard.GetVIP; 2005 2070 2071 // Check that we can guard here 2072 if (cmpGuard.CanGuard(target)) 2073 { 2074 // Check that we're in range of the guarded target 2075 if (cmpGuard.CheckGuardRange(target)) 2076 { 2077 // Check that garrisoning succeeds 2078 if (cmpGuard.AddGuards(this.entity)) 2079 { 2080 this.isGuarding = true; 2081 this.VIP=target; 2082 return;} 2083 } 2084 } 2085 }, 2086 "leave": function() { 2087 this.StopTimer(); 2088 this.isGuarding = false; 2089 var cmpGuard = Engine.QueryInterface(this.VIP, IID_Guard); 2090 cmpGuard.EntityLeave(this.entity); 2091 this.VIP=undefined; 2092 return; 2093 } 2094 }, 2006 2095 "HEAL": { 2007 2096 "Attacked": function(msg) { 2008 2097 // If we stand ground we will rather die than flee … … 2705 2794 this.order = undefined; // always == this.orderQueue[0] 2706 2795 this.formationController = INVALID_ENTITY; // entity with IID_Formation that we belong to 2707 2796 this.isGarrisoned = false; 2797 this.isGuarding = false; 2708 2798 this.isIdle = false; 2709 2799 this.lastFormationName = ""; 2710 2800 this.finishedOrder = false; // used to find if all formation members finished the order … … 2772 2862 { 2773 2863 return this.isGarrisoned; 2774 2864 }; 2775 2865 UnitAI.prototype.IsGuarding = function() 2866 { 2867 return this.IsGuarding; 2868 }; 2776 2869 UnitAI.prototype.IsWalking = function() 2777 2870 { 2778 2871 var state = this.GetCurrentState().split(".").pop(); … … 4182 4275 case "ReturnResource": 4183 4276 case "Repair": 4184 4277 case "Garrison": 4278 case "Guard": 4185 4279 // Find the target unit's position 4186 4280 var cmpTargetPosition = Engine.QueryInterface(order.data.target, IID_Position); 4187 4281 if (!cmpTargetPosition || !cmpTargetPosition.IsInWorld()) … … 4209 4303 // Return the total distance to the end of the order queue 4210 4304 return distance; 4211 4305 }; 4212 4306 UnitAI.prototype.Guard = function(target, queued) 4307 { 4308 if (!this.CanGuard(target)) 4309 { 4310 this.WalkToTarget(target, queued); 4311 return; 4312 } 4313 this.WalkToTarget(target, queued); 4314 + this.AddOrder("Guard", { "target": target, "force": true }, queued); 4315 }; 4213 4316 UnitAI.prototype.AddOrder = function(type, data, queued) 4214 4317 { 4215 4318 if (queued) … … 4907 5010 4908 5011 return true; 4909 5012 }; 5013 UnitAI.prototype.CanGuard = function(target) 5014 { 5015 // Formation controllers should always respond to commands 5016 // (then the individual units can make up their own minds) 5017 if (this.IsFormationController()) 5018 return true; 5019 5020 var cmpGuard = Engine.QueryInterface(target, IID_Guard); 5021 if (!cmpGuard) 5022 return false; 4910 5023 5024 // Verify that the target is owned by this entity's player or a mutual ally of this player 5025 var cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership); 5026 if (!cmpOwnership || !(IsOwnedByPlayer(cmpOwnership.GetOwner(), target) || IsOwnedByMutualAllyOfPlayer(cmpOwnership.GetOwner(), target))) 5027 return false; 5028 5029 // Don't let animals garrison for now 5030 // (If we want to support that, we'll need to change Order.Garrison so it 5031 // doesn't move the animal into an INVIDIDUAL.* state) 5032 if (this.IsAnimal()) 5033 return false; 5034 return true; 5035 }; 4911 5036 UnitAI.prototype.CanPack = function() 4912 5037 { 4913 5038 var cmpPack = Engine.QueryInterface(this.entity, IID_Pack); -
binaries/data/mods/public/simulation/components/interfaces/Guard.js
1 Engine.RegisterInterface("Guard"); 2 3 // Message of the form { } (use GetEntities if you want the current details), 4 // sent to the current entity whenever the garrisoned units change. 5 Engine.RegisterMessageType("GuardingUnitsChanged"); 6 No newline at end of file -
binaries/data/mods/public/simulation/helpers/Commands.js
156 156 cmpUnitAI.GatherNearPosition(cmd.x, cmd.z, cmd.resourceType, cmd.resourceTemplate, cmd.queued); 157 157 }); 158 158 break; 159 159 case "guard": 160 // Verify that the building can be controlled by the player or is mutualAlly 161 if (CanControlUnitOrIsAlly(cmd.target, player, controlAllUnits)) 162 { 163 GetFormationUnitAIs(entities, player).forEach(function(cmpUnitAI) { 164 cmpUnitAI.Guard(cmd.target, cmd.queued); 165 }); 166 warn("Invalid command: guard is in alpha state "+player+" (or ally): "+uneval(cmd)); 167 168 } 169 else if (g_DebugCommands) 170 { 171 warn("Invalid command: garrison target cannot be controlled by player "+player+" (or ally): "+uneval(cmd)); 172 } 173 break; 160 174 case "returnresource": 161 175 // Check dropsite is owned by player 162 176 if (g_DebugCommands && !IsOwnedByPlayer(player, cmd.target)) -
binaries/data/mods/public/simulation/templates/template_unit.xml
53 53 </Formations> 54 54 </Identity> 55 55 <Looter/> 56 <Guard> 57 </Guard> 56 58 <Minimap> 57 59 <Type>unit</Type> 58 60 </Minimap> -
binaries/system/Quickstart.bat
Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream
1 start pyrogenesis.exe -quickstart 1 start pyrogenesis.exe -quickstart 2 No newline at end of file