Spell This is my first custom hero

roXplosive

New Member
Reaction score
15
I will start off by posting the extended tooltip of my hero :

The sole surviver from her batalion at the battle for the World Tree she recovered with the help of Furion and is now ready to assist the Sentinel against the defiling Scourge . She is adept of transmiting her pain to the enemies , attacking from afar and avenging her fallen comrades .

-----------------------HERE IS THE MAP --------------------------
Latest version here :
View attachment 32539
Changes :
- added special effects
- swapped to vJass
- limited number of Spellbinding arrow areas
- added a variable for blood hatred life regeneration
- removed a bug in programming
- added a GUI trigger (to have one of those too if you were wondering )

All right now I will gie some skill descriptions and what they should do . I think my tooltips are relevant enough but in any case :

1. Avenging Wrath (is highly customizable) - based off Channel .Sends out a number of spirits x spellLVL (chosen 8) on a N spikes star (chosen 7) that require 3 HP to summon each and each heals 6HP when it hits an enemy . Maximum heal is twice the life cost for casting the spell .

Initializer for variables used for faster computation




JASS:

globals
 trigger gg_trg_Startup
 real Arc1Angle
 real Arc2Angle
 real Arc3Angle
 real ArcRadius
 real array Arcs1Start[100]
 real array Arcs2Start[100]
 real array Arcs3Start[100]
 real array InnerCircleCentersX[100]
 real array InnerCircleCentersY[100]
 real array OuterCircleCentersX[100]
 real array OuterCircleCentersY[100]
 real ArcVariationOnTimer
 real AvengingWrathAoE=600.00
 integer AvengingWrathDuration=5       
 integer HealingFactor=2                //how much can AvengingWrath heal compared to it's life cost
 integer Spirits = 8                    //number of summoned spirits increases with skillevel
 integer StarEdges = 7                  //number of directions in which spirits will travel
 real SummoningDamage = 3               //life cost for summoning an avenging spirit
 integer Temporizator = 10              //determines how often do spirits move every second
 string WispAnimation = "Abilities\\Spells\\Human\\Invisibility\\InvisibilityTarget.mdl" 
 //what special effect plays when spirits hit an enemy
 //alternative effect "Abilities\\Spells\\Human\\HolyBolt\\HolyBoltSpecialArt.mdl"
endglobals


scope Startup initializer InitTrig_Startup

function Trig_Startup_Actions takes nothing returns nothing

//local ariable for how much the arcs should be rotated;startup angle so that my image has an edge facing upwards
local real StarAngle
local real StartAngle
local integer A
//The dummy units will be displayed on the points delimited by global and local variables but will be relatie to current caster position

//call BJDebugMsg("Startup Initialising globalvars ")

set StarAngle=2*bj_PI/I2R(StarEdges)

//call BJDebugMsg("StarAngle="+R2S(StarAngle)+"rad")

set StartAngle=3*bj_PI/2.00

//call BJDebugMsg("StartAngle="+R2S(StartAngle)+"rad")

set ArcRadius=AvengingWrathAoE/SquareRoot(2*(1+Cos(StarAngle)))

//call BJDebugMsg("Trajectory radius="+R2S(ArcRadius)+"distance")

//Arc1Angle is the center angle of the first arc 2*STarAngle+2*(PI-StarAngle)/2
// Since Arc2Angle is the center angle it is twice the angle doing the same arc but with the edge on the circle 

set Arc2Angle=Acos(1-2*Sin(StarAngle)*Sin(StarAngle))
set Arc1Angle=bj_PI+Arc2Angle/2
set Arc3Angle=Arc1Angle

set A=1
loop

//the points determining the centers of triangles inscribed in the AoE with 2 points on the edge and 1 in the center
//Using the definition of Cos in 1 triangle we can determine the length of the median line starting from the center point
// it is R*cos(alpha/2) where aplha is the angle of the triangle for the point which is the AoE center
// and the denter of the circumcised circle is a 2/3 median distance from a triangle's edges
set InnerCircleCentersX[A]=ArcRadius*Cos(StartAngle+StarAngle*A-StarAngle/2)
set InnerCircleCentersY[A]=ArcRadius*Sin(StartAngle+StarAngle*A-StarAngle/2)

//call BJDebugMsg("Center of Inner Circle "+I2S(A)+" X= "+R2S(InnerCircleCentersX[A])+" Y= "+R2S(InnerCircleCentersY[A]))

//The center points of the simmetrical triangles is well the double of the previous alues

set OuterCircleCentersX[A]=(2*AvengingWrathAoE*Cos(StarAngle/2)-ArcRadius)*Cos(StartAngle+StarAngle*A-StarAngle/2)
set OuterCircleCentersY[A]=(2*AvengingWrathAoE*Cos(StarAngle/2)-ArcRadius)*Sin(StartAngle+StarAngle*A-StarAngle/2)

//The acrs for the first drawing are the reverse of the arc between center and inner circles

set Arcs1Start[A]=StartAngle+StarAngle*A-StarAngle/2-bj_PI

//call BJDebugMsg("Starting angle for the first arc of position "+I2S(A)+" is "+R2S(Arcs1Start[A]*180/bj_PI))

//the arcs for the second drawing are similar but there is an extra -1/2 StarAngle

set Arcs2Start[A]=StartAngle+StarAngle*A-StarAngle/2-bj_PI+Arc2Angle/2

//the arcs for the third line start from the end position of the first drawn arc==StarAngle+PI

set Arcs3Start[A]=StartAngle+StarAngle*A-StarAngle/2+Arc2Angle/2

set A=A+1

exitwhen A>StarEdges
endloop
//I'm too lazy to use IF and I think this will make it easy on the code since if will be applied 1 time only
set InnerCircleCentersX[A]=InnerCircleCentersX[1]
set InnerCircleCentersY[A]=InnerCircleCentersY[1]
set OuterCircleCentersX[A]=OuterCircleCentersX[1]
set OuterCircleCentersY[A]=OuterCircleCentersY[1]
set Arcs1Start[A]=Arcs1Start[1]
set Arcs2Start[A]=Arcs2Start[1]
set Arcs3Start[A]=Arcs3Start[1]

set ArcVariationOnTimer=(Arc1Angle+Arc2Angle+Arc3Angle)/I2R(AvengingWrathDuration*Temporizator)

//call BJDebugMsg("Startup init ends")

endfunction

//===========================================================================
function InitTrig_Startup takes nothing returns nothing
    set gg_trg_Startup = CreateTrigger(  )
    //call BJDebugMsg("Startup called")
    call TriggerAddAction( gg_trg_Startup, function Trig_Startup_Actions )
endfunction

endscope //Startup

scope AvengingWrath initializer InitTrig_Avenging_Wrath

function Trig_Avenging_Wrath_Conditions takes nothing returns boolean
   return GetSpellAbilityId() == 'A000' 
endfunction

function AvengingWrathDamage takes unit u , unit caster , real HealedMAX returns real Remaining_heal
local group g = CreateGroup()
local location l=GetUnitLoc(u)
local unit un
local real caster_life
local real life_bonus=0

//call BJDebugMsg("AvengingWrathDamage starts")

set g = GetUnitsInRangeOfLocAll(50,l)
loop
set un=FirstOfGroup(g)
if un!=null and (not IsUnitAlly(un,GetOwningPlayer(caster))) and GetUnitState(un,UNIT_STATE_LIFE)>0 then
    call UnitDamageTarget(u,un,30,false,false,ATTACK_TYPE_MAGIC,DAMAGE_TYPE_MAGIC,WEAPON_TYPE_WHOKNOWS)
    call DestroyEffect( AddSpecialEffectTargetUnitBJ( "overhead", un , WispAnimation ))
    set life_bonus=life_bonus+SummoningDamage*HealingFactor
endif
call GroupRemoveUnit(g,un)
exitwhen un==null
endloop

call RemoveLocation(l)
call RemoveUnit(un)
call DestroyGroup(g)
set l=null
set un=null

//call BJDebugMsg("AengingWrathDmg ends")

//for each enemy struck the caster gains life
set caster_life=GetUnitState(caster,UNIT_STATE_LIFE)
//call BJDebugMsg("caster_life= " + R2S(caster_life))
if life_bonus<HealedMAX then
call SetUnitLifeBJ(caster,caster_life+life_bonus)
return HealedMAX-life_bonus
else
call SetUnitLifeBJ(caster,caster_life+HealedMAX)
return 0.00
endif
return 0.00
//return how much life can still be healed
endfunction

function Trig_Avenging_Wrath_Actions takes nothing returns nothing

local unit array spirits
local integer i
local integer j
local integer k
local integer d1
local integer d2
local unit    u=GetTriggerUnit()
local integer lvl=GetUnitAbilityLevel(u,'A000')
local integer SS=Spirits*lvl //SS stands for summonedspirits
local integer iterations=AvengingWrathDuration*Temporizator
local real     X
local real     Y
local real     HealedMAX
//Temporizator is how many breaks should be in this thread during 1 second

//call BJDebugMsg("AvengingWrathActions Starts")
//call BJDebugMsg("Spirits for summoning : "+I2S(SS))

//debug action:
//set k=1
//set X=GetUnitX(u)
//set Y=GetUnitY(u)
//loop
//call CreateUnit(Player(11),'e000',X+InnerCircleCentersX[k],Y+InnerCircleCentersY[k],0)
//call CreateUnit(Player(11),'e000',X+OuterCircleCentersX[k],Y+OuterCircleCentersY[k],0)
//set k=k+1
//exitwhen k>StarEdges
//endloop



set i=1
// sets the maximum healing according to the damage taken when summoning and healing factor
set HealedMAX=lvl*SummoningDamage*StarEdges*Spirits

//this loop is used to create/move dummyunits and also make them damage enemies
//dummyunits are destroyed at the end of the iterations or when the caster is dead
loop
    set X=GetUnitX(u)
    set Y=GetUnitY(u)
    if GetWidgetLife(u)>.405 and i<=SS then
    //if there are left units to be summoned
        set k=0
        loop 
            if GetWidgetLife(u)>.405 then
                    set spirits[i+k*SS]=CreateUnit(GetOwningPlayer(u),'e000',X,Y,0) 
                    call UnitDamageTargetBJ(u,u,SummoningDamage,ATTACK_TYPE_MAGIC,DAMAGE_TYPE_DIVINE)
            endif
        set k=k+1
        exitwhen k>=StarEdges
        endloop    
    endif    
    //Initially I wanted to move only the last created unit but it doesn't look right so it shall have some changes
    //by moving all the available units except the last created one when possible
    set j=1
    if GetWidgetLife(u)>.405 then
            loop 
            exitwhen j>i or j>SS
            set k=0
                loop
                    if (i-j+1)*ArcVariationOnTimer<=Arc1Angle then
                        call SetUnitPosition(spirits[j+k*SS],X+InnerCircleCentersX[k+1]+ArcRadius*Cos((i-j+1)*ArcVariationOnTimer+Arcs1Start[k+1]),Y+InnerCircleCentersY[k+1]+ArcRadius*Sin((i-j+1)*ArcVariationOnTimer+Arcs1Start[k+1]))
                    elseif (i-j+1)*ArcVariationOnTimer<=Arc1Angle+Arc2Angle then
                        call SetUnitPosition(spirits[j+k*SS],X+OuterCircleCentersX[k+2]+ArcRadius*Cos(Arc1Angle-(i-j+1)*ArcVariationOnTimer+Arcs2Start[k+2]),Y+OuterCircleCentersY[k+2]+ArcRadius*Sin(Arc1Angle-(i-j+1)*ArcVariationOnTimer+Arcs2Start[k+2]))                
                    elseif (i-j+1)*ArcVariationOnTimer<=Arc1Angle+Arc2Angle+Arc3Angle then
                        call SetUnitPosition(spirits[j+k*SS],X+InnerCircleCentersX[k+2]+ArcRadius*Cos(Arc1Angle+Arc2Angle-(i-j+1)*ArcVariationOnTimer+Arcs3Start[k+2]),Y+InnerCircleCentersY[k+2]+ArcRadius*Sin(Arc1Angle+Arc2Angle-(i-j+1)*ArcVariationOnTimer+Arcs3Start[k+2]))                    
                    else
                        //I won't remove them here but move them to the caster's position
                        call SetUnitPosition(spirits[j+k*SS],X,Y)
                    endif
                set k=k+1
                exitwhen k>=StarEdges
                endloop
            set j=j+1
            endloop
    endif
    // Well I have to do the damaging sequence too and I guess that soon after my damagefunc will be incorporated here
   set k=1
   loop
   set j=0
        loop
        set HealedMAX=AvengingWrathDamage(spirits[k+j*SS],u,HealedMAX)
        set j=j+1
        exitwhen j>=StarEdges
        endloop
    set k=k+1
    exitwhen k>=i or k>SS
    endloop
    
    //wait a while before moving/damaging again
    call TriggerSleepAction(1/I2R(Temporizator))
    
set i=i+1
exitwhen i>iterations or GetWidgetLife(u)<.405 or u==null
endloop


//to do memory unalloc

set i=1
loop
set j=0
    loop
    call RemoveUnit(spirits[i+j*SS])
    set spirits[i+j*SS]=null
    set j=j+1
    exitwhen j>=StarEdges
    endloop
set i=i+1
exitwhen i>SS
endloop

//call RemoveUnit(u)
set u=null

//call BJDebugMsg("AvengingWrathActions ends")

endfunction

//===========================================================================
function InitTrig_Avenging_Wrath takes nothing returns nothing
    set gg_trg_Avenging_Wrath = CreateTrigger(  )
    call TriggerExecute(gg_trg_Startup)
    call TriggerRegisterAnyUnitEventBJ( gg_trg_Avenging_Wrath, EVENT_PLAYER_UNIT_SPELL_EFFECT )
    call TriggerAddCondition( gg_trg_Avenging_Wrath, Condition( function Trig_Avenging_Wrath_Conditions ) )
    call TriggerAddAction( gg_trg_Avenging_Wrath, function Trig_Avenging_Wrath_Actions )
endfunction

endscope


2. Spell Binding Arrow - based off Critical Strike Passive skill gives a chance on hitting to make a casred area in which Avenging Spirits spawn and patrol . All the statistics are based on her stats and the chance is based on skill level .

I wanted to make a trigger when a unit takes damage and how to attach the events to the actual trigger and +rep (when i learn how to do it ) goes to Deebee because I got insipred by this thread .

Here I have added the damage / healing part of my Blood Hatred skill because it makes it lighter on the code and uses almost al the conditions as Arrow Strike . I have discovered the crash bug that occured when I was trying to damage stuff with my hero so I disabled the Damage detection trigger before damaging . Changed yet again so if that my hero dies it won't damage ally and foe alike because the source of damage becomes null and null has no allies .




JASS:

globals
    trigger gg_trg_InitSpellBindingArrowAddEvent
    trigger gg_trg_SpellBindingArrowAddEvent
    trigger gg_trg_SpellBindingArrowStrikeDisplay
    constant integer MaxSpiritFields=10      //set up a maximum number of spirit fields to prevent lag
    integer CurrentSpiritFields = 1 
    integer FieldsInGame = 1
    integer FieldsToKill = 0
    real increment=bj_PI/100                //speed of summoned spirits in radians
    real BH_regeneration = 0.5              // factor of bloodhatred damage restored as HP
endglobals
//TRIGGER FOR REGISTERING UNIT_DAMAGE FOR STARTUP UNITS
scope InitSpellBindingArrowEvent initializer InitTrig_InitSpellBindingArrowAddEvent

function Trig_InitSpellBindingArrowAddEvent_Actions takes nothing returns nothing
    local group G
    local unit u
    set G = GetUnitsInRectAll(GetPlayableMapRect())
    loop
    set u=FirstOfGroup(G)
    call TriggerRegisterUnitEvent( gg_trg_SpellBindingArrowStrike, u , EVENT_UNIT_DAMAGED )
    call TriggerRegisterUnitEvent( gg_trg_PotADismountLifeCheck , u , EVENT_UNIT_DAMAGED )
    call GroupRemoveUnit(G,u)
    exitwhen u==null
    endloop
    call RemoveUnit(u)
    set u=null
    call DestroyGroup(G)
    set G=null
endfunction

//===========================================================================
function InitTrig_InitSpellBindingArrowAddEvent takes nothing returns nothing
    set gg_trg_InitSpellBindingArrowAddEvent = CreateTrigger(  )
    call TriggerAddAction( gg_trg_InitSpellBindingArrowAddEvent, function Trig_InitSpellBindingArrowAddEvent_Actions )
endfunction

endscope

//TRIGGER FOR REGISTERING EVENT_UNIT_DAMAGE FOR NEWLY CREATED UNITS
scope SpellBindingArrowEvent initializer InitTrig_SpellBindingArrowAddEvent

function Trig_SpellBindingArrowAddEvent_Actions takes nothing returns nothing
    call TriggerRegisterUnitEvent( gg_trg_SpellBindingArrowStrike, GetTriggerUnit(), EVENT_UNIT_DAMAGED ) 
    call TriggerRegisterUnitEvent( gg_trg_PotADismountLifeCheck , GetTriggerUnit(), EVENT_UNIT_DAMAGED ) 
endfunction

//===========================================================================
function InitTrig_SpellBindingArrowAddEvent takes nothing returns nothing
    set gg_trg_SpellBindingArrowAddEvent = CreateTrigger(  )
    call TriggerRegisterEnterRectSimple( gg_trg_SpellBindingArrowAddEvent, GetPlayableMapRect() )
    call TriggerAddAction( gg_trg_SpellBindingArrowAddEvent, function Trig_SpellBindingArrowAddEvent_Actions )
endfunction

endscope
//TRIGGER FOR SHOWING NUMBER OF SPIRITS AND DAMAGE WITH -AS COMMAND
scope SpellBingingArrowCommand initializer InitTrig_SpellBindingArrowStrikeDisplay

function Trig_SpellBindingArrowStrikeDisplay_Actions takes nothing returns nothing
local player p=GetTriggerPlayer()
local group  g=GetUnitsInRectAll(GetPlayableMapRect())
local unit   u

set bj_wantDestroyGroup=true

loop
set u=FirstOfGroup(g)
if IsUnitType(u,UNIT_TYPE_HERO) and GetUnitAbilityLevel(u,'A002')>0 and (GetOwningPlayer(u)==p)then
    //call BJDebugMsg("Spellbinding Arrow summons "+R2S(30*GetHeroInt(u,true)/100)+" spirits that damage for "+R2S((GetHeroStr(u,true)+GetHeroAgi(u,true))/5)+" damage")
    call DisplayTimedTextToPlayer(p,0,0,3,"Spellbinding Arrow summons "+R2S(30*GetHeroInt(u,true)/100)+" spirits that damage for "+R2S((GetHeroStr(u,true)+GetHeroAgi(u,true))/5)+" damage")
endif
call GroupRemoveUnit(g,u)
exitwhen u==null
endloop

call DestroyGroup(g)
call RemoveUnit(u)
set g=null
set u=null
set p=null

endfunction

//===========================================================================
function InitTrig_SpellBindingArrowStrikeDisplay takes nothing returns nothing
    set gg_trg_SpellBindingArrowStrikeDisplay = CreateTrigger(  )
    call TriggerRegisterPlayerChatEvent( gg_trg_SpellBindingArrowStrikeDisplay, Player(0), "-as", true )
    call TriggerRegisterPlayerChatEvent( gg_trg_SpellBindingArrowStrikeDisplay, Player(1), "-as", true )
    call TriggerRegisterPlayerChatEvent( gg_trg_SpellBindingArrowStrikeDisplay, Player(2), "-as", true )
    call TriggerRegisterPlayerChatEvent( gg_trg_SpellBindingArrowStrikeDisplay, Player(3), "-as", true )
    call TriggerRegisterPlayerChatEvent( gg_trg_SpellBindingArrowStrikeDisplay, Player(4), "-as", true )
    call TriggerRegisterPlayerChatEvent( gg_trg_SpellBindingArrowStrikeDisplay, Player(5), "-as", true )
    call TriggerRegisterPlayerChatEvent( gg_trg_SpellBindingArrowStrikeDisplay, Player(6), "-as", true )
    call TriggerRegisterPlayerChatEvent( gg_trg_SpellBindingArrowStrikeDisplay, Player(7), "-as", true )
    call TriggerRegisterPlayerChatEvent( gg_trg_SpellBindingArrowStrikeDisplay, Player(8), "-as", true )
    call TriggerRegisterPlayerChatEvent( gg_trg_SpellBindingArrowStrikeDisplay, Player(9), "-as", true )
    call TriggerRegisterPlayerChatEvent( gg_trg_SpellBindingArrowStrikeDisplay, Player(10), "-as", true )
    call TriggerRegisterPlayerChatEvent( gg_trg_SpellBindingArrowStrikeDisplay, Player(11), "-as", true )
    call TriggerAddAction( gg_trg_SpellBindingArrowStrikeDisplay, function Trig_SpellBindingArrowStrikeDisplay_Actions )
endfunction

endscope
//TRIGGER DOING THE ACTUAL SUMMONING ON STRIKING AND DOES BH BONUS DAMAGE TOO
scope SpellbindingArrow initializer InitTrig_SpellBindingArrowStrike

function Trig_SpellBindingArrowStrike_Conditions takes nothing returns boolean
//activate arrow effects if target is not a structure , the attacker is hero 
//and the attacked is not ally of attacker

return (not IsUnitType(GetTriggerUnit(),UNIT_TYPE_STRUCTURE)) and IsUnitType(GetEventDamageSource(),UNIT_TYPE_HERO) and (not IsUnitAlly(GetTriggerUnit(),GetOwningPlayer(GetEventDamageSource())))

endfunction

function SpellBindDamage takes unit u , player owner , integer damage returns nothing
local group g = CreateGroup()
local location l=GetUnitLoc(u)
local unit un

set g = GetUnitsInRangeOfLocAll(50,l)
loop
set un=FirstOfGroup(g)
if un!=null and not IsUnitAlly(un,owner) and GetWidgetLife(un)>.405 and not IsUnitType(un,UNIT_TYPE_MAGIC_IMMUNE) then
    call UnitDamageTargetBJ(u,un,damage,ATTACK_TYPE_HERO,DAMAGE_TYPE_MAGIC)
    call DestroyEffect( AddSpecialEffectTargetUnitBJ( "overhead", un , WispAnimation ))
endif
call GroupRemoveUnit(g,un)
exitwhen un==null
endloop

call RemoveLocation(l)
call RemoveUnit(un)
call DestroyGroup(g)
set l=null
set un=null

endfunction

function Trig_SpellBindingArrowStrike_Actions takes nothing returns nothing
local unit    att=GetEventDamageSource()
local player  owner=GetOwningPlayer(att)
local unit    target=GetTriggerUnit()
local integer lvl=GetUnitAbilityLevel(att,'A002')
local boolean undead=IsUnitType(GetTriggerUnit(),UNIT_TYPE_UNDEAD)
local real    X=GetLocationX(GetUnitLoc(target))
local real    Y=GetLocationY(GetUnitLoc(target))
local integer STR=GetHeroStr(att,TRUE)
local integer AGI=GetHeroAgi(att,TRUE)
local integer INT=GetHeroInt(att,TRUE)
local integer AoEX=R2I(STR+INT+100)
local integer AoEY=R2I(AGI+INT+100)
local integer HorizL=IMinBJ(R2I(20*STR/100),5)
local integer VertiL=IMinBJ(R2I(10*AGI/100),9)
local integer SpiritsNo=(30*INT/100)
local integer SpiritDMG=R2I((AGI+STR)/5)
local integer chance
local unit array spirits
local integer i
local integer j
local real angle
local integer fieldcode=-1
//Parameters for BH
local integer lvl2=GetUnitAbilityLevel(att,'A003')
local real    lifelost
local real    BHdamage
local real Texttag_Vlcty   = 60
local real Texttag_Size    = 10
local real Texttag_Red     = 250
local real Texttag_Green   = 86
local real Texttag_Blue    = 245
local real Texttag_Trsprcy = 8
local real Texttag_Angle   = 90
local real Texttag_Durtn   = 1.25
local real Cut_Off_Durtn   = 2.5
local texttag t


//call BJDebugMsg("ArrowStrike Actions")
//call BJDebugMsg("ArrowStrike lvl "+I2S(lvl))
//if undead then
//call BJDebugMsg("Undead target")
//endif
//call BJDebugMsg("Target Position X "+R2S(X)+" Y "+R2S(Y))
//call BJDebugMsg("Attacker stats S="+I2S(STR)+" A="+I2S(AGI)+" I="+I2S(INT))
//call BJDebugMsg("AoE X="+I2S(AoEX)+" Y="+I2S(AoEY))
//call BJDebugMsg("Loops X="+I2S(HorizL)+" Y="+I2S(VertiL))
//call BJDebugMsg("Spirits No="+I2S(SpiritsNo)+" Dmg="+I2S(SpiritDMG))
//creating a random value to see if the ability triggers

//Doing BH damage here

if lvl2>0 then

set lifelost=GetUnitState(att,UNIT_STATE_MAX_LIFE)-GetUnitState(att,UNIT_STATE_LIFE)
set BHdamage=0.01*lvl2*lifelost
        //Amazingly I cannot use the hero to damage stuff while the trigger is activated FFS
        call DisableTrigger(gg_trg_SpellBindingArrowStrike)
        call UnitDamageTarget(att,target,BHdamage, false , false ,ATTACK_TYPE_MAGIC,DAMAGE_TYPE_DIVINE,WEAPON_TYPE_WHOKNOWS)
        call EnableTrigger(gg_trg_SpellBindingArrowStrike)
        call SetUnitLifeBJ(att,GetUnitState(att,UNIT_STATE_LIFE)+BHdamage*BH_regeneration)
        //display damage in black
        if R2I(BHdamage)>0 then
        set t = CreateTextTagUnitBJ("+" + I2S(R2I(BHdamage)), target , Texttag_Vlcty, Texttag_Size, Texttag_Red, Texttag_Green, Texttag_Blue, Texttag_Trsprcy)
        call SetTextTagVelocityBJ(t, Texttag_Vlcty, Texttag_Angle)
        call SetTextTagPermanent(t, false)
        call SetTextTagLifespan(t, Texttag_Durtn)
        endif
endif

//ArrowStrike here
if lvl>0 then

if undead then
set chance = GetRandomInt(1,50)
else
set chance = GetRandomInt(1,100)
endif

//checking and doing actions if it does
if chance<=5*lvl then
    //call BJDebugMsg("Spirits have been summoned")
        if (fieldcode==-1) then
        if (CurrentSpiritFields==MaxSpiritFields) then
            set fieldcode=MaxSpiritFields
            set FieldsInGame=FieldsInGame+1
            set CurrentSpiritFields=1
            if FieldsInGame>MaxSpiritFields then
                set FieldsToKill=fieldcode
            endif
        else 
            set fieldcode=CurrentSpiritFields
            set FieldsInGame=FieldsInGame+1
            set CurrentSpiritFields=CurrentSpiritFields+1
            if FieldsInGame>MaxSpiritFields then
                set FieldsToKill=fieldcode
            endif
        endif
    endif  
    
    set angle=2*bj_PI/SpiritsNo
    set i=0
    loop
    set spirits<i>=CreateUnit(GetOwningPlayer(att),&#039;e000&#039;,X+AoEX*Cos(HorizL*i*angle),Y+AoEY*Sin(VertiL*i*angle),0)
    set i=i+1
    exitwhen i==SpiritsNo
    endloop
    set i=0
    loop
    set j=0
        loop
        call SetUnitPosition(spirits[j],X+AoEX*Cos(HorizL*(j*angle+i*increment)),Y+AoEY*Sin(VertiL*(j*angle+i*increment)))
        //for this damage function I used the owner because inlike Avenging Wrath if the hero dies it will still go on
        //the hero may die if he morphs and we don&#039;t want the morphed hero to take damage from his own skill
        //so he has the same owner as the previous unit spawning this effect so the player and his allies are
        //safe from selfdamage
        call SpellBindDamage(spirits[j],owner,SpiritDMG)
        set j=j+1
        exitwhen j==SpiritsNo
        endloop
    call TriggerSleepAction(0.04)
    set i=i+1
    exitwhen i*increment&gt;bj_PI or fieldcode==FieldsToKill
    endloop

set j=0
loop
call RemoveUnit(spirits[j])
set spirits[j]=null
set j = j + 1
exitwhen j==SpiritsNo
endloop

set FieldsInGame=FieldsInGame-1
if FieldsToKill==fieldcode then
 set FieldsToKill=0
endif    
    
endif


endif// lvl of arrowstrike &gt;0

endfunction



//===========================================================================
function InitTrig_SpellBindingArrowStrike takes nothing returns nothing
    set gg_trg_SpellBindingArrowStrike = CreateTrigger(  )
    call TriggerAddCondition(gg_trg_SpellBindingArrowStrike , Condition(function Trig_SpellBindingArrowStrike_Conditions))
    call TriggerAddAction( gg_trg_SpellBindingArrowStrike, function Trig_SpellBindingArrowStrike_Actions )
endfunction

endscope

</i>


I have decided to add -as command to display the number of spirits summoned by ArrowStrike and their damage :

3. Blood Hatred - based off Evasion . You deal aditional damage of 1% * SpellLvl of your lost life as bonus damage and heal 1/2 of this bonus damage dealt and also if an enemy hero kills a nonhero,nonmechanical,nonbuilding unit you gain 0.01*SpellLvL Strength

Now If a player learns BloodHatred skill his hero will be memorized into an array and in similar arrays will be stored the Str bonuses to be gained and already gained due to this ability .

Upon further thinking I decided to make my hero playable by all the players but in 1 instance for every one of them . Here are the triggers for monitoring applying STR and displaying it with player command -bh

JASS:

globals
    trigger gg_trg_BHDisplay
    integer array BH_StrengthAdded
    real    array BH_StrengthTotal
endglobals
//TRIGGER FOR INCREASING HERO STRENGTH FOR ALLIED CREEP KILLED BY ENEMY HERO
scope BHStrengthBonus initializer InitTrig_BHStrengthBonus

function Trig_BHStrengthBonus_Actions takes nothing returns nothing
local integer i=0
local integer Strength
local group   g
local unit    un

loop
exitwhen i==12
//the players will gain strength if :
// the killed enemy isn&#039;t building, hero or mechanical
//the killing unit is an enemy hero
//my array contains only the units that have already learned BH so testing if the unit shall have STR++ is unnecesary
if (not IsUnitType(GetTriggerUnit(),UNIT_TYPE_STRUCTURE)) and (not IsUnitType(GetTriggerUnit(),UNIT_TYPE_HERO)) and (not IsUnitType(GetTriggerUnit(),UNIT_TYPE_MECHANICAL)) and IsUnitEnemy(GetKillingUnit(),Player(i)) and IsUnitType(GetKillingUnit(),UNIT_TYPE_HERO) then
    set g=GetUnitsOfPlayerAll(Player(i))
    loop
    set un = FirstOfGroup(g)
    call GroupRemoveUnit(g,un)
    exitwhen un==null or GetUnitAbilityLevel(un,&#039;A003&#039;)&gt;0
    endloop
    //we consider the hero is unique and cannot be purchased more than once by a player
    //we also consider that all players can have the same hero
    set BH_StrengthTotal<i>=BH_StrengthTotal<i> + 0.01*GetUnitAbilityLevel(un,&#039;A003&#039;)
    if R2I(BH_StrengthTotal<i>)&gt;BH_StrengthAdded<i> then
    set Strength=GetHeroStr(un,false)
    call SetHeroStr(un,Strength+R2I(BH_StrengthTotal<i>)-BH_StrengthAdded<i>,true)
    set BH_StrengthAdded<i>=R2I(BH_StrengthTotal<i>)
    endif
endif
set i=i+1
endloop


endfunction

//===========================================================================
function InitTrig_BHStrengthBonus takes nothing returns nothing
    set gg_trg_BHStrengthBonus = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ(gg_trg_BHStrengthBonus,EVENT_PLAYER_UNIT_DEATH)
    call TriggerAddAction( gg_trg_BHStrengthBonus, function Trig_BHStrengthBonus_Actions )
endfunction

endscope
//TRIGGER FOR DISPLAYING THE STRENGTH GAINED
scope display initializer InitTrig_BHDisplay

function Trig_BHDisplay_Actions takes nothing returns nothing
//call  BJDebugMsg(&quot;Your BloodHatred strength is &quot;+R2S(BH_StrengthTotal<i>))
call DisplayTimedTextToPlayer(GetTriggerPlayer(),0,0,3,&quot;Your BloodHatred strength is &quot;+R2S(BH_StrengthTotal[GetPlayerId(GetTriggerPlayer())]))

endfunction

//===========================================================================
function InitTrig_BHDisplay takes nothing returns nothing
    set gg_trg_BHDisplay = CreateTrigger(  )
    call TriggerRegisterPlayerChatEvent( gg_trg_BHDisplay, Player(0), &quot;-bh&quot;, true )
    call TriggerRegisterPlayerChatEvent( gg_trg_BHDisplay, Player(1), &quot;-bh&quot;, true )
    call TriggerRegisterPlayerChatEvent( gg_trg_BHDisplay, Player(2), &quot;-bh&quot;, true )
    call TriggerRegisterPlayerChatEvent( gg_trg_BHDisplay, Player(3), &quot;-bh&quot;, true )
    call TriggerRegisterPlayerChatEvent( gg_trg_BHDisplay, Player(4), &quot;-bh&quot;, true )
    call TriggerRegisterPlayerChatEvent( gg_trg_BHDisplay, Player(5), &quot;-bh&quot;, true )
    call TriggerRegisterPlayerChatEvent( gg_trg_BHDisplay, Player(6), &quot;-bh&quot;, true )
    call TriggerRegisterPlayerChatEvent( gg_trg_BHDisplay, Player(7), &quot;-bh&quot;, true )
    call TriggerRegisterPlayerChatEvent( gg_trg_BHDisplay, Player(8), &quot;-bh&quot;, true )
    call TriggerRegisterPlayerChatEvent( gg_trg_BHDisplay, Player(9), &quot;-bh&quot;, true )
    call TriggerRegisterPlayerChatEvent( gg_trg_BHDisplay, Player(10), &quot;-bh&quot;, true )
    call TriggerRegisterPlayerChatEvent( gg_trg_BHDisplay, Player(11), &quot;-bh&quot;, true )
    call TriggerAddAction( gg_trg_BHDisplay, function Trig_BHDisplay_Actions )
endfunction

endscope

</i></i></i></i></i></i></i></i></i>


4. Pain of the Ancients - based off channel . It is mainly done but there are still issues

What it does :
- changes the hero into another one
- he keeps the BH strength bonus and BH still works normally thereafter
- he doesn't kill himself with SpellBindingArrow any more when changing forms
- He gains the multishot as he should
- he gsins the bonus damage and bonus damage for allied building lost normally
- he gains the armor and spell immunity
- autoactivates when HP < 30% ; now it autoactivates the second time and third time and so on too
- fixed so it has 45 seconds cooldown ; removed cooldown from the object editor spell
- can be activated
- uses up mana
- shows cripple but also plays the stupid cripple sound
- plays funny music but not as loud as I would like

What it doesn't do :
- doesn't display magic immunity buff (based off spell immunity unit ability)
- fills the hero skills tab with useless icons (and i would rather it doesn't do it)
- doesn't display cooldown in normal fashion ; I made some text messages to notify you but hope to improve it

JASS:

globals
    trigger gg_trg_PotADismountLifeCheck
    trigger gg_trg_PotABuildingLost
    trigger gg_trg_PotAHeroReived
    trigger gg_trg_PotARevive
    integer array PotA_FallenAllies[12]
    integer array PotALostBuildings[12]
    boolean array PotAOnCooldown[12]
    real ActivationLifePercent=30.00
endglobals


//TRIGGER FOR COUNTING BUILDINGS AND ALLIED HEROES DEAD
scope LostAllies initializer InitTrig_PotABuildingLost

function Trig_PotABuildingLost_Actions takes nothing returns nothing
local integer i=0
local integer owner=GetPlayerId(GetOwningPlayer(GetTriggerUnit()))
//hero death
if IsUnitType(GetTriggerUnit(),UNIT_TYPE_HERO) then
    loop
    if IsPlayerAlly(Player(i),Player(owner)) then 
        //call BJDebugMsg(&quot;An allied hero of player &quot;+I2S(i)+&quot;has been slain !!!&quot;)
        set PotA_FallenAllies<i>=PotA_FallenAllies<i>+1
    endif
    exitwhen i&gt;11 
    set i=i+1
    endloop
//unit death
elseif IsUnitType(GetTriggerUnit(),UNIT_TYPE_STRUCTURE) then
    loop
    if IsPlayerAlly(Player(i),Player(owner)) then
        //call BJDebugMsg(&quot;Our base??? is under attack !!! - ally of player &quot; + I2S(i))
        set PotALostBuildings<i>=PotALostBuildings<i> + 1
    endif
    exitwhen i&gt;11
    set i = i + 1 
    endloop
endif

endfunction

//===========================================================================
function InitTrig_PotABuildingLost takes nothing returns nothing
    set gg_trg_PotABuildingLost = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ(gg_trg_PotABuildingLost,EVENT_PLAYER_UNIT_DEATH)
    call TriggerAddAction( gg_trg_PotABuildingLost, function Trig_PotABuildingLost_Actions )
endfunction

endscope

//TRIGGER ALLIED HERO REVIED DURING ULTIMATE TO REDUCE MULTISHOT TARGETS
scope AllyRevived initializer InitTrig_PotAHeroReived

function Trig_PotAHeroReived_Actions takes nothing returns nothing
local integer i
local integer owner = GetPlayerId(GetOwningPlayer(GetTriggerUnit()))

loop
if IsPlayerAlly(Player(i),Player(owner)) then
    set PotA_FallenAllies<i> = PotA_FallenAllies<i> - 1
endif
exitwhen i&gt;11
set i=i+1
endloop
endfunction

//===========================================================================
function InitTrig_PotAHeroReived takes nothing returns nothing
    set gg_trg_PotAHeroReived = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ(gg_trg_PotAHeroReived,EVENT_PLAYER_HERO_REVIVE_FINISH)
    call TriggerAddAction( gg_trg_PotAHeroReived, function Trig_PotAHeroReived_Actions )
endfunction

endscope

//TRIGGER FOR REVIVING A HERO DEAD DURING THE ULTIMATE
scope revive initializer InitTrig_PotARevive

function Trig_PotARevive_Conditions takes nothing returns boolean
    return  GetUnitTypeId(GetTriggerUnit()) == &#039;E001&#039;
endfunction

function Trig_PotARevive_Actions takes nothing returns nothing
local unit caster=GetTriggerUnit()
local integer AWlevels = GetUnitAbilityLevel(caster,&#039;A000&#039;)
local integer SbAlevels = GetUnitAbilityLevel(caster,&#039;A002&#039;)
local integer BHlevels  = GetUnitAbilityLevel(caster,&#039;A003&#039;)
local integer PotAlevels = GetUnitAbilityLevel(caster,&#039;A005&#039;)
local integer StatsLevels = GetUnitAbilityLevel(caster,&#039;A001&#039;)
local real    lifelevel = GetUnitState(caster,UNIT_STATE_LIFE)
local integer i

set caster=ReplaceUnitBJ(caster,&#039;E002&#039;,bj_UNIT_STATE_METHOD_RELATIVE)
call SetUnitState(caster,UNIT_STATE_LIFE,lifelevel)
call SetHeroStr(caster,GetHeroStr(caster,false)+BH_StrengthAdded[GetPlayerId(GetOwningPlayer(caster))],true)
//it&#039;s left to learn the abilities of the hero
set i=0
loop
exitwhen i==AWlevels
call SelectHeroSkill(caster,&#039;A000&#039;)
set i=i+1
endloop

set i=0
loop
exitwhen i==SbAlevels
call SelectHeroSkill(caster,&#039;A002&#039;)
set i=i+1
endloop

set i=0
loop
exitwhen i==BHlevels
call SelectHeroSkill(caster,&#039;A003&#039;)
set i=i+1
endloop

set i=0
loop
exitwhen i==PotAlevels
call SelectHeroSkill(caster,&#039;A004&#039;)
set i=i+1
endloop

set i=0
loop
exitwhen i==StatsLevels
call SelectHeroSkill(caster,&#039;A001&#039;)
set i=i+1
endloop

set caster = null

endfunction

//===========================================================================
function InitTrig_PotARevive takes nothing returns nothing
    set gg_trg_PotARevive = CreateTrigger(  )
    call DisableTrigger( gg_trg_PotARevive )
    call TriggerRegisterPlayerUnitEventSimple( gg_trg_PotARevive, Player(0), EVENT_PLAYER_HERO_REVIVE_FINISH )
    call TriggerRegisterPlayerUnitEventSimple( gg_trg_PotARevive, Player(1), EVENT_PLAYER_HERO_REVIVE_FINISH )
    call TriggerRegisterPlayerUnitEventSimple( gg_trg_PotARevive, Player(2), EVENT_PLAYER_HERO_REVIVE_FINISH )
    call TriggerRegisterPlayerUnitEventSimple( gg_trg_PotARevive, Player(3), EVENT_PLAYER_HERO_REVIVE_FINISH )
    call TriggerRegisterPlayerUnitEventSimple( gg_trg_PotARevive, Player(4), EVENT_PLAYER_HERO_REVIVE_FINISH )
    call TriggerRegisterPlayerUnitEventSimple( gg_trg_PotARevive, Player(5), EVENT_PLAYER_HERO_REVIVE_FINISH )
    call TriggerRegisterPlayerUnitEventSimple( gg_trg_PotARevive, Player(6), EVENT_PLAYER_HERO_REVIVE_FINISH )
    call TriggerRegisterPlayerUnitEventSimple( gg_trg_PotARevive, Player(7), EVENT_PLAYER_HERO_REVIVE_FINISH )
    call TriggerRegisterPlayerUnitEventSimple( gg_trg_PotARevive, Player(8), EVENT_PLAYER_HERO_REVIVE_FINISH )
    call TriggerRegisterPlayerUnitEventSimple( gg_trg_PotARevive, Player(9), EVENT_PLAYER_HERO_REVIVE_FINISH )
    call TriggerRegisterPlayerUnitEventSimple( gg_trg_PotARevive, Player(10), EVENT_PLAYER_HERO_REVIVE_FINISH )
    call TriggerRegisterPlayerUnitEventSimple( gg_trg_PotARevive, Player(11), EVENT_PLAYER_HERO_REVIVE_FINISH )
    call TriggerAddCondition( gg_trg_PotARevive, Condition( function Trig_PotARevive_Conditions ) )
    call TriggerAddAction( gg_trg_PotARevive, function Trig_PotARevive_Actions )
endfunction

endscope

//TRIGGER FOR AUTOACTIATION OF POTA
scope AutoActivation initializer InitTrig_PotADismountLifeCheck

function Trig_PoTADismountCheck_Conditions takes nothing returns boolean
return GetUnitStatePercent(GetTriggerUnit(),UNIT_STATE_LIFE,UNIT_STATE_MAX_LIFE)&lt;ActivationLifePercent and GetUnitAbilityLevel(GetTriggerUnit(),&#039;A004&#039;)&gt;0
endfunction

function Trig_PotADismountLifeCheck_Actions takes nothing returns nothing
//call BJDebugMsg(&quot;life &lt;30%&quot;)
if not PotAOnCooldown[GetPlayerId(GetOwningPlayer(GetTriggerUnit()))] then
    call TriggerExecute(gg_trg_PotADismount)
endif
endfunction

//===========================================================================
function InitTrig_PotADismountLifeCheck takes nothing returns nothing
    set gg_trg_PotADismountLifeCheck = CreateTrigger(  )
    call TriggerAddCondition(gg_trg_PotADismountLifeCheck , Condition(function Trig_PoTADismountCheck_Conditions))
    call TriggerAddAction( gg_trg_PotADismountLifeCheck, function Trig_PotADismountLifeCheck_Actions )
endfunction

endscope

//TRIGGER FOR DOING ACTIONS FOR PAIN OF THE ANCIENTS
scope PotAActions initializer InitTrig_PotADismount

function Trig_PotADismount_Conditions takes nothing returns boolean
    return GetSpellAbilityId()==&#039;A004&#039; 
endfunction

function Trig_PotADismount_Actions takes nothing returns nothing
local unit caster=GetTriggerUnit()
local integer AWlevels = GetUnitAbilityLevel(caster,&#039;A000&#039;)
local integer SbAlevels = GetUnitAbilityLevel(caster,&#039;A002&#039;)
local integer BHlevels  = GetUnitAbilityLevel(caster,&#039;A003&#039;)
local integer PotAlevels = GetUnitAbilityLevel(caster,&#039;A004&#039;)
local integer StatsLevels = GetUnitAbilityLevel(caster,&#039;A001&#039;)
local real    lifelevel = GetUnitState(caster,UNIT_STATE_LIFE)
local real    manalevel = GetUnitState(caster,UNIT_STATE_MANA)
//this one is because it&#039;s annoying to reselect the hero time and again
local boolean isselected = IsUnitSelected(caster,GetOwningPlayer(caster))
local integer i
local integer j=0
local integer loops = 5+5*PotAlevels
local integer allies_dead = PotA_FallenAllies[GetPlayerId(GetOwningPlayer(caster))]
local integer allies_dead_new
local integer buildings_lost = PotALostBuildings[GetPlayerId(GetOwningPlayer(caster))]
local integer buildings_lost_new
//local unit    holder = CreateUnit(GetOwningPlayer(caster),&#039;h000&#039;,0,0,0)

if not PotAOnCooldown[GetPlayerId(GetOwningPlayer(caster))] then

//adjusting mana consumed and putting skill on cooldown

set manalevel=manalevel  - 50*(PotAlevels+1)
set PotAOnCooldown[GetPlayerId(GetOwningPlayer(caster))]=true

set caster=ReplaceUnitBJ(caster,&#039;E001&#039;,bj_UNIT_STATE_METHOD_RELATIVE)
call SetHeroStr(caster,GetHeroStr(caster,false)+BH_StrengthAdded[GetPlayerId(GetOwningPlayer(caster))],true)
call AddSpecialEffectTargetUnitBJ( &quot;origin&quot;, caster, &quot;Abilities\\Spells\\Undead\\Cripple\\CrippleTarget.mdl&quot; )
call PlaySoundOnUnitBJ( gg_snd_ArcherPissed2, 100, caster )
//it&#039;s left to learn the abilities of the hero
//here go the usual abilities
set i=0
loop
exitwhen i==AWlevels
call SelectHeroSkill(caster,&#039;A000&#039;)
set i=i+1
endloop

set i=0
loop
exitwhen i==StatsLevels
call SelectHeroSkill(caster,&#039;A001&#039;)
set i=i+1
endloop

set i=0
loop
exitwhen i==SbAlevels
call SelectHeroSkill(caster,&#039;A002&#039;)
set i=i+1
endloop

set i=0
loop
exitwhen i==BHlevels
call SelectHeroSkill(caster,&#039;A003&#039;)
set i=i+1
endloop

set i=0
loop
exitwhen i==PotAlevels
call SelectHeroSkill(caster,&#039;A005&#039;)
set i = i + 1
endloop

//after setting all the abilities we set the life/mana values so that leveling stats won&#039;t give hero HP;MP heal
call SetUnitState(caster,UNIT_STATE_LIFE,lifelevel)
call SetUnitState(caster,UNIT_STATE_MANA,manalevel)

//Add spell Immunity

call UnitAddAbility(caster,&#039;A008&#039;)

//adding the hero only multishot
//the level of multishot is basically the number of allied heroes fallen but I capped it to
//a number between 1 and 5 because that is how many levels I gave the multishot ability
if allies_dead&gt;0 then
call UnitAddAbility(caster,&#039;A006&#039;)
call SetUnitAbilityLevel(caster,&#039;A006&#039;,IMinBJ(IMaxBJ(allies_dead,1),5))
endif

//selecting new hero
call SelectUnit(caster,isselected)

//Adding auras with damage and armor on the dummy unit created 


call UnitAddAbility(caster,&#039;A007&#039;)
call SetUnitAbilityLevel(caster,&#039;A007&#039;,20*(PotAlevels-1)+IMinBJ(buildings_lost,19))

//In the loop I will add also the skill for bonus damage and modify stuff as necessary :
//remove spell imunity , increase damage dealt , reduce or increase multishot level
loop

call TriggerSleepAction(1)

set allies_dead_new = PotA_FallenAllies[GetPlayerId(GetOwningPlayer(caster))]
set buildings_lost_new = PotALostBuildings[GetPlayerId(GetOwningPlayer(caster))]


if allies_dead_new&gt;allies_dead then
set allies_dead = allies_dead_new
call SetUnitAbilityLevel(caster,&#039;A006&#039;,IMinBJ(IMaxBJ(allies_dead,1),5))
endif

//get the damage bonus from the buildings lost or the base ; 
//bonus from buildings lost is capped at 19 instances
if buildings_lost_new&gt;buildings_lost then
set buildings_lost=buildings_lost_new
call UnitAddAbility(caster,&#039;A007&#039;)
call SetUnitAbilityLevel(caster,&#039;A007&#039;,20*(PotAlevels-1)+IMinBJ(buildings_lost,19))
endif

if j==3*PotAlevels then
//remove spell imunity and add an icon holder
call UnitRemoveAbility(caster,&#039;A008&#039;)
endif

exitwhen j==loops or GetWidgetLife(caster)&lt;.405
set j = j+1
endloop


//call BJDebugMsg(&quot;Should return hero to normal &quot; )

//the archer now remounts
if GetWidgetLife(caster)&gt;.405 then
set AWlevels = GetUnitAbilityLevel(caster,&#039;A000&#039;)
set SbAlevels = GetUnitAbilityLevel(caster,&#039;A002&#039;)
set BHlevels  = GetUnitAbilityLevel(caster,&#039;A003&#039;)
set PotAlevels = GetUnitAbilityLevel(caster,&#039;A005&#039;)
set StatsLevels = GetUnitAbilityLevel(caster,&#039;A001&#039;)
set lifelevel = GetUnitState(caster,UNIT_STATE_LIFE)
set manalevel = GetUnitState(caster,UNIT_STATE_MANA)
set isselected = IsUnitSelected(caster,GetOwningPlayer(caster))


set caster=ReplaceUnitBJ(caster,&#039;E002&#039;,bj_UNIT_STATE_METHOD_RELATIVE)
call SetHeroStr(caster,GetHeroStr(caster,false)+BH_StrengthAdded[GetPlayerId(GetOwningPlayer(caster))],true)
//it&#039;s left to learn the abilities of the hero
set i=0
loop
exitwhen i==AWlevels
call SelectHeroSkill(caster,&#039;A000&#039;)
set i=i+1
endloop

set i=0
loop
exitwhen i==SbAlevels
call SelectHeroSkill(caster,&#039;A002&#039;)
set i=i+1
endloop

set i=0
loop
exitwhen i==BHlevels
call SelectHeroSkill(caster,&#039;A003&#039;)
set i=i+1
endloop

set i=0
loop
exitwhen i==PotAlevels
call SelectHeroSkill(caster,&#039;A004&#039;)
set i=i+1
endloop

set i=0
loop
exitwhen i==StatsLevels
call SelectHeroSkill(caster,&#039;A001&#039;)
set i=i+1
endloop

//after setting all the abilities we set the life/mana values so that leveling stats won&#039;t give hero HP;MP heal
call SetUnitState(caster,UNIT_STATE_LIFE,lifelevel)
call SetUnitState(caster,UNIT_STATE_MANA,manalevel)

call SelectUnit(caster,isselected)

else
//enable reviving trigger
call EnableTrigger(gg_trg_PotARevive)
endif // unit is alive when the skill finishes

call DestroyEffect(GetLastCreatedEffectBJ())

//waiting the remaining time till cooldown is over
call TriggerSleepAction(45-loops)
set PotAOnCooldown[GetPlayerId(GetOwningPlayer(caster))]=false
call DisplayTimedTextToPlayer(GetOwningPlayer(caster),0,0,3,&quot; Pain of the Ancients cooldown has finished&quot;)

else

call DisplayTimedTextToPlayer(GetOwningPlayer(caster),0,0,3,&quot; Pain of the Ancients is on cooldown &quot;)

endif // if not on cooldown


endfunction

//===========================================================================
function InitTrig_PotADismount takes nothing returns nothing
    set gg_trg_PotADismount = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( gg_trg_PotADismount , EVENT_PLAYER_UNIT_SPELL_EFFECT )
    call TriggerAddCondition( gg_trg_PotADismount, Condition( function Trig_PotADismount_Conditions ) )
    call TriggerAddAction( gg_trg_PotADismount, function Trig_PotADismount_Actions )
endfunction

endscope
</i></i></i></i></i></i>


Miscelaneous BUG (the passive abilities don't activate if I don't make this triggers executed at map init , and this last trigger does just that ) for which I found only this solution :

Trigger:
  • Init
    • Events
      • Map initialization
    • Conditions
    • Actions
      • Custom script: call TriggerExecute(gg_trg_SpellBindingArrowStrike)
      • Custom script: call TriggerExecute(gg_trg_InitSpellBindingArrowAddEvent)


Now it is readable thanks' to SharkBait's efforts .
 

Komaqtion

You can change this now in User CP.
Reaction score
469
This should be in the Tutorials and Resources forum!

And you can't create new threads in like the Spells subforum, or something... Only approved things get moved there ;)
 

roXplosive

New Member
Reaction score
15
I reckon it is good enough looking and moving for Temp 10 , Spirits 8 , Edges 4,7+ and 10 ; Duration is in theory 5 but it doesn't really matter :D . I wonder if we choose 1 shall i make an array with all available positions for spirits and speed up computations ? I hope someone tests it too .

I've been trying another ability (passive) but it seems like I messed up with trigger registration because neither of the trigger's methods are used . I want to trigger when a unit is damaged so I tried something like this :

JASS:
function InitTrig_SpellBindingArrowStrike takes nothing returns nothing
    set gg_trg_SpellBindingArrowStrike = CreateTrigger(  )
    call TriggerRegisterUnitEvent(gg_trg_SpellBindingArrowStrike , GetTriggerUnit() ,EVENT_UNIT_DAMAGED)
    call TriggerAddCondition(gg_trg_SpellBindingArrowStrike , Condition(function Trig_SpellBindingArrowStrike_Conditions))
    call TriggerAddAction( gg_trg_SpellBindingArrowStrike, function Trig_SpellBindingArrowStrike_Actions )
endfunction


I guess tomorrow will update the map too (3.30 am atm).
 

Viikuna

No Marlo no game.
Reaction score
265
Can you post your spellcodes? Im on vacation so I dont have wc3 on this computer, but I wuld like to read your codes..
 

roXplosive

New Member
Reaction score
15
Ok I will post the codes here and the new version of the map . This one is beyond buglike and any help is appreciated . I have made 2 passive skills based off evasion and critical strike . They use the same events and if I learn BH skill first my Warcraft 3 I can exit war3 without using keys or menu .

After making this work I will start off to think about my ultimate .
 

Samael88

Evil always finds a way
Reaction score
181
Please edit that post and change the tags from [trigger] to
Code:
.
That would be easier to read;)
 

roXplosive

New Member
Reaction score
15
I'm afraid I don't understand . I saw when I first posted I used WC3 tags instead of JASS ones . is that it ?

Edit: For a number of 4 star spikes there is some funny effect . The first skill should work fine for star axis >= 5 . The higher the number the more will it look like a circle .

My idea for ultimate isn't going to be easily made . Basically I want to activate it or self activate when your hp<=25% .

Effects : The archer dismounts and has Cripple effect on it . Play a sound effect from normal units archer (i think it's the funnyest blizzard made along with the dryad ones ) "Fear my 1337 skillz !" . The new unit has the normal abilities of the hero and some extra :
-90% movespeed (this is debilitation is to be read -90% or set speed to static value of 100)
-multishot of 3 arrows + 1 / allied hero dead : targets only hero
-3/6/10 seconds spell immunity
-5/10/15 seconds bonus of 15/30/45 armor
- gains bonus damage according to allied buildings lost 20/40/60%+4/8/12%/building lost

I'm still thinking if the ultimate form should have enhanced range by 20/40/60% of base or not .

I really don't know if it matters the base skill is Evasion for BH because I used only triggered actions . If someone knows why it behaves strange please drop by .
 

roXplosive

New Member
Reaction score
15
If you can hint me to some useful resources in vJass and tell me with what is it different then I'm in to making the code lighter/better .

And here is the map . If you got helping ideas please don't be shy .:thup:

View attachment 32484
 

roXplosive

New Member
Reaction score
15
Thanks for + rep . Now I fixed the functionality of it all and now what's left is adding speciall effects . I don't know how to do it and I would appreciate help . How do I set a skill to be on cooldown ? Is there any way because it would really make a difference .

View attachment 32499

This is what I'm hoping to add next :
- I am also dwelling on the idea of adding an effect on the enemy struck by spirits ( holy light target of thorns aura target)
- show cripple special effect on hero when in archer form
- play music the pissed off music "pheer my 1337 skillz !" when you activate the ultimate
- display magic immunity buff (based off spell immunity unit ability)
- remove useless icons added by passives/selfauras when the ultimate kicks in
- display cooldown for ultimate in normal fashion ; I made some text messages to notify you but hope to improve it
 

BlackRose

Forum User
Reaction score
239
Um..... post the map on the FIRST POST rather then having us search for the latest? Unless you already did and I'm mistaken.

The screenshot looks nice, which made me want to download it :D
 

roXplosive

New Member
Reaction score
15
Well I posted it as a link I think .

Latest version here :

I have made some tiny modifications I forgot to remove in the posted version where the number of spirit trails for the first skill is 4 but you can change the global var StarEdges as you see fit .
 

D.V.D

Make a wish
Reaction score
73
Maybe replace all those globals with locals? and replace the BJ's if you haven't done so. Download JassNewGenPack and go on TESH to find the native used for the BJ.
 

roXplosive

New Member
Reaction score
15
I will convert it soon . This was to get used to functions , constants events . Don't worry I'm evolving . Soon the zerg sound "Evilution complete will arise ."
 

D.V.D

Make a wish
Reaction score
73
Make your globals private. And change the function names to make it more readable.
 

roXplosive

New Member
Reaction score
15
What effect would making them private have ? Will all my trigger's subfunctions be able to acces them ?
 
General chit-chat
Help Users
  • No one is chatting at the moment.

      The Helper Discord

      Staff online

      Members online

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top