| 12-04-2008, 10:44 PM | #1 |
I'm hoping to create an ability that will use a passive icon to actively store corpses in the caster. What I mean is, there will be a passive spell icon displaying text, while the owner of the hero need not click any icons to facilitate the corpse storage. I want to accomplish this using only 1 icon / space. I have successfully made a spell that is actively used to store corpses, however I think it will be a burden on the hero if the user has to be constantly clicking. I've also tried using a spellbook trick that uses raise dead to target the corpses, and is triggered such that when the maximum number of corpses has been stored, autocast is turned on, and when corpses are used, autocast is turned off. However, disabling the spellbook ability seems to also disable the raise dead ability stored within it. The other option you may think of is of course the actual corpse cargo load ability, however it severely interferes with the hero interface and also makes it very difficult to remove the stored unit, which I want to do immediately after the spell is cast. Doing it a conventional way of ordering the unit to just drop the corpse once it's picked up requires a second icon unfortunately. Anyone have some ideas? I'm scrambling here. |
| 12-04-2008, 10:49 PM | #2 |
Trigger it completely? Detect if a corpse is in range (maybe based on an order string?), remove it, increase some variable. If the maximum is reached, loop and create a skeleton and subtract the corpse count until you've used every corpse. |
| 12-04-2008, 11:04 PM | #3 |
I've already made a spell identical to that is used actively. Do you mean a passive version that just checks every once in a while and carries out the removal action? I want it to be done via casting a spell such that the hero is required to walk over to and "pick up" the corpse, which would be a pain to code. Plus I think having a timer run like that throughout the game might be expensive, though I have seen it done before. I guess the best option now is using a permanent timer. |
| 12-05-2008, 12:30 AM | #4 |
Base it off of cannabalism. :P |
| 12-05-2008, 01:02 AM | #5 |
That's a good idea, and it limits to one icon. But it still requires active use of the spell :(. |
| 12-05-2008, 01:21 AM | #6 |
GUI or JASS? This would be a bit complicated in GUI, but less complicated using JASS. Another thing that might help is: if you disable an ability for a player, does it retain its current cooldown? Because if so, then this wouldn't be too complicated in GUI. |
| 12-05-2008, 01:27 AM | #7 |
JASS all the way. I'm pretty sure the ability and therefore its cooldown is still there if you disable it, you just can't do squat with it. It wouldn't need a cooldown or manacost though. Do you have a plan? If so, lay it out for me. |
| 12-05-2008, 01:34 AM | #8 |
You give the units a passive ability that simply displays the number of corpses and then an active ability based on silence that does absolutely nothing except play the animation you want to play when the unit picks up a corpse. This spell is disabled for all players at map init.
I'll write up some JASS in a second that does this. JASS:scope CorpseSpell initializer Init globals private constant integer PASSIVE_ID = 'A000' private constant integer ACTIVE_ID = 'A001' private constant real TIMER_INTERVAL = 0.15 private constant real SEARCH_RADIUS = 200.00 private constant string ORDER_STRING = "silence" private timer T = null private trigger SpellCast = null private boolexpr B = null private boolexpr B2 = null private group G = null private group G2 = null endglobals private function HasPassive takes nothing returns boolean return GetUnitAbilityLevel(GetFilterUnit(), PASSIVE_ID) > 0 endfunction private function IsCorpse takes nothing returns boolean return GetWidgetLife(U) < 0.406 endfunction private function Periodic takes nothing returns nothing local integer J = 0 local unit U local unit U2 local unit C local real CX local real CY local real Dist = SEARCH_RADIUS*SEARCH_RADIUS+32.00 local integer O local real U2D local real U2X local real U2Y local real X local real Y loop call SetPlayerAbilityAvailable(Player(J), ACTIVE_ID, true) set J = J+1 exitwhen J >= 12 endloop call GroupEnumUnitsInRect(G, bj_mapInitialPlayableArea, B) loop set U = FirstOfGroup(G) exitwhen U == null set X = GetUnitX(U) set Y = GetUnitY(U) call GroupEnumUnitsInRange(G2, X, Y, SEARCH_RADIUS, B2) loop set U2 = FirstOfGroup(G) exitwhen U2 == null set U2X = GetUnitX(U) set U2Y = GetUnitY(U) set U2D = (U2X-X)*(U2X-X) + (U2Y-Y)*(U2Y-U) if U2D < Dist then set C = U2 set Dist = U2D set CX = U2X set CY = U2Y endif endloop if C != null then set O = GetUnitCurrentOrder(U) if O == Order("smart") or O == Order("stop") then call IssueTargetOrder(U, ORDER_STRING, CX, CY) endif set C == null endif endloop set J = 0 loop call SetPlayerAbilityAvailable(Player(J), ACTIVE_ID, false) set J = J+1 exitwhen J >= 12 endloop endfunction private function ActiveCastConditions takes nothing returns boolean return GetSpellAbilityId() == ACTIVE_ID endfunction private function ActiveCast takes nothing returns nothing //Do your stuff here endfunction private function Init takes nothing returns nothing local integer J = 0 loop call SetPlayerAbilityAvailable(Player(J), ACTIVE_ID, false) set J = J+1 exitwhen J >= 12 endloop set G = CreateGroup() set G2 = CreateGroup() set B = Condition(function HasPassive) set B2 = Condition(function IsCorpse) set SpellCast = CreateTrigger() call TriggerRegisterAnyUnitEventBJ(SpellCast, EVENT_PLAYER_UNIT_SPELL_EFFECT) call TriggerAddCondition(SpellCast, Condition(function ActiveCastConditions)) call TriggerAddAction(SpellCast, function ActiveCast) call TimerStart(T, TIMER_INTERVAL, true, function Periodic) endfunction endscope |
| 12-05-2008, 01:41 AM | #9 |
Dude that's an awesome idea... I already have the corpse removal / variable increase coded, I just need to implement the new ability and the enabling / disabling trick. So yeah I guess it does need a constant timer... Don't sweat going through all this, I'm sure you have enough on your hands. Oh I see. I'm rather glad you went through with it Pyro, thank you. That seems like a fairly efficient way of doing it. I was considering using an individual instanciation of a structure per creation of the hero: that is, individual timer, conditions, corpse counter, disabling / enabling for only that player. Probably gets much more expensive with more and more people using the hero... One question before I say g'night: At what point is each unit who has the spell and available space, ordered to cast silence? In the Periodic? |
| 12-05-2008, 02:21 AM | #10 |
I hadn't finished when I saved that edit. Now it's finished. I'm not entirely sure if the enabling/disabling thing will work, though. |
| 12-05-2008, 05:15 PM | #11 |
I read through the script Pyro, and I definitely get the gist of it... Though I have yet to test it and see whether the spell can fire in time before the disable. I can see how using those locals is a useful way to find the dead unit, though I usually use a static group, boolexpr, and simply sort through each unit in the boolexpr, and check it with static constants that I set right before the enum. Then instead of comparison of squares you can use IsUnitInRangeXY though that is a function call. I'm not really sure which is more efficient. Thank you for writing the script. |
| 12-05-2008, 11:37 PM | #12 |
I don't honestly know how IsUnitInRangeXY() compares to GetUnitX() + GetUnitY() + Math + if-comparison. My guess is that it's probably better :P So yeah, use that. |
| 12-06-2008, 12:30 AM | #13 |
And it takes their collision size into account |
| 12-07-2008, 10:32 PM | #14 |
I've made my decision: The caster will not go to the dead units; they will come to him :D. I'll say no more because I want it a secret until the Hero Contest Poll. |
