• Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
  • Read Evilhog's interview with Gregory Alper, the original composer of the music for WarCraft: Orcs & Humans 🔗Click here to read the full interview.

[JASS] pre-spelleffect Check isn't preventing Cast

Status
Not open for further replies.
Level 14
Joined
Jul 26, 2008
Messages
1,009
So it seems fairly common to add your own preventative cast conditions. You know, if the Unit is casting a spell on an area and there's certain regions you don't want cast in. You use UNIT_SPELL_CAST and if the conditions are failed then you order the unit to stop, thus preventing the effects and mana consumption.

Well I've got that set up but the unit is still going through with their actions! The SimError shows up, so I know they're firing. The unit just isn't stopping!

I have a casting time and a cooldown just to make sure the spell has a decent window to stop the cast, but that's not working either.

I've been over the trigger a few times and can't find a problem, perhaps someone else could check it again for me. If it's not in the trigger, then suggestions on what else it might be would also help :)

Another weird bug is that the new unit's damage is suppose to increase based on the abilitylevel, but every cast increases the damage by 1. So after casting this spell 30 times the new unit summoned has +31 damage.

Uses: UnitProperty, SimError, GroupUtils
JASS:
scope Swarm initializer init

globals
    private constant integer SPELLID        = 'Swar'
    private constant real AREA              = 600
    private constant string ERROR           ="Must target a non-Hero corpse."
    integer array SwarmMax
    boolean array ScarabConsumption
endglobals

private function FilterConditions takes nothing returns boolean
    return IsUnitType(GetFilterUnit(),UNIT_TYPE_DEAD) and not(IsUnitType(GetFilterUnit(), UNIT_TYPE_STRUCTURE) or IsUnitType(GetFilterUnit(), UNIT_TYPE_HERO))
endfunction

private function CheckConditions takes nothing returns boolean
    local unit c = GetTriggerUnit()
    local real x = GetUnitX(c)
    local real y = GetUnitY(c)
    local integer id = GetPlayerId(GetOwningPlayer(c))
    local integer lvl = GetUnitAbilityLevel(c, SPELLID)
    local integer max = 4+3*lvl
    local group g = CreateGroup()
    if GetSpellAbilityId() == SPELLID then
        if SwarmMax[id] < max then //Checks to make sure you don't have the Max allowed Scarabs. Similar to Nerubian's Carrion Beetles.
            call GroupEnumUnitsInArea(g, x, y, AREA, Filter(function FilterConditions))//Groups nearby dead and not a structore or hero units
            debug call BJDebugMsg(GetUnitName(FirstOfGroup(g)))
            if FirstOfGroup(g) == null then //Make sure there is one
                call IssuePointOrder( c, "move", GetUnitX(c), GetUnitY(c) ) //Prevents the cast
                call SimError( Player(id), ERROR )
            endif
        else
            call IssuePointOrder( c, "move", GetUnitX(c), GetUnitY(c) )
            call SimError( Player(id), "You have " + I2S(SwarmMax[id]) + " scarab(s), which is your max limit.")
        endif
    endif
    call DestroyGroup(g)
    set g = null
    set c = null
 return false
endfunction

private function Actions takes unit c, unit old, unit new returns nothing
 local integer lvl = GetUnitAbilityLevel(c, SPELLID)
 local real x = GetUnitX(c)
 local real y = GetUnitY(c)
 local group g = NewGroup()
    call GroupEnumUnitsInArea(g, x, y, AREA, Filter(function FilterConditions))
    set old = FirstOfGroup(g)
    if GetRandomInt(1,4) == 1 then
        set new = CreateUnit( GetOwningPlayer(c), 'gosc', GetUnitX(old), GetUnitY(old), GetUnitFacing(old) )
        call SetUnitMoveSpeed(new, GetUnitDefaultMoveSpeed(c)-20)
    else
        set new = CreateUnit( GetOwningPlayer(c), 'swar', GetUnitX(old), GetUnitY(old), GetUnitFacing(old) )
        call SetUnitMoveSpeed(new, GetUnitDefaultMoveSpeed(c)+10)
    endif
    set SwarmMax[GetPlayerId(GetOwningPlayer(c))] = SwarmMax[GetPlayerId(GetOwningPlayer(c))] + 1
    //INSERT GROWTH AND STATBOOSTS HERE
    call UnitModifyDamage(new,lvl-1)//To be honest this isn't a big deal to me
    call RemoveUnit(old)
    call SetUnitAnimation(new, "birth")
    call DestroyEffect(AddSpecialEffect( GetAbilityEffectById(SPELLID, EFFECT_TYPE_SPECIAL, 0), x, y ) )
 call GroupClear(g)
 call ReleaseGroup(g)
endfunction

private function Conditions takes nothing returns boolean
    if GetSpellAbilityId() == SPELLID then
        call Actions(GetTriggerUnit(), null, null)
    endif
 return false
endfunction

//===========================================================================
public function init takes nothing returns nothing
 local trigger array t
    set t[0] = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ( t[0], EVENT_PLAYER_UNIT_SPELL_CAST ) //The Pre-Effect casting check
    call TriggerAddCondition( t[0], function CheckConditions )
    set t[1] = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ( t[1], EVENT_PLAYER_UNIT_SPELL_EFFECT )//The cast check
    call TriggerAddCondition( t[1], function Conditions )
    call XE_PreloadAbility(SPELLID)
endfunction

endscope
 
Last edited:
Level 26
Joined
Aug 18, 2009
Messages
4,099
You start your CheckActions-function by executing, thus it gets an individual thread and event responses like GetTriggerUnit() are no longer reserved.

I do not know about UnitModifyDamage but from your statement I would guess that the bonus is saved and you maybe do not clean up after a unit vanishes, leaving a preset value for the next unit that gets the same id or that the units all get the same index. Do some debugs.
 
Level 14
Joined
Jul 26, 2008
Messages
1,009
Actually ...
http://www.hiveworkshop.com/forums/1786456-post13.html

I believe Bribe, he's quiet the expert on these things. But I would understand your logic of reasoning. The function seems to work though despite the ExecuteFunc. Though I've removed it in the newest update.

Fortunately the bonuses have sort of fixed themselves, though... I'm not sure of that yet. I still need to test. I'll do some debugs if it doesn't stabalize.
 
Level 14
Joined
Nov 18, 2007
Messages
1,084
You start your CheckActions-function by executing, thus it gets an individual thread and event responses like GetTriggerUnit() are no longer reserved.
It's because CheckActions was private which changes how the function is named.

You should only use ExecuteFunc if the function you're trying to call is below that function or you're trying to use TriggerSleepAction instead of timers.
Also, you could just do everything inside Conditions instead of calling another function.

BTW, you don't need local group g. Just use ENUM_GROUP. You don't have to worry about destroying ENUM_GROUP.
 
Level 14
Joined
Jul 26, 2008
Messages
1,009
Gotcha. Thanks watermelon.

However, this new version still isn't preventing the cast via "move" order:
JASS:
scope Swarm initializer init

globals
    private constant integer SPELLID        = 'Swar'
    private constant real AREA              = 600
    private constant string ERROR           ="Must have a nearby non-Hero corpse."
    integer array SwarmMax
    boolean array ScarabConsumption
endglobals

private function FilterConditions takes nothing returns boolean
    return IsUnitType(GetFilterUnit(),UNIT_TYPE_DEAD) and not(IsUnitType(GetFilterUnit(), UNIT_TYPE_STRUCTURE) or IsUnitType(GetFilterUnit(), UNIT_TYPE_HERO))
endfunction

private function CheckConditions takes nothing returns boolean
    local unit c = GetTriggerUnit()
    local real x = GetUnitX(c)
    local real y = GetUnitY(c)
    local integer id = GetPlayerId(GetOwningPlayer(c))
    local integer lvl = GetUnitAbilityLevel(c, SPELLID)
    local integer max = 4+3*lvl
    if GetSpellAbilityId() == SPELLID then
        if SwarmMax[id] < max then //Checks to make sure you don't have the Max allowed Scarabs. Similar to Nerubian's Carrion Beetles.
            call GroupEnumUnitsInArea(ENUM_GROUP, x, y, AREA, Filter(function FilterConditions))//Groups nearby dead and not a structore or hero units
            if FirstOfGroup(ENUM_GROUP) == null then //Make sure there is one
                call IssuePointOrder( c, "move", GetUnitX(c), GetUnitY(c) ) //Prevents the cast
                call SimError( Player(id), ERROR )
            endif
        else
            call IssuePointOrder( c, "move", GetUnitX(c), GetUnitY(c) )
            call SimError( Player(id), "You have " + I2S(SwarmMax[id]) + " scarab(s), which is your max limit.")
        endif
    endif
    set c = null
 return false
endfunction

private function Actions takes unit c, unit old, unit new returns nothing
 local integer lvl = GetUnitAbilityLevel(c, SPELLID)
 local real x = GetUnitX(c)
 local real y = GetUnitY(c)
    call GroupEnumUnitsInArea(ENUM_GROUP, x, y, AREA, Filter(function FilterConditions))
    set old = FirstOfGroup(ENUM_GROUP)
    if GetRandomInt(1,4) == 1 then
        set new = CreateUnit( GetOwningPlayer(c), 'gosc', GetUnitX(old), GetUnitY(old), GetUnitFacing(old) )
        call SetUnitMoveSpeed(new, GetUnitDefaultMoveSpeed(c)-20)
    else
        set new = CreateUnit( GetOwningPlayer(c), 'swar', GetUnitX(old), GetUnitY(old), GetUnitFacing(old) )
        call SetUnitMoveSpeed(new, GetUnitDefaultMoveSpeed(c)+10)
    endif
    set SwarmMax[GetPlayerId(GetOwningPlayer(c))] = SwarmMax[GetPlayerId(GetOwningPlayer(c))] + 1
    //INSERT GROWTH AND STATBOOSTS HERE
    call UnitModifyDamage(new,lvl-1)//To be honest this isn't a big deal to me
    call RemoveUnit(old)
    call SetUnitAnimation(new, "birth")
    call DestroyEffect(AddSpecialEffect( GetAbilityEffectById(SPELLID, EFFECT_TYPE_SPECIAL, 0), x, y ) )
endfunction

private function Conditions takes nothing returns boolean
    if GetSpellAbilityId() == SPELLID then
        call Actions(GetTriggerUnit(), null, null)
    endif
 return false
endfunction

//===========================================================================
public function init takes nothing returns nothing
 local trigger array t
    set t[0] = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ( t[0], EVENT_PLAYER_UNIT_SPELL_CAST ) //The Pre-Effect casting check
    call TriggerAddCondition( t[0], function CheckConditions )
    set t[1] = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ( t[1], EVENT_PLAYER_UNIT_SPELL_EFFECT )//The cast check
    call TriggerAddCondition( t[1], function Conditions )
    call XE_PreloadAbility(SPELLID)
endfunction

endscope
 
Level 26
Joined
Aug 18, 2009
Messages
4,099
Actually ...
http://www.hiveworkshop.com/forums/1786456-post13.html

I believe Bribe, he's quiet the expert on these things.

From fast tests I can confirm that it is this way, that responses are transfered to executed threads. Learnt a new thing. This could be useful if you wanted to redirect to dynamic code and you are not sure about which responses exist.

watermelon is right, too, with private changing the function name. Earlier, when you specified a non-existing function name in ExecuteFunc, it would cause a crash. But this seems to have been fixed within the last patches.

edit: Is the unit able to move? Does the IssueOrder-action return true? Does the unit have a casting animation time?
 
Level 40
Joined
Dec 14, 2005
Messages
10,532
Actually ...
http://www.hiveworkshop.com/forums/1786456-post13.html

I believe Bribe, he's quiet the expert on these things. But I would understand your logic of reasoning. The function seems to work though despite the ExecuteFunc. Though I've removed it in the newest update.

Fortunately the bonuses have sort of fixed themselves, though... I'm not sure of that yet. I still need to test. I'll do some debugs if it doesn't stabalize.
Don't get in the habit of doing that though since there are several ways to start threads and their behaviour is inconsistent (notably, Timers).
 
Status
Not open for further replies.
Top