• 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.

[Solved] UnitShareVision

Status
Not open for further replies.
Level 5
Joined
Aug 16, 2010
Messages
97
Hello.
I am making a spell which gives my hero sight of enemy wounded heroes (like
Strygwyr's Thirst in DotA). I use UnitShareVision function to achieve that. But when I attempt to remove the shared vision, it doesn't work and I can still see enemy's hero. What should I do?
Here's the trigger. Thanks in advance.
JASS:
library MySpell requires AutoIndex, TimerUtils

//-------------------------------------------------------------------------------------------
//      Hunter's Instinct
//
//        by Dr.Killer
//
// The Warden uses her unatural instincts to locate wounded enemies.
// Then she chooses one target and gains the ability to become invisible
// when near her target. She can backstab her victim 3 times before revealing
// herself, the last of which deals bonus damage based on Warden's distance
// from her target at the time of casting.
//-------------------------------------------------------------------------------------------

//-------------------------------------------------------------------------------------------
//      Configuration
//-------------------------------------------------------------------------------------------

globals
    private constant integer MAIN_SPELL_ID              =   'A001'
    private constant integer VISION_SPELL_ID            =   'A002'
    private constant integer VISION_SPELL_BUFF          =   'Bfae'
    private constant string  VISION_SPELL_ORDER_STRING  =   "feariefire"     
    private constant integer VISION_SPELL_ORDER_ID      =   852149
    private constant integer DUMMY_ID                   =   'e000'
    
    private constant boolean CONFIG_RANGE               =   false           //Determines whether or not to use a constant value for range
    private constant real    RANGE                      =   99999.
    private constant real    DURATION                   =   8.
endglobals

private function Range takes integer lvl returns real
    return 1000.+I2R(lvl)*200.
endfunction

private function HpThreshold takes integer lvl returns real
    return ((10.+10.*I2R(lvl))/100.)
endfunction

//-------------------------------------------------------------------------------------------
//      End of Configuration
//-------------------------------------------------------------------------------------------

private struct SpellData
    private unit    caster
    private unit    dummy
    private integer lvl
    private group   targets
    private timer   main_timer
    private real    casterX
    private real    casterY
    private boolean success

//-------------------------------------------------------------------------------------------
//      This method runs when spell duration ends; does cleanups, effect removal, etc.
//-------------------------------------------------------------------------------------------
    private static method onFinish takes nothing returns nothing
        local unit      u      = null
        local SpellData object = GetTimerData(GetExpiredTimer())
        
        loop
            set u = FirstOfGroup(object.targets)
            exitwhen u == null
            call IssuePointOrder(u, "move", 0., 0.)
            call UnitShareVision(u, GetOwningPlayer(object.caster), false)
            call GroupRemoveUnit(object.targets, u)
        endloop
        
        call DestroyGroup(object.targets)
    endmethod
    
//-------------------------------------------------------------------------------------------
//      This method sets the needed variables for struct's instance
//-------------------------------------------------------------------------------------------
    private static method onCast takes nothing returns nothing
        local SpellData object          = SpellData.create()
        local group     tempGroup       = CreateGroup()
        local unit      u               = null
        
        set object.targets = CreateGroup()
        set object.caster  = GetTriggerUnit()
        set object.casterX = GetUnitX(object.caster)
        set object.casterY = GetUnitY(object.caster)
        set object.lvl     = GetUnitAbilityLevel(object.caster, MAIN_SPELL_ID)
        call GroupEnumUnitsInRange(tempGroup, object.casterX, object.casterY, RANGE, null)
        call BJDebugMsg("early target count: "+I2S(CountUnitsInGroup(tempGroup)))
        loop
            set u = FirstOfGroup(tempGroup)
            exitwhen u == null
            if (IsUnitType(u, UNIT_TYPE_HERO) and (GetUnitState(u, UNIT_STATE_LIFE) <= (GetUnitState(u, UNIT_STATE_MAX_LIFE)*HpThreshold(object.lvl))) and IsUnitEnemy(u, GetOwningPlayer(object.caster))) then
                call GroupRemoveUnit(tempGroup, u)
                call GroupAddUnit(object.targets, u)
            else
                call GroupRemoveUnit(tempGroup, u)
            endif
        endloop
        call DestroyGroup(tempGroup)
        call object.runSpell()
    endmethod

//-------------------------------------------------------------------------------------------
//      Core method; which actually does the job
//-------------------------------------------------------------------------------------------
    private method runSpell takes nothing returns nothing
        local group tempGroup = CreateGroup()           
        local unit  u         = null
        
        call GroupAddGroup(.targets, tempGroup)
        
        loop
            set u = FirstOfGroup(tempGroup)
            exitwhen u == null
            call UnitShareVision(u, GetOwningPlayer(.caster), true)
            call GroupRemoveUnit(tempGroup, u)
        endloop
        
        set .main_timer = NewTimer()
        call SetTimerData(.main_timer, this)
        call TimerStart(.main_timer, DURATION, false, function thistype.onFinish)
        call DestroyGroup(tempGroup)
        call RemoveUnit(.dummy)
        set .dummy = null
        set .caster = null
    endmethod
        
        /*
        local unit caster           = GetTriggerUnit()
        local real object.casterX   = 0.
        local real object.casterY   = 0.
        local unit dummy            = null
        local integer lvl           = GetUnitAbilityLevel(caster, MAIN_SPELL_ID)
        local group tempGroup       = CreateGroup()
        local group targets         = CreateGroup()
        local timer t               = NewTimer()
        local unit u                = null
        local integer i             = 0
        local integer targetCount   = 0
        local boolean success       = false
        */

    
    private static method castCondition takes nothing returns boolean
        return GetSpellAbilityId() == MAIN_SPELL_ID
    endmethod
    
    private static method onInit takes nothing returns nothing
        local trigger t = CreateTrigger()
        
        call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
        call TriggerAddCondition(t, Condition(function thistype.castCondition))
        call TriggerAddAction(t, function thistype.onCast)
    endmethod

endstruct
endlibrary
 
Level 15
Joined
Jul 6, 2009
Messages
889
JASS:
set .caster = null
call UnitShareVision(u, GetOwningPlayer(object.caster), false)

This is what you're doing. You're nulling the caster before you're using it, so that means you get a null player. Therefore, you're stripping the vision off a null player. You don't need to null struct members as they're going to be used again and again. Globals don't leak like that.

So to answer your question of What should I do?, you should not null .caster in your .runSpell method.
 
Status
Not open for further replies.
Top