• 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.
  • The Hive's 22nd Icon Contest: Creep Abilities is now concluded, time to vote for your favourite set of icons! Click here to vote!
  • ✅ The POLL for Hive's Texturing Contest #34 is OPEN! Vote for the TOP 3 SKINS! 🔗Click here to cast your vote!
  • ✅ The POLL for Hive's Techtree Contest #20 is OPEN! Vote for the TOP 3 FACTIONS! 🔗Click here to cast your vote!

Finger of Death dummy spell returns null

Status
Not open for further replies.
Level 13
Joined
Mar 24, 2010
Messages
950
I am using Finger of Death for my dummy spell and i need the trigger reactions to happen after the spell is done being casted.

Unfortunately when i try and reference the target unit of ability being cast it returns null, so the ability doesnt work. it does fully work when i use begins casting an ability but i have to use waits becuz of the long cast time (even tho its set to 0) and it is making things messy when i have to use waits.

can anyone help me with this problem, keep in mind it has to be Finger of Death because it needs to be an ulti and i want it to target spell immune units etc.
 
I have same problems with some spells ago, even putting the unit into a variable directly does not work, the way I used was I added the target unit into a unit group and then pick it from the group (it will be the only unit inside the group) then set it to a variable...

you should do this with the event Starts the effect on an ability... then just use that variable afterwards... though this wont be MUI, if you want it to be MUI you can use timers + hashtables or indexing systems
 
whats the point if i use channel or figure of death.. the trigger wont pick up the target unit of casted ability when responding to "finishes casting an ability" so unless i have another trigger that saves the unit to the var when the ability starts casting but that can get messy and dont wanna do it that way.. :/ wont be perfectly MUI then..
 
whats the point if i use channel or figure of death.. the trigger wont pick up the target unit of casted ability when responding to "finishes casting an ability" so unless i have another trigger that saves the unit to the var when the ability starts casting but that can get messy and dont wanna do it that way.. :/ wont be perfectly MUI then..

it can be MUI, you can use a normal hashtable for MUI though maybe not SUI but since the spell has cooldown (I hope) it does not need to be SUI... or if you can, you can use hashtable loops or indexing systems to make if MUI and SUI...

what I mean with normal hashtables is that you save the target to a hashtable tat uses the HandleId of the casting unit as a parent while the hashtable loops are similar to indexing though it uses hashtables...
 
i found a easy way around the glitch i was having with leaving it how i had it before now so its good.

But on a side note i havent really messed around with hashtables much since the new patch that introduced them becuz i had no need yet, would be cool if ya showed an example of what your describing if its not too much work. :) might implement stuff with it if it looks more efficient.

also +rep but it wont let me again to you yet for some reason
 
for example of a normal hashtable use for that spell, first be sure to create a hashtable.. NOTE: JNGP seems to still have problems with Key - Handle Id in hashtables so use the normal WE...


  • Events
    • Map Initialization
  • Actions
    • Hahstable - Create A Hashtable
    • Set FODHASH = LastCreatedHashtable

  • OnCast
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
      • Ability being cast is equal to FingerofDeath
    • Actions
      • Hashtable - Save Handle of TargetUnitOfAbilityBeingCast as Key Target of Key TriggeringUnit in FODHASH
      • Hashtable - Save timebeforedamageisdealt as Key Time of Key TriggeringUnit in FODHASH
      • Hashtable - Save damage as Key Damage of Key TriggeringUnit in FODHASH
      • Unit Group - Add TriggeringUnit to FODGROUP

  • Events
    • Time - Every .03 seconds of game time
  • Actions
    • UnitGroup - Pick every unit in FODGROUP and do
      • Actions
        • Set Time = Load Key Time of Key PickedUnit in FODHASH
        • if - Conditions
          • Time is greater than 0
        • then - Actions
          • Hashtable - Save (Time - .03) as Key Time of Key PickedUnit in FODHASH
        • else - Actions
          • Unit - Cause PickedUnit to damage Load Key Target of Key PickedUnit in FODHASH, dealing Load Key Damage of Key PickedUnit in FODHASH
          • Unit Group - Remove Picked unit from FODGROUP
          • Hashtable - Clear all child hashtables of child Key PickedUnit in FODHASH


Key TriggeringUnit and Key pickedUnit are of the Key GetHandleId
while the other keys are of Key Get String Id... This code may contain errors, its just an example and havent tested...
 
you can use the SpellEvent system

SpellEvent.TargetUnit should work flawlessly...
JASS:
library SpellEvent initializer Init requires Table

//*****************************************************************
//*  SPELL EVENT LIBRARY 1.1
//*
//*  written by: Anitarf
//*  requires: -Table
//*
//*  Maps with many triggered spells require many triggers that run
//*  on spell events and whenever a spell is cast, all those
//*  triggers need to be evaluated by the game even though only one
//*  actually needs to run. This library has been written to reduce
//*  the number of triggers in such maps; instead of having a
//*  trigger per spell, you can use this library's single trigger
//*  to only run the code associated with the spell that's actually
//*  being cast.
//*
//*  Perhaps more significant than the marginal speed gain is the
//*  feature that allows you to access all the spell event
//*  responses from all spell events, something that the native
//*  functions senselessly do not support. With this system you can
//*  for example easily get the target unit of the spell on the
//*  casting finish event.
//*
//*  All functions following the Response function interface that
//*  is defined at the start of this library can be used to respond
//*  to damage events. Simply put them on the call list for any of
//*  the spell events using the appropriate function:
//*
//*    function RegisterSpellChannelResponse takes integer spellId, Response r returns nothing
//*    function RegisterSpellCastResponse takes integer spellId, Response r returns nothing
//*    function RegisterSpellEffectResponse takes integer spellId, Response r returns nothing
//*    function RegisterSpellFinishResponse takes integer spellId, Response r returns nothing
//*    function RegisterSpellEndCastResponse takes integer spellId, Response r returns nothing
//*
//*  The first event occurs at the very start of the spell, when
//*  the spell's casting time begins; most spells have 0 casting
//*  time, so in most cases this first event occurs at the same
//*  time as the second one, which runs when the unit actually
//*  begins casting a spell by starting it's spell animation. The
//*  third event occurs when the spell effect actually takes place,
//*  which happens sometime into the unit's spell animation
//*  depending on the unit's Animation - Cast Point property.
//*  The fourth event runs if the unit finishes casting the spell
//*  uninterrupted, which might be important for channeling spells.
//*  The last event runs when the unit stops casting the spell,
//*  regardless of whether it finished casting or was interrupted.
//*
//*  If you specify a spell id when registering a function then
//*  that function will only run when that ability is cast; only
//*  one function per ability per event is supported, if you
//*  register more functions then only the last one registered will
//*  be called. If, however, you pass 0 as the ability id parameter
//*  then the registered function will run for all spells. Up to
//*  8190 functions can be registered this way for each event.
//*  These functions will be called before the ability's specific
//*  function in the order they were registered.
//*
//*  This library provides it's own event responses that work
//*  better than the Blizzard's bugged native cast event responses.
//*  They still aren't guaranteed to work after a wait, but aside
//*  from that they will work in response functions no matter what
//*  event they are registered to.
//*
//*  Here are usage examples for all event responses:
//*
//*    local integer a = SpellEvent.AbilityId
//*    local unit u = SpellEvent.CastingUnit
//*    local unit t = SpellEvent.TargetUnit
//*    local item i = SpellEvent.TargetItem
//*    local destructable d = SpellEvent.TargetDestructable
//*    local location l = SpellEvent.TargetLoc
//*    local real x = SpellEvent.TargetX
//*    local real y = SpellEvent.TargetY
//*    local boolean b = SpellEvent.CastFinished
//*
//*  SpellEvent.TargetLoc is provided for odd people who insist on
//*  using locations, note that if you use it you have to cleanup
//*  the returned location yourself.
//*
//*  SpellEvent.CastFinished boolean is intended only for the
//*  EndCast event as it tells you whether the spell finished or
//*  was interrupted.
//*
//*  Note that a few spells such as Berserk and Wind Walk behave
//*  somewhat differently from regular spells: they are cast
//*  instantly without regard for cast animation times, they do not
//*  interrupt the unit's current order, as well as any spell it
//*  may be casting. SpellEvent can now handle such spells without
//*  errors provided they are truly instant (without casting time).
//*
//*****************************************************************

    // use the RegisterSpell*Response functions to add spell event responses to the library
    public function interface Response takes nothing returns nothing

// ================================================================

    private keyword casterTable
    private keyword effectDone
    private keyword init
    private keyword get

    private struct spellEvent
        static HandleTable casterTable
        boolean effectDone=false

        integer AbilityId
        unit CastingUnit
        unit TargetUnit
        item TargetItem=null
        destructable TargetDestructable=null
        real TargetX=0.0
        real TargetY=0.0
        boolean CastFinished=false
        
        private spellEvent interrupt

        method operator TargetLoc takes nothing returns location
            return Location(.TargetX, .TargetY)
        endmethod
        
        private static method create takes nothing returns spellEvent
            return spellEvent.allocate()
        endmethod
        static method init takes nothing returns spellEvent
            local spellEvent s=spellEvent.allocate()
            set s.AbilityId = GetSpellAbilityId()
            set s.CastingUnit = GetTriggerUnit()
            set s.TargetUnit = GetSpellTargetUnit()
            if s.TargetUnit != null then
                set s.TargetX = GetUnitX(s.TargetUnit)
                set s.TargetY = GetUnitY(s.TargetUnit)
            else
                set s.TargetDestructable = GetSpellTargetDestructable()
                if s.TargetDestructable != null then
                    set s.TargetX = GetDestructableX(s.TargetDestructable)
                    set s.TargetY = GetDestructableY(s.TargetDestructable)
                else
                    set s.TargetItem = GetSpellTargetItem()
                    if s.TargetItem != null then
                        set s.TargetX = GetItemX(s.TargetItem)
                        set s.TargetY = GetItemY(s.TargetItem)
                    else
                        set s.TargetX = GetSpellTargetX()
                        set s.TargetY = GetSpellTargetY()
                    endif
                endif
            endif
            set s.interrupt=spellEvent.casterTable[s.CastingUnit]
            set spellEvent.casterTable[s.CastingUnit]=integer(s)
            return s
        endmethod
        static method get takes unit caster returns spellEvent
            return spellEvent(spellEvent.casterTable[caster])
        endmethod
        method onDestroy takes nothing returns nothing
            if .interrupt==0 then
                call spellEvent.casterTable.flush(.CastingUnit)
            else
                set spellEvent.casterTable[.CastingUnit]=.interrupt
            endif
            set .CastingUnit=null
        endmethod
    endstruct
    
    globals
        spellEvent SpellEvent=0
    endglobals
    
// ================================================================

    //! textmacro spellEvent_make takes name
    globals
        private Response array $name$CallList
        private integer $name$CallCount=0
        private Table $name$Table
    endglobals

    private function $name$Calls takes nothing returns nothing
        local integer i=0
        local integer id=GetSpellAbilityId()
        local spellEvent previous=SpellEvent
        set SpellEvent=spellEvent.get(GetTriggerUnit())
        loop
            exitwhen i>=$name$CallCount
            call $name$CallList[i].evaluate()
            set i=i+1
        endloop
        if $name$Table.exists(id) then
            call Response($name$Table[id]).evaluate()
        endif
        set SpellEvent=previous
    endfunction

    function RegisterSpell$name$Response takes integer spellId, Response r returns nothing
        if spellId==0 then
            set $name$CallList[$name$CallCount]=r
            set $name$CallCount=$name$CallCount+1
        else
            set $name$Table[spellId]=integer(r)
        endif
    endfunction
    //! endtextmacro

    //! runtextmacro spellEvent_make("Channel")
    //! runtextmacro spellEvent_make("Cast")
    //! runtextmacro spellEvent_make("Effect")
    //! runtextmacro spellEvent_make("Finish")
    //! runtextmacro spellEvent_make("EndCast")

    private function Channel takes nothing returns nothing
        call spellEvent.init()
        call ChannelCalls()
    endfunction
    private function Cast takes nothing returns nothing
        call CastCalls()
    endfunction
    private function Effect takes nothing returns nothing
        local spellEvent s=spellEvent.get(GetTriggerUnit())
        if s!=0 and not s.effectDone then
            set s.effectDone=true
            call EffectCalls()
        endif
    endfunction
    private function Finish takes nothing returns nothing
        set spellEvent.get(GetTriggerUnit()).CastFinished=true
        call FinishCalls()
    endfunction
    private function EndCast takes nothing returns nothing
        call EndCastCalls()
        call spellEvent.get(GetTriggerUnit()).destroy()
    endfunction

// ================================================================

    private function InitTrigger takes playerunitevent e, code c returns nothing
        local trigger t=CreateTrigger()
        call TriggerRegisterAnyUnitEventBJ( t, e )
        call TriggerAddAction(t, c)
        set t=null
    endfunction
    private function Init takes nothing returns nothing
        set spellEvent.casterTable=HandleTable.create()
        set ChannelTable=Table.create()
        set CastTable=Table.create()
        set EffectTable=Table.create()
        set FinishTable=Table.create()
        set EndCastTable=Table.create()
        call InitTrigger(EVENT_PLAYER_UNIT_SPELL_CHANNEL, function Channel)
        call InitTrigger(EVENT_PLAYER_UNIT_SPELL_CAST, function Cast)
        call InitTrigger(EVENT_PLAYER_UNIT_SPELL_EFFECT, function Effect)
        call InitTrigger(EVENT_PLAYER_UNIT_SPELL_FINISH, function Finish)
        call InitTrigger(EVENT_PLAYER_UNIT_SPELL_ENDCAST, function EndCast)
    endfunction

endlibrary

edit: if you want a quick example of how to use the system, post your spell(no gui, use convert to custom text if you have to) and i'll modify it for you.
edit2: whoops that first library was the old one...replaced with newest version.
 
Status
Not open for further replies.
Back
Top