HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

Multiple buffs, only want to remove 1 instance

04-21-2009, 07:34 PM#1
marshall
I have a unit that casts Wand of Shadowsight on another unit and gets vision of that unit. I'm starting a timer and when that timer expires I want to lose vision of the unit.
I imagine I can just use 'remove buff' on the unit to take away the shadowsight buff, however I have multiple units that could cast Wand of Shadowsight on the same target. They should all have separate timers and each unit loses sight of the target unit at different times.

Is this possible? How do I say "remove shadowsight buff that was applied by unit X, but leave other shadowsight buffs intact"?

I'm using plain Jass.
04-21-2009, 10:02 PM#2
Anitarf
If your buff is based on faerie fire then there's no way to do it, since buffs of the same type don't stack up. If one player casts faerie fire on a unit and then another player does the same, the first player will loose vision of the unit the moment the second player casts it.

If your buff is entirely triggered (I believe there's a function that gives you shared vision of a unit) then it would be possible, but still tricky since if a buff from one caster wears out you shouldn't take away the vision of there are any buffs from other casters of the same player still going on the unit.
04-22-2009, 03:13 AM#3
cosmicat
Probably the buff is based on Wand of Shadowsight. But the same principle applies.
04-23-2009, 01:03 AM#4
Feroc1ty
Making the spell for you as I write this, will have it done in a few minutes.

EDIT:

I haven't tested it yet, but here's the code, it should work, but a code that hasn't been ran/debugged is doomed to fail.

Collapse JASS:
scope Shadowsight
globals
    private integer SPELL_LENGTH = 120
    private integer SPELL_ID = 'Afae'
    private integer number = 0
    private unit array target [50]
    private player array caster [50]
    private integer array length [50]
endglobals

private function move takes integer n returns nothing
    local integer i = n
    loop
        exitwhen i == number
        set target[i] = target[i+1]
        set caster[i] = caster[i+1]
        set length[i] = length[i+1]
        set i = i + 1
    endloop
    set number = number - 1
endfunction

private function time takes nothing returns nothing
    local integer i = 0
    if number > 0 then
        loop
            if length[i] < 0 then
                call UnitShareVision( target[i], caster[i], false)
                call move(i)
            else
                set length[i] = length[i] - 1
                set i = i + 1
            endif
            exitwhen number == i
        endloop
    endif
endfunction

private function Conditions takes nothing returns boolean
    return GetSpellAbilityId() == SPELL_ID
endfunction

private function Initialize takes nothing returns nothing
    local timer t = CreateTimer()
    call TimerStart( t, 1.00, true, function time)
    set t = null
endfunction

private function Action takes nothing returns nothing
    local unit t = GetSpellTargetUnit()
    local player c = GetOwningPlayer(GetSpellAbilityUnit())
    call UnitShareVision(t, c, true)
    set number = number + 1
    set target[number] = t
    set caster[number] = c
    set length[number] = SPELL_LENGTH
endfunction

//===========================================================================
function InitTrig_Shadowsight takes nothing returns nothing
    set gg_trg_Shadowsight = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( gg_trg_Shadowsight, EVENT_PLAYER_UNIT_SPELL_CHANNEL )
    call TriggerAddCondition( gg_trg_Shadowsight, Condition( function Conditions ) )
    call TriggerAddAction( gg_trg_Shadowsight, function Action )
    call TriggerSleepAction(0)
    call Initialize()
endfunction
endscope

Make sure you put this code into an empty trigger called "Shadowsight"

You'll need to run "Shadowsight_Initialize" at seconds of the game. EDIT: You won't anymore, updated the code so you won't have to do anything, it will just do what it's supposed to, simply change the duration and spell ID to whatever you want.


Just realized, the spell will work for different players, but won't stack, as in if you put it on the same unit again, it won't matter, could be fixed if I used the units UserData, but for one spell it would be a waste.
04-23-2009, 04:07 AM#5
cosmicat
I haven't run it either, but looking at your code...

"Length" is spelled wrong all over the place, but as far as the code is concerned that shouldn't matter as long as the spelling error is consistent throughout (and it looks like it is). I can't really tell, though.

Collapse JASS:
private function move takes integer n returns nothing
    local integer i = n
    loop
        exitwhen n == number
        set target[i] = target[i+1]
        set caster[i] = caster[i+1]
        set lenght[i] = lenght[i+1]
        set i = i + 1
    endloop
    set number = number - 1
endfunction
Shouldn't that be exitwhen i == number? You're not changing the value of n at all (= infinite loop).

Also, instead of checking for whether this is the first time it is run, you could start a short timer in the initialization function that will run the trigger a few seconds after map init.
04-23-2009, 04:55 AM#6
Feroc1ty
Quote:
Originally Posted by cosmicat
I haven't run it either, but looking at your code...

"Length" is spelled wrong all over the place, but as far as the code is concerned that shouldn't matter as long as the spelling error is consistent throughout (and it looks like it is). I can't really tell, though.

Collapse JASS:
private function move takes integer n returns nothing
    local integer i = n
    loop
        exitwhen n == number
        set target[i] = target[i+1]
        set caster[i] = caster[i+1]
        set lenght[i] = lenght[i+1]
        set i = i + 1
    endloop
    set number = number - 1
endfunction
Shouldn't that be exitwhen i == number? You're not changing the value of n at all (= infinite loop).

Also, instead of checking for whether this is the first time it is run, you could start a short timer in the initialization function that will run the trigger a few seconds after map init.

Thanks for noticing the loop, that's fixed, replaced old method with TSA and initialization call, and fixed the spelling errors(it was a consistent mistake :])

And I thought you couldn't start timers at initialization, is that true, or was I just limiting myself for no reason.
04-23-2009, 07:08 PM#7
marshall
Thanks guys, your help is much appreciated.
Something I've realised I need to do is to have a dummy unit cast the spell on a dead hero, which of course isn't possible. I think I'm gonna go for a simplified version, and just trigger the on/off of UnitShareVision (thanks btw, didn't know about that) and forget about having a visible buff.