| 09-11-2007, 05:37 PM | #1 |
I'm trying to make my own redemption aura that has a chance to redeem a corpse every 10 seconds and restore 10% of the units total health. The problem is that it does it every ten seconds even if there are no corpses, and the effect (resurrection with the angel) will play in the center of the map instead of the corpse. Even if there are nearby corpses, it still plays the effect in the center of the map. Here is the code. JASS:function RedemptionAuraGroupAdd takes nothing returns nothing call GroupAddUnitSimple(GetEnumUnit(), udg_RedemptionAuraGroup) endfunction function RedemptionAuraDeadCheck takes nothing returns boolean local unit u = GetEnumUnit() return (IsUnitDeadBJ(u)) endfunction function Trig_Redemption_Aura_Actions takes nothing returns nothing local unit caster = udg_LightBearer local location l = GetUnitLoc(caster) local unit u = GroupPickRandomUnit(udg_RedemptionAuraGroup) local real x = GetLocationX(GetUnitLoc(u)) local real y = GetLocationY(GetUnitLoc(u)) local effect e1 local effect e2 local real heal = GetUnitStateSwap(UNIT_STATE_MAX_LIFE, caster)*0.10 local integer i = GetRandomInt(1,5) if i != 1 then return endif call ForGroupBJ( GetUnitsInRangeOfLocMatching(600.00, l, Condition(function RedemptionAuraDeadCheck)), function RedemptionAuraGroupAdd ) if IsUnitGroupEmptyBJ(udg_RedemptionAuraGroup) then return endif set e1 = AddSpecialEffect("Abilities\\Spells\\Human\\Resurrect\\ResurrectCaster.mdl", x, y) call DestroyEffect(e1) set e1 = null set x = GetLocationX(GetUnitLoc(caster)) set y = GetLocationY(GetUnitLoc(caster)) set e2 = AddSpecialEffect("Abilities\\Spells\\Undead\\ReplenishHealth\\ReplenishHealthCasterOverhead.mdl", x, y) call SetUnitLifeBJ( caster, ( GetUnitStateSwap(UNIT_STATE_LIFE, caster) + heal ) ) call GroupClear(udg_RedemptionAuraGroup) call RemoveUnit(u) set u = null call DestroyEffect(e2) call RemoveLocation(l) set l = null endfunction //=========================================================================== function InitTrig_Redemption_Aura takes nothing returns nothing set gg_trg_Redemption_Aura = CreateTrigger( ) call DisableTrigger( gg_trg_Redemption_Aura ) call TriggerRegisterTimerEventPeriodic( gg_trg_Redemption_Aura, 10.00 ) call TriggerAddAction( gg_trg_Redemption_Aura, function Trig_Redemption_Aura_Actions ) endfunction Any suggestions? Thanks ahead of time |
| 09-11-2007, 05:50 PM | #2 |
JASS:function RedemptionAuraDeadCheck takes nothing returns boolean local unit u = GetEnumUnit() return (IsUnitDeadBJ(u)) endfunction That should be GetFilterUnit(), as you're running a conditions check, not performing actions. That should solve your first problem. JASS:local unit u = GroupPickRandomUnit(udg_RedemptionAuraGroup) local real x = GetLocationX(GetUnitLoc(u)) local real y = GetLocationY(GetUnitLoc(u)) There isn't anybody *in* RedemptionAuraGroup yet, so of course x and y are just going to go to 0, because u will be null. Reset u, x, and y after you add the units into RedemptionAuraGroup. And for the future, I would recommend getting away from all those GUI-converted-to-JASS functions and methods of doing things ;). Here's how to properly loop through a group (so that you can use local variables - then you won't need a global RedemptionAuraGroup variable, or all those BJ's). http://www.wc3jass.com/viewtopic.php?t=1998 |
| 09-11-2007, 08:14 PM | #3 |
I made a spell called Redemption Aura once and it appears to do exactly what you're trying to do. If you'd like to view how my spell works to help with yours, here's a link for it: http://www.hiveworkshop.com/forums/s...&postcount=169 Now as for your coding, I have a few suggestions: if IsUnitGroupEmptyBJ(udg_RedemptionAuraGroup) then I would change this line to: if FirstOfGroup(udg_RedemptionAuraGroup) == null then This avoids the BJ function and is the best method I can think of. JASS:local real x = GetLocationX(GetUnitLoc(u)) local real y = GetLocationY(GetUnitLoc(u)) // You're calling many more functions than necessary as well as leaking 2 locations // Here's what you should be doing local real x = GetUnitX(caster) local real y = GetUnitY(caster) call SetWidgetLife(caster, GetWidgetLife(caster) + heal) |
| 09-11-2007, 10:01 PM | #4 |
Ok, I understood all of that and appreciate the help (it's hard to learn JASS from scratch). I'm trying to understand the code that TaintedReality showed me. http://www.wc3jass.com/viewtopic.php?t=1998 The ForGroupBJ command I currently use will take all dead units within 600 of the caster. If I use the system TaintedReality showed me, how do I make it only put dead units within 600 of the caster into udg_RedemptionAuraGroup? Do I just include an 'if' statement in the part labeled JASS: // Actions here... Use u as current unit JASS:if ("unit range is < 600" and IsUnitDeadBJ(u)) then call GroupAddUnitSimple(u, udg_RedemptionAuraGroup) endif |
| 09-12-2007, 12:48 AM | #5 |
You'll need to set a variable equal to the X/Y coordinates you want to compare the distance to, then do this: JASS:set ux = GetUnitX(u) set uy = GetUnitY(u) if (u-ux)*(u-ux)+(y-uy)*(y-uy) > 360000 then //600*600 = 3600; the square the distance you want to compare to. //Do stuff endif |
| 09-12-2007, 02:05 AM | #6 | |
Quote:
Why not only add all units witin 600 of the caster to the temporary group in the first place? Using: JASS:native GroupEnumUnitsInRange takes group whichGroup, real x, real y, real radius, boolexpr filter returns nothing |
| 09-12-2007, 03:01 AM | #7 |
Well, I rewrote the trigger. But every 10 seconds (when the aura 'procs'), the game will freeze for 2 seconds, and Vex's Editor says that my trigger has reached the "op limit". This is my rewritten trigger. JASS:function Trig_Redemption_Aura_Actions takes nothing returns nothing // // Locals // local group redemption = CreateGroup() local group deadredemption = CreateGroup() local unit redeem = null local unit caster = udg_LightBearer local real casterx = GetUnitX(caster) local real castery = GetUnitY(caster) local real redeemx local real redeemy local integer i = GetRandomInt(1,5) local real heal = GetWidgetLife(caster)*0.10 local effect castereffect local effect redeemeffect // // This is the 20% chance to occur // if i > 1 then return endif // // Takes nearby corpses and adds them to 'deadredemption' // call GroupEnumUnitsInRange(redemption, casterx, castery, 600, null) loop set redeem = FirstOfGroup(redemption) exitwhen redeem == null if IsUnitDeadBJ(redeem) then call GroupAddUnitSimple(redeem,deadredemption) call GroupRemoveUnit(redemption,redeem) endif endloop // // If there are any nearby corpses, it heals the caster, and plays the special effects // if (not (FirstOfGroup(deadredemption) == null)) then set castereffect = AddSpecialEffect("Abilities\\Spells\\Undead\\ReplenishHealth\\ReplenishHealthCasterOverhead.mdl", casterx, castery) call DestroyEffect(castereffect) set redeem = FirstOfGroup(deadredemption) set redeemx = GetUnitX(redeem) set redeemy = GetUnitY(redeem) set redeemeffect = AddSpecialEffect("Abilities\\Spells\\Human\\Resurrect\\ResurrectCaster.mdl", redeemx, redeemy) call DestroyEffect(redeemeffect) call SetWidgetLife(caster, GetWidgetLife(caster) + heal) endif call DestroyGroup(redemption) call DestroyGroup(deadredemption) endfunction //=========================================================================== function InitTrig_Redemption_Aura takes nothing returns nothing set gg_trg_Redemption_Aura = CreateTrigger( ) call DisableTrigger( gg_trg_Redemption_Aura ) call TriggerRegisterTimerEventPeriodic( gg_trg_Redemption_Aura, 10.00 ) call TriggerAddAction( gg_trg_Redemption_Aura, function Trig_Redemption_Aura_Actions ) endfunction BTW, what is the op limit, and how do I prevent reaching it? I read a few posts on triggers that are location heavy reaching an op limit, but nothing that was clear. |
| 09-12-2007, 03:15 AM | #8 | |
Haven't looked at the rest, but the first thing that jumped out at me (that's causing you to hit the op limit) is this: JASS:
loop
set redeem = FirstOfGroup(redemption)
exitwhen redeem == null
if IsUnitDeadBJ(redeem) then
call GroupAddUnitSimple(redeem,deadredemption)
call GroupRemoveUnit(redemption,redeem)
endif
endloopIf the unit isn't dead, then it will enter an infinite loop. You set redeem = FirstOfGroup, but then only remove redeem from the group if redeem is dead, and if you don't remove it then next time FirstOfGroup will be the same unit. Just pull that GroupRemoveUnit outside the if statement. Quote:
War3 can only execute so many operations in the same thread without a pause. You usually won't reach it unless looping a very high number of times, in which case you can add a TriggerSleepAction every once and a while, or you can use ExecuteFunc, which starts a new thread. But you don't need to worry about it for this, as fixing that GroupRemoveUnit problem should stop the function from hitting the op limit. |
| 09-12-2007, 03:21 AM | #9 |
Yup, that fixed the problem +rep |
