HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

Redemption Aura

09-11-2007, 05:37 PM#1
Castlemaster
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.
Collapse 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
TaintedReality
Collapse 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.

Collapse 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
wyrmlord
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.
Collapse 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)
In addition, I see you're using the SetUnitLifeBJ function as well as the GetUnitStateSwap function. Just make things easy on yourself and use SetWidgetLife and GetWidgetLife. Here's what it would look like:
call SetWidgetLife(caster, GetWidgetLife(caster) + heal)
09-11-2007, 10:01 PM#4
Castlemaster
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
Collapse JASS:
    // Actions here... Use   u   as current unit
something like this
Collapse JASS:
if ("unit range is < 600" and IsUnitDeadBJ(u)) then   
   call GroupAddUnitSimple(u, udg_RedemptionAuraGroup)
endif
and then from there find out if udg_RedemptionAuraGroup is empty?
09-12-2007, 12:48 AM#5
Pyrogasm
You'll need to set a variable equal to the X/Y coordinates you want to compare the distance to, then do this:
Collapse 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
TaintedReality
Quote:
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

Why not only add all units witin 600 of the caster to the temporary group in the first place? Using:
Collapse JASS:
native GroupEnumUnitsInRange                takes group whichGroup, real x, real y, real radius, boolexpr filter returns nothing
09-12-2007, 03:01 AM#7
Castlemaster
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.
Collapse 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
TaintedReality
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:
Collapse JASS:
    loop
        set redeem = FirstOfGroup(redemption)
        exitwhen redeem == null
       if IsUnitDeadBJ(redeem) then
        call GroupAddUnitSimple(redeem,deadredemption)
        call GroupRemoveUnit(redemption,redeem)
        endif
    endloop

If 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:
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.

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
Castlemaster
Yup, that fixed the problem

+rep