HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

In need of testers

09-16-2006, 08:23 PM#1
Vexorian
Hello I saw reports on hydra having bugs. But it later seemed that the fault was on RagingCharge which used DestroyTrigger .

Anyways I need different people to download the old Hydra - RagingCharge map : http://www.wc3campaigns.net/showthread.php?t=80577

Then test this: Cast hydra, restore cooldown, Cast RagingCharge.

Do so repeatedly for let's say 15 minutes. IF you find a bug (with either of the spells) then replace RagingCharge's code with this:

Really big code

Collapse JASS:
//********************************************************************************************************
//*                                 A JESP Spell by Vexorian
//* Codename: RagingCharge
//* ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
//* Requirements:
//* ¯¯¯¯¯¯¯¯¯¯¯¯¯
//* - The RagingCharge ability
//* - The Caster System ( [url]http://wc3campaigns.net/vexorian[/url] )
//* - This Trigger (MAKE SURE TO change the rawcodes in the trigger to the correct ones of your map)
//*
//* Object Editor fields
//* ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
//* - Duration              : Duration of the ability determines how much the charge lasts.
//* - Art - Caster          : After charge Animation
//* - Art - Special     (1) : Hero charge effect
//* - Art - Special     (2) : Hero charge effect attachment point
//* - Art - Area Effect (1) : Knockback effect
//* - Art - Area Effect (2) : Knockback effect attachment point
//* - Art - Target      (1) : Impact effect
//* - Art - Target      (2) : Impact effect attachment point
//*
//********************************************************************************************************

//========================================================================================================
// RagingCharge Spell Configuration:
// 
//
////
// SpellId 
// ¯¯¯¯¯¯¯
// Make sure to replace A007 with the correct Rawcode in your map.
//
constant function RagingCharge_SpellId takes nothing returns integer
    return 'A007' 
endfunction

////
// Animation Stuff:
// ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
// _AnimationIndex   : The sequence index of the animation you want to be played during the charge,
//                     (Depends on the model used, see next trigger for more info)
// _AnimationDuration: Duration of the animation (Period of time before playing it again)
// _AnimationSpeed   : Speed factor for the animation
//
constant function RagingCharge_AnimationIndex takes integer level returns integer
    return 3
endfunction
constant function RagingCharge_AnimationDuration takes integer level returns real
    return 0.466
endfunction
constant function RagingCharge_AnimationSpeed takes real level returns real
    return 1.+level*0
endfunction
constant function RagingCharge_Speed takes real level returns real
    return 800.0+level*0
endfunction

////
// Balance Stuff:
// ¯¯¯¯¯¯¯¯¯¯¯¯¯
// _Damage          : Damage done to units that are hit by RagingCharge
// _DamagePerSecond : Damage per second units get during knockback
// _ImpactRange     : How close must a unit be to be hit by RagingCharge?
// _FrontAngle      : Angle in Deg, less than 180.0 that determines the front of the hero
//
constant function RagingCharge_Damage takes real level returns real
    return -5 + (85-5*level)*level
endfunction
constant function RagingCharge_DamagePerSecond takes real level returns real
    return 20+8*level 
endfunction
constant function RagingCharge_ImpactRange takes real level returns real
    return 200+level*0
endfunction
constant function RagingCharge_FrontAngle takes real level returns real
    return 179.0
endfunction

////
// Targetting options:
// ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
function RagingCharge_DamageOptions takes integer level returns integer
//** Damage options for impact damage:
    return DamageTypes(ATTACK_TYPE_NORMAL,DAMAGE_TYPE_FIRE) + DamageOnlyEnemies() + DamageException(UNIT_TYPE_FLYING,0)
//
// Will do fire spell damage, won't damage allies, and will only affect ground units.
// other damage options can be used, check caster system readme for more information.
//
//  (This is for the Impact damage)
//
endfunction
function RagingCharge_KnockbackOptions takes integer level returns integer
//** Damage options for knockback:
    return DamageOnlyEnemies() + DamageException(UNIT_TYPE_FLYING,0)
//
// Will knockback enemy ground units
// other damage options can be used, check caster system readme for more information.
//
//  (This is for the Knockback, meaning that only in case these damage options determine an unit is
// immune, it won't be affected by the knockback, this has nothing to do with damage
//
endfunction
function RagingCharge_KillTrees takes integer level returns boolean
//** true == kill trees ; false == don't kill trees
    return true
endfunction

////
// Other:
// ¯¯¯¯¯
constant function RagingCharge_Timer takes nothing returns real
//** Timer Period:
    return 0.04
//
//  This is the timer period, a low value (0.01) will look better but will be worse lag-wise, a high
// value (1.0) would be faster lag-wise but will surelly look bad. I think 0.04 is the perfect value.
endfunction




//========================================================================================================
// RagingCharge code:
//
// Why RagingCharge_ItemCheck instead of IsTerrainPathable?
// IsTerrainPathable doesn't consider pathing blockers, destructables nor buildings 
//
function RagingCharge_GetI takes nothing returns nothing
    set bj_rescueChangeColorUnit = bj_rescueChangeColorUnit or (GetEnumItem()!=bj_itemRandomCurrentPick)
endfunction
function RagingCharge_ItemCheck takes item p, real x, real y returns boolean
 local integer i=30
 local rect r
    call SetItemPosition(p,x,y)
    if ((Pow(GetItemX(p)-x,2)+Pow(GetItemY(p)-y,2))<=100) then
        return true
    endif
    set r=Rect(x-i,y-i,x+i,y+i)
    set bj_itemRandomCurrentPick=p
    set bj_rescueChangeColorUnit=false
    call EnumItemsInRect(r,null,function RagingCharge_GetI)
   call RemoveRect(r)

   set r=null
 return bj_rescueChangeColorUnit
endfunction
function RagingCharge_CheckPathability takes real x, real y returns boolean
 local item it=CreateItem('ciri',x,y)
 local boolean b =RagingCharge_ItemCheck(it,x,y)
    call SetItemVisible(it,false)
    call RemoveItem(it)
    
 set it=null
 return b
endfunction

function RagingCharge_OrbMov takes unit m,integer l, timer t,group g,string k returns boolean
 local real x=GetUnitX(m)
 local real y=GetUnitY(m)
 local real f=GetTableReal(k,"f")
 local real d=RagingCharge_Speed(l)*RagingCharge_Timer()
 local real nx=x+d*CosBJ(f)
 local real ny=y+d*SinBJ(f)
 local boolean b
 local integer error
 local integer n =GetAttachedInt(m,"times")+1
 local real nex

    call AttachInt(m,"times",n)


    call SetUnitFacing(m,f)
    set nex=GetTableReal(k,"next")
    if (n * RagingCharge_Timer() >= nex) then
        call SetTableReal(k,"next",nex+RagingCharge_AnimationDuration(l))
        call SetUnitAnimationByIndex(m,RagingCharge_AnimationIndex(l))
    endif


    if ((RagingCharge_CheckPathability(nx,ny)) and (CS_MoveUnit(m,nx,ny)))  then
        return true
    endif
    call SetUnitPosition(m,x,y)
    call TriggerEvaluate(GetTableTrigger(k,"endT"))
 return false
endfunction

function RagingCharge_Mov takes nothing returns nothing
 local timer t=GetExpiredTimer()
 local string k=I2S(GetTableInt("[RagingCharge]",GetAttachmentTable(t)))
 local group g=GetTableGroup(k,"g")
 local group a
 local unit m
 local unit o
 local unit u
 local real f
 local real h
 local real dir
 local real inc
 local real x
 local real y
 local real nx
 local real ny
 local real px
 local real py
 local real mina
 local real maxa
 local integer tms
 local integer l=GetTableInt(k,"l")
 local integer num=GetTableInt(k,"num")+1
 local trigger tg=GetTableTrigger(k,"endT")


    if (GetTriggerEvalCount(tg)>0) then

        loop
            set m=FirstOfGroup(g)
            exitwhen m==null
            call GroupRemoveUnit(g,m)
            call DestroyEffect( GetTableEffect(k,GetAttachmentTable(m)))
        endloop
        call DestroyGroup(g)
        set tg=GetTableTrigger(k,"ran")
        call TriggerRemoveAction(tg,GetTableTriggerAction(k,"ac"))
        call DisableTrigger(tg)
        call DestroyTimer(t)
        set m=GetTableUnit(k,"u")
        call DestroyEffect(GetTableEffect(k,"fx"))
        call QueueUnitAnimation(m,GetAbilityEffectById(RagingCharge_SpellId(),EFFECT_TYPE_CASTER,0))
        call SetUnitTimeScale(m,1)
        call DestroyTable(k)
        set num=GetTableInt("[RagingCharge]","N")
        if (num<=1) then
            call ClearTable("[RagingCharge]")
        else
            call SetTableInt("[RagingCharge]","N",num-1)
        endif
       set t=null
       set g=null
       set a=null
       set m=null
        return
    endif
   set tg=null
    call SetTableInt(k,"num",num)
    set o=GetTableUnit(k,"u")
    set u=GetTableUnit(k,"o")
    set x=GetUnitX(o)
    set y=GetUnitY(o)
    set a=CreateGroup()
    set inc=RagingCharge_Speed(l)*RagingCharge_Timer()
    
    if (RagingCharge_KillTrees(l)) then
        call DamageTreesInCircle(x,y,RagingCharge_ImpactRange(l))
    endif
    set h=RagingCharge_DamagePerSecond(l)*RagingCharge_Timer()
    loop
        set m=FirstOfGroup(g)
        exitwhen (m==null)
        set nx=GetUnitX(m)
        set ny=GetUnitY(m)
        if (IsUnitInRange(m,o,RagingCharge_ImpactRange(l))) and (GetWidgetLife(m)>0) then
            call DamageUnitByOptions(u,m,h,RagingCharge_DamageOptions(l))
            set f=Atan2(ny-y,nx-x)
            set px=nx+inc*Cos(f)
            set py=ny+inc*Sin(f)
            call SetUnitPosition(m,px,py)
            call SetUnitFacing(m,GetRandomReal(0,360))
            if (Pow(GetUnitX(m)-px,2)+Pow(GetUnitY(m)-py,2))>400 then
                call SetUnitPosition(m,nx,ny)
            endif
            call GroupAddUnit(a,m)

        else
            call DestroyEffect( GetTableEffect(k, GetAttachmentTable(m) ))
        endif
        call GroupRemoveUnit(g,m)
    endloop
    loop
        set m=FirstOfGroup(a)
        exitwhen m==null
        call GroupAddUnit(g,m)
        call GroupRemoveUnit(a,m)
    endloop
    call RagingCharge_OrbMov(o,l,t,g,k)
 call DestroyGroup(a)
 set t=null
 set g=null
 set a=null
 set m=null
endfunction

function RagingCharge_OrbImpact takes nothing returns nothing
 local string k=I2S(GetTableInt("[RagingCharge]",GetAttachmentTable(GetTriggeringTrigger())))
 local unit u=GetTriggerUnit()
 local unit m=GetTableUnit(k,"u")
 local group g=GetTableGroup(k,"g")
 local integer l=GetTableInt(k,"l")
 local real f
 local real dt
 local integer s=RagingCharge_SpellId()
 local integer i=0

    if not(IsUnitInGroup(u,g)) and (GetWidgetLife(u)>0) and not(IsUnitType(u,UNIT_TYPE_DEAD)) and not(IsUnitType(u,UNIT_TYPE_STRUCTURE)) then

        set f=GetTableReal(k,"f")
        set dt=RagingCharge_FrontAngle(l)/2
        if (Angles_IsAngleBetweenAngles( Atan2BJ(GetUnitY(u)-GetUnitY(m),GetUnitX(u)-GetUnitX(m)),f-dt,f+dt)) then
            if  (GetDamageFactorByOptions(m,u,RagingCharge_KnockbackOptions(l))!=0) then
                call DestroyEffect( AddSpellEffectTargetById(s,EFFECT_TYPE_TARGET,u,GetAbilityEffectById(s,EFFECT_TYPE_TARGET,1)) )
                call SetTableObject(k,GetAttachmentTable(u),AddSpellEffectTargetById(s,EFFECT_TYPE_AREA_EFFECT,u,GetAbilityEffectById(s,EFFECT_TYPE_AREA_EFFECT,1)))
                call GroupAddUnit(g,u)
            endif
        endif

        call DamageUnitByOptions(m,u,RagingCharge_Damage(l),RagingCharge_DamageOptions(l))
    endif

 set u=null
 set m=null
 set g=null
endfunction

function RagingCharge_Actions takes nothing returns nothing
 local unit u=GetTriggerUnit()
 local integer s=GetSpellAbilityId()
 local integer l=GetUnitAbilityLevel(u,s)
 local location loc
 local real x=GetUnitX(u)
 local real y=GetUnitY(u)
 local real f
 local timer t=CreateTimer()
 local group g=CreateGroup()
 local trigger tg=CreateTrigger()
 local integer ki=NewTableIndex()
 local string data=I2S(ki)

    call SetTableObject(data,"ac",TriggerAddAction(tg,function RagingCharge_OrbImpact))
    
    call SetTableInt("[RagingCharge]",GetAttachmentTable(t),ki)
    call SetTableInt("[RagingCharge]",GetAttachmentTable(tg),ki)
    call SetTableInt("[RagingCharge]","N",GetTableInt("[RagingCharge]","N")+1)

    if (GetSpellTargetUnit()!=null) then
        set loc=GetUnitLoc(GetSpellTargetUnit())
    else
        set loc=GetSpellTargetLoc()
    endif
    set f=Atan2BJ(GetLocationY(loc)-y,GetLocationX(loc)-x)
    call RemoveLocation(loc)

    call SetTableInt(data,"l",l)
    call SetTableReal(data,"dir",ModuloReal(-f,360))
    call SetTableReal(data,"f",f)
    call SetTableObject(data,"u",u)
    call SetTableObject(data,"g",g)
    call SetTableObject(data,"ran",tg)

    call TriggerRegisterUnitInRange(tg,u,RagingCharge_ImpactRange(l),null)
    call SetTableObject(data,"fx",AddSpellEffectTargetById(s,EFFECT_TYPE_SPECIAL,u,GetAbilityEffectById(s,EFFECT_TYPE_SPECIAL,1)))

    set tg=CreateTrigger()
    call TriggerRegisterUnitEvent(tg,u,EVENT_UNIT_SPELL_ENDCAST)

    call SetTableObject(data,"endT",tg)
    call TimerStart(t,RagingCharge_Timer(),true,function RagingCharge_Mov)
    call SetUnitTimeScale(u,RagingCharge_AnimationSpeed(l))
    call SetUnitAnimationByIndex(u,RagingCharge_AnimationIndex(l))

 set tg=null
 set u=null
 set loc=null
 set t=null
 set g=null
endfunction
function InitTrig_RagingCharge takes nothing returns nothing
 local integer s=RagingCharge_SpellId()
    call OnAbilityEffect(s,"RagingCharge_Actions" )
    call Preload(GetAbilityEffectById(s,EFFECT_TYPE_SPECIAL,0))
    call Preload(GetAbilityEffectById(s,EFFECT_TYPE_TARGET,0))
    call Preload(GetAbilityEffectById(s,EFFECT_TYPE_AREA_EFFECT,0))
endfunction



And repeat the process. Then tell me if the bug happened again. In case you didn't find the problem the first time you don't have to do the second test just tell me it didn't bug for you.
09-16-2006, 10:35 PM#2
Ceo
just tested and had this bug occur after about 10 minutes

testing new code now

for some reason when I try to save the map with the new code it tells me, unable to save "<mapname>" with no errors
09-17-2006, 06:37 AM#3
Captain Griffen
Quote:
Originally Posted by Ceo
just tested and had this bug occur after about 10 minutes

testing new code now

for some reason when I try to save the map with the new code it tells me, unable to save "<mapname>" with no errors

Because WC3 is accessing the map file, so you cannot write to it.
09-17-2006, 07:53 AM#4
BertTheJasser
Will test today evening.
09-18-2006, 01:45 PM#5
Vexorian
okay
09-18-2006, 03:10 PM#6
BertTheJasser
Had no tie so far, you'll have to wait till tomorrow morning.
09-24-2006, 11:34 AM#7
BertTheJasser
My results:
The old code bugged out as you said. Some hydraheads did not disappear.
After inserting the new code I managed to screw up your whole collision missile system(!!!), and hydra did not work anymore.

Btw. Where is the difrence between the 2 codes? (Had no time to have a look at)
Attached Images
File type: jpgBuggedCS.JPG (173.5 KB)
09-24-2006, 05:16 PM#8
Vexorian
what patch are you using?
09-25-2006, 06:28 AM#9
BertTheJasser
1.20e

EDIT:
If it is true, that this is a local machine problem, would you test my Hero Arena? At my PC it has the same problem with collision missiles, taht they start bugging out after about 10-30 min, depending on the player number.
09-25-2006, 08:08 AM#10
MeanMachine
Just Tested:
1. With the old code - bugged. The hero got stuck in the charge forever, the hidras stopped shooting and were never removed. Some missiles were also stuck in the air.
2. With the new code - still bugged. One of the hidras never disapeared.

Replays attached.
BUG.w3g
Still bugged.w3g
Attached Files
File type: w3gBUG.w3g (36.4 KB)
File type: w3gStill bugged.w3g (23.9 KB)
09-25-2006, 01:03 PM#11
Vexorian
It might be a local machine problem indeed, and that would just be the worst thing that could happen. Anyways I highly doubt the problem is really with the collision missiles but with some other code Destroying a Trigger or setting a timer to null.
09-25-2006, 01:26 PM#12
Vexorian
Well I need you 2 guys to test again:
* Do not use RagingCharge this time, only cast Hydra.

If Hydra fails test again, but this time update hydra's code:
Collapse JASS:
//********************************************************************************************************
//*                                 A JESP Spell by Vexorian
//* Codename: Hydra
//* ¯¯¯¯¯¯¯¯
//* Requirements:
//* ¯¯¯¯¯¯¯¯¯¯¯¯¯
//* - The "Hydra" ability
//* - The "Hydra head" unit
//* - The Caster System ( [url]http://wc3campaigns.net/vexorian/[/url] )
//* - This Trigger (MAKE SURE TO change the rawcodes in the trigger to the correct ones of your map)
//*
//* Object Editor fields
//* ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
//* - Unit's First Attack Art - Projectile : Determines the missile effect
//*
//********************************************************************************************************

//===================================================================================================
// Hydra Spell Configuration:
//
//

////
// Important Stuff (Must make sure you change these to correct values)
// ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
// _SpellId : Must match the rawcode of the Hydra Ability
// _UnitId  : Must match the rawcode of the Hydra Head unit, note that you can use different
//            units depending on head index and level.
//
constant function Hydra_SpellId takes nothing returns integer
    return 'A002'
endfunction
constant function Hydra_UnitId takes integer index, integer level returns integer
    return 'o000'
endfunction
constant function Hydra_AttackAnimationPoint takes integer index, integer level returns real
    return 0.5
endfunction

////
// Eye Candy Options
// ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
// _Area           : Spawn distance between the spell cast point and each head
// _FirstSpawnAngle: The angle between the first head and the spell point
// _Animation      : Animation suffix for the different heeads, by index and level
// _Scale          : Model Scale of each head
// _MissileScale   : Model Scale of the missiles by head index and level
//
constant function Hydra_Area takes real level returns real
    return 50+0*level
endfunction
constant function Hydra_FirstSpawnAngle takes integer level returns integer
   return 90
endfunction
constant function Hydra_UnitAnimation takes integer index, integer level returns string
    if (index==3) then
        return "third"
    endif
    if (index==2) then
        return "second"
    endif
 return "first"
endfunction
constant function Hydra_Scale takes integer index, real level returns real
    return 1.0+0.0*level
endfunction
constant function Hydra_MissileScale takes real index, real level returns real
    return 0.5
endfunction
constant function Hydra_MissileHeight takes integer index, integer level returns integer
    if (index==1) then
        return 45
    endif
 return 35
endfunction


////
// Balance Options
// ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
// _Cycle          : Delay in seconds before spitting a new fire bolt
// _Duration       : Total duration of the spell
// _Number         : Number of heads per level
// _BoltSpeed      : Movement speed of the missiles
// _BoltMaxDist    : Maximum distance for missiles' movement
// _BoltImpactDist : Collision Size of each missile
// _ZCollision     : The Collision Size of the missile in the Z axis
//                   (minimum bolt and target flying height difference to allow a hit)
// _Damage         : Damage done by each missile
//
function Hydra_Cycle takes real level returns real
    return 0.4 - 0.05*level
endfunction
constant function Hydra_Duration takes real level returns real
//return 4.9
    return 20+4*level
endfunction
constant function Hydra_Number takes integer level returns integer
    return 3+0*level
endfunction
constant function Hydra_BoltSpeed takes real level returns real
    return 750+0*level
endfunction
constant function Hydra_BoltMaxDist takes real level returns real
    return 2000+0*level
endfunction
constant function Hydra_ImpactDist takes real level returns real
    return 35+0*level
endfunction
constant function Hydra_ZCollision takes real level returns real
    return 60.0
endfunction
function Hydra_Damage takes real level returns real
    return GetRandomReal( 22+3*level , 45+6*level)
    //First is the minimum value, second the maximum, so the result is random
    //Hint : to use random values on other functions make sure to remove the
    //constant preffix
endfunction


////
// Detect Options
// ¯¯¯¯¯¯¯¯¯¯¯¯¯¯
// Determine the kind of units that can be detected by the heads
//
function Hydra_DetectOptions  takes integer level returns integer
    return DamageOnlyEnemies() + DamageOnlyVisibles()
    //Visible Enemies only
endfunction

////
// Explode Options
// ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
// Determine the kind of units that make fireballs explode when they hit them
//
function Hydra_ExplodeOptions  takes integer level returns integer
    return DamageOnlyEnemies()
    //Hit enemies only
endfunction

////
// Damage Options
// ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
// Determine the kind of damage the fireballs cause
//
function Hydra_DamageOptions takes integer level returns integer
    return DamageTypes(ATTACK_TYPE_NORMAL,DAMAGE_TYPE_FIRE)
    //Do normal (spell) fire (magical) damage
endfunction


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

function Hydra_Hit takes nothing returns nothing
 local unit m=GetTriggerCollisionMissile()
 local string mk=GetAttachmentTable(m)
 local string k=I2S(GetTableInt("[Hydra]",mk))
 local unit u
 local integer l
 local unit t=GetTriggerUnit()

    if (t==null) then
        call SetTableInt(k,"fireballs",GetTableInt(k,"fireballs")-1)
        call GroupAddUnit(GetTableGroup(k,"g"),GetTableUnit(k,mk))
    else
        set u=GetTableUnit(k,"u")
        set l=GetTableInt(k,"l")
        if (( RAbsBJ(GetUnitFlyHeight(m)-GetUnitFlyHeight(t) )<=Hydra_ZCollision(l) ) and (GetDamageFactorByOptions(u,t,Hydra_ExplodeOptions(l))!=0)) then
            call CollisionMissile_Destroy(m)
            call DamageUnitByOptions(u,t, Hydra_Damage(l), Hydra_DamageOptions(l))
        endif
        set u=null
        set t=null
    endif
    
 
 set m=null
endfunction

function GetExpiredITimer takes nothing returns integer
    return GetExpiredTimer()
    return 0
endfunction

function CreateITimer takes nothing returns integer
    return CreateTimer()
    return 0
endfunction



function GetRealTimer takes integer t returns timer
    return t
    return null
endfunction

function Hydra_Bolt takes nothing returns nothing
 local integer t=GetExpiredITimer()
 local string kt=I2S(t)
 local integer ki=GetTableInt("[Hydra]",kt)
 local string k=I2S(ki)
 local unit hy=GetTableUnit(k,kt)
 local unit m
 local integer i=GetTableInt(k,GetAttachmentTable(hy))
 local integer l=GetTableInt(k,"l")
 local real s
    call DestroyTimer(GetRealTimer(t))
    
    set m = CollisionMissile_Create(GetAbilityEffectById(GetUnitTypeId(hy),EFFECT_TYPE_MISSILE,0),GetUnitX(hy),GetUnitY(hy),GetUnitFacing(hy),Hydra_BoltSpeed(l),0,Hydra_BoltMaxDist(l),Hydra_MissileHeight(i,l),true,Hydra_ImpactDist(l),function Hydra_Hit)

    set kt=GetAttachmentTable(m)
    call SetTableInt("[Hydra]",kt,ki)
    call SetTableObject(k,kt,hy)
    set s=Hydra_MissileScale(i,l)
    call SetUnitScale(m,s,s,s)

 set m=null
 set hy=null

endfunction

function Hydra_AttackAnim takes unit u, unit hy, real x, real y, real f, integer l, integer ki, string k, integer i returns nothing
 local integer s=Hydra_SpellId()
 local integer t=CreateITimer()
 local string kt=I2S(t)
 
 local string suf=Hydra_UnitAnimation(i,l)
 
    call SetTableInt("[Hydra]",kt,ki)
    call SetTableObject(k,kt,hy)
    call SetUnitFacing(hy,f)
    call SetUnitAnimation(hy,"attack "+suf)
    call QueueUnitAnimation(hy,"stand "+suf)
    call SetTableInt(k,"fireballs",GetTableInt(k,"fireballs")+1)
    call TimerStart(GetRealTimer(t),Hydra_AttackAnimationPoint(i,l),false,function Hydra_Bolt)

endfunction

function Hydra_End takes nothing returns nothing
 local integer t=GetExpiredITimer()
   call SetTableBoolean(I2S(GetTableInt("[Hydra]",I2S(t))),"end",true)
   call DestroyTimer(GetRealTimer(t))

endfunction



function Hydra_OnCycle takes nothing returns nothing
    call ExecuteFunc("Hydra_Attack")
endfunction

function Hydra_GetTarget takes unit ret, group log, integer l, unit u, real x, real y, real z returns unit
 local real f=Hydra_BoltMaxDist(l)
 local real are = f/32
 local real fl
 local group g=CreateGroup()
 local unit rep=null
 local unit p
    if (ret!=null)and(IsUnitInRangeXY(ret,x,y,f)) then
        call GroupAddUnit(g,ret)
    endif
    set ret=null
    set fl=Hydra_ZCollision(l)
    loop
        exitwhen(ret!=null)
        loop
            set p=FirstOfGroup(g)
            exitwhen (p==null) or (ret!=null)
            call GroupRemoveUnit(g,p)       
            if( ( RAbsBJ(GetUnitFlyHeight(p) - z)<=fl) and (GetDamageFactorByOptions(u,p,Hydra_DetectOptions(l))!=0) and ((rep==null) or not(IsUnitInGroup(p,log)) ) )then
                if (IsUnitInGroup(p,log)) then
                    set rep=p
                else
                    set ret=p
                endif
            endif
        endloop
        exitwhen (are>f)
        call GroupEnumUnitsInRange(g,x,y,are,null)
        set are=are+are
    endloop
    if (ret==null) then
        set ret=rep
    endif

 set rep=null
 return ret
endfunction

function Hydra_Attack takes nothing returns nothing
 local integer t=GetExpiredITimer()
 local integer ki=GetTableInt("[Hydra]",I2S(t))
 local integer i
 local string k=I2S(ki)
 local string hk
 local group g=GetTableGroup(k,"g")
 local integer l=GetTableInt(k,"l")
 local integer n
 local group targets = GetTableGroup(k,"targets")

 local unit u=GetTableUnit(k,"u")
 local unit tr
 local unit hy
 local real x
 local real y
 local real f
 local boolean first
 local string tarfield

    if (GetTableBoolean(k,"end")) then
        loop
            exitwhen (GetTableInt(k,"fireballs")<=0)
            call TriggerSleepAction(0)
        endloop

        call GroupAddUnit(g,null)
        loop
            set hy=FirstOfGroup(g)
            exitwhen (hy==null)
            call GroupRemoveUnit(g,hy)
            //set suf=Hydra_UnitAnimation(GetTableInt(k,GetAttachmentTable(hy) ),l)
            call ExplodeUnitBJ(hy)
            //call SetUnitAnimation(hy,"death "+suf)
        endloop
        call DestroyGroup(g)
        call DestroyGroup(targets)

        call DestroyTimer(GetRealTimer(t))
        set n=GetTableInt("[Hydra]","n")
        if (n<=1) then
            call ClearTable("[Hydra]")
        else
            call SetTableInt("[Hydra]","n",n-1)
        endif
        call DestroyTable(k)
    else
        set first=true
        loop
            set hy=FirstOfGroup(g)
            exitwhen (hy==null)
            call GroupRemoveUnit(g,hy)
            if (not first) then
                call TriggerSleepAction(0)
            endif
            set x=GetUnitX(hy)
            set y=GetUnitY(hy)
            set hk=GetAttachmentTable(hy)
            set tarfield="target"+hk
            set tr=GetTableUnit(k,tarfield)
            call GroupRemoveUnit(targets,tr)
            set i=GetTableInt(k,hk)
            set tr=Hydra_GetTarget(tr,targets,l,u,x,y,Hydra_MissileHeight(i,l))
            if (tr!=null) then
                set f=Atan2BJ(GetUnitY(tr)-y,GetUnitX(tr)-x)
                call Hydra_AttackAnim(u,hy,x,y,f,l,ki,k,i)
                call GroupAddUnit(targets,tr)
                call SetTableObject(k,tarfield,tr)
            else
                call GroupAddUnit(g,hy)
                exitwhen true
            endif
            
            set first=false            
        endloop
    
        set tr=null
        call TimerStart(GetRealTimer(t),Hydra_Cycle(l),false,function Hydra_OnCycle)
    endif
  
 set g=null

 set u=null
 set targets=null
endfunction


function Hydra_Actions takes nothing returns nothing
 local integer t=CreateITimer()
 local integer end=CreateITimer()
 
 local unit u=GetTriggerUnit()
 local integer s=GetSpellAbilityId()
 local integer l=GetUnitAbilityLevel(u,s)
 local unit hy
 local integer n=Hydra_Number(l)
 local integer a=0
 local location loc=GetSpellTargetLoc()
 local real x=GetLocationX(loc)
 local real y=GetLocationY(loc)
 local real xu
 local real yu
 local real d=Hydra_Area(l)

 local real h
 local group g=CreateGroup()

 local string suf
 local integer ki=NewTableIndex()
 local string k=I2S(ki)
 local string hk
 local real grad = Hydra_FirstSpawnAngle(l) * bj_DEGTORAD

    call RemoveLocation(loc)
 
    call SetTableInt("[Hydra]","n",GetTableInt("[Hydra]","n")+1)
    call SetTableObject(k,"u",u)
    call SetTableObject(k,"g",g)

    call SetTableObject(k,"targets",CreateGroup())
    call SetTableReal(k,"x",x)
    call SetTableReal(k,"y",y)
    call SetTableInt(k,"l",l)
    call SetTableInt("[Hydra]",I2S(t),ki)
    call SetTableInt("[Hydra]",I2S(end),ki)

    

    loop
        exitwhen a==n

        set yu=Hydra_Area(l)*Sin(grad)
        set xu=Hydra_Area(l)*Cos(grad)
        set hy=CreateUnit(GetOwningPlayer(u),Hydra_UnitId(a+1,l),x+xu,y+yu,270)
        set h=Hydra_Scale(a+1,l)
        call SetUnitScale(hy,h,h,h)
        set suf=Hydra_UnitAnimation(a+1,l)
        call UnitAddAbility(hy,'Aloc')
        set hk=GetAttachmentTable(hy)
        call SetTableInt(k,hk,a+1)
        call SetTableInt("[Hydra]",hk,ki)
        call SetUnitAnimation(hy,"birth "+suf)
        call QueueUnitAnimation(hy,"stand "+suf)
        call GroupAddUnit(g,hy)
        set a=a+1
        if (a<n) then
            call TriggerSleepAction(0)
        endif
        set grad= grad  + (2*bj_PI)/n
    endloop
    call TimerStart(GetRealTimer(t),Hydra_Cycle(l),false,function Hydra_OnCycle )
    call TimerStart(GetRealTimer(end),Hydra_Duration(l),false,function Hydra_End)
 set loc=null
 set u=null
 set g=null

 
 
 
 
endfunction

//===========================================================================
function InitTrig_Hydra takes nothing returns nothing
    call OnAbilityEffect(Hydra_SpellId(),"Hydra_Actions")
endfunction
09-25-2006, 01:28 PM#13
BertTheJasser
I use a dynamic array system which bugged out some time, so in my map this could be even a reason.
09-25-2006, 01:36 PM#14
BertTheJasser
OK, here we go.

This is the code of my hydra (actually it's yours adepted and modified a bit, so they can be dispelled). It works 90% fine, the other 10%, I guess bugs out because of some dumb mistakes I made with some timers and attached arrays, destroying and creating arrays.
Collapse JASS:
constant function Hydra_SpellId takes nothing returns integer
 return 'A00B'
endfunction
constant function Hydra_UnitId takes integer i, integer level returns integer
 return 'o005'
endfunction
constant function Hydra_AttackAnimationPoint takes integer i, integer level returns real
 return 0.5
endfunction

constant function Hydra_Area takes real level returns real
 return 50.
endfunction
constant function Hydra_FirstSpawnAngle takes integer level returns integer
 return 90
endfunction
constant function Hydra_UnitAnimation takes integer i, integer level returns string
    if i==3 then
     return "third"
    endif
    if i==2 then
     return "second"
    endif
 return "first"
endfunction
constant function Hydra_Scale takes integer index, real level returns real
 return 1.0
endfunction
constant function Hydra_MissileScale takes real index, real level returns real
 return 0.5
endfunction
constant function Hydra_MissileHeight takes integer i, integer level returns integer
    if i==1 then
     return 70
    endif
 return 50
endfunction

function Hydra_Cycle takes real level returns real
 return 0.4 - 0.02*level
endfunction
constant function Hydra_Duration takes real level returns real
 return 20.+4.*level
endfunction
constant function Hydra_Number takes integer level returns integer
 return 3
endfunction
constant function Hydra_BoltSpeed takes real level returns real
 return 750.
endfunction
constant function Hydra_BoltMaxDist takes real level returns real
 return 900.
endfunction
constant function Hydra_ImpactDist takes real level returns real
 return 40.
endfunction
function Hydra_Damage takes real level returns real
 return GetRandomReal(22.+3.*level,45.+6.*level)
endfunction

function Hydra_DetectQ  takes integer level returns integer
 return DQ()+FactorAEN(0.,1.,0.)+OnlyVisible()
endfunction

function Hydra_ExplodeQ  takes integer level returns integer
 return DQ()+DamageType(ATTACK_TYPE_NORMAL,DAMAGE_TYPE_FIRE)+FactorAEN(0.,1.,0.)+OnlyVisible()
endfunction

function Hydra_HitX takes nothing returns nothing
 local integer m=GetData(GetTriggeringTrigger())
 local integer k=CollisionMissile_GetCustom(m)
 local integer i=GetArrayInt(k,0)
 local integer a=GetArrayInt(k,1)
 local unit t=GetTriggerUnit()

    if t==null then
        call SetArrayInt(i,6,GetArrayInt(i,6)-1)
        call GroupAddUnit(GetArrayGroup(i,2),GetArrayUnit(k,2))
        //call Msg("Z")
        call DestroyArray(k)
    else
        set a=GetArrayInt(i,5) //a is now the level
        if UnitTreatUnitQ(GetArrayUnit(i,0),t,Hydra_Damage(a),Hydra_ExplodeQ(a))>0 then
            call CollisionMissile_Destroy(m)
            
            //call ClearTextMessages()
            //call Msg("X")
            //k doesn't need to be destroyed, because this trigger gets executed again
            
        endif
    endif
 set t=null
endfunction

function Hydra_Bolt takes nothing returns nothing
 local timer t=GetExpiredTimer()
 local integer k=GetData(t)
 local integer i=GetArrayInt(k,0)
 local integer a=GetArrayInt(k,1)
 local integer l=GetArrayInt(i,5) //level
 local integer m
 local unit hy=GetArrayUnit(k,2)
 local real s
    call PauseTimer(t)
    call DestroyTimer(t)
    
    set m=CollisionMissile_Create(GetAbilityEffectById(GetUnitTypeId(hy),EFFECT_TYPE_MISSILE,0),GetUnitX(hy),GetUnitY(hy),GetUnitFacing(hy),Hydra_BoltSpeed(l),0.,Hydra_BoltMaxDist(l),Hydra_MissileHeight(a,l),true,Hydra_ImpactDist(l),function Hydra_HitX,k)
    set s=Hydra_MissileScale(a,l)
    call SetUnitScale(CollisionMissile_GetMissile(m),s,s,s)
    
 set hy=null
 set t=null
endfunction

function Hydra_AttackAnim takes integer i,integer a,integer l,unit hy,timer t returns nothing
 local string suf=Hydra_UnitAnimation(a,l)
 local integer k=NewArray(3,false)
    call SetArrayInt(i,6,GetArrayInt(i,6)+1) //update fireball num
    call SetUnitAnimation(hy,"attack "+suf)
    call QueueUnitAnimation(hy,"stand "+suf)
    call SetArrayInt(k,0,i)
    call SetArrayInt(k,1,a)
    call SetArrayHandle(k,2,hy)
    call SetData(t,k)
    call TimerStart(t,Hydra_AttackAnimationPoint(a,l),false,function Hydra_Bolt)
endfunction

function Hydra_OnCycle takes nothing returns nothing
 call ExecuteFunc("Hydra_Attack")
endfunction

function Hydra_GetTarget takes unit ret,group log,integer l,unit u, real x, real y returns unit
 local real f=Hydra_BoltMaxDist(l)
 local real are=f/32.
 local group g=CreateGroup()
 local unit rep=null
 local unit p
 local integer qdet=Hydra_DetectQ(l)
    if ret!=null and IsUnitInRangeXY(ret,x,y,f) then
        call GroupAddUnit(g,ret)
    endif
    set ret=null
    loop
        exitwhen ret!=null
        loop
            set p=FirstOfGroup(g)
            exitwhen (p==null) or (ret!=null)
            call GroupRemoveUnit(g,p)
            if UnitTreatUnitQ(u,p,0.,qdet)>0 and (rep==null or not IsUnitInGroup(p,log) ) then
                if IsUnitInGroup(p,log) then
                    set rep=p
                else
                    set ret=p
                endif
            endif
        endloop
        exitwhen are>f
        call GroupEnumUnitsInRadius(g,x,y,are,null)
        set are=are+are
    endloop
    if ret==null then
        set ret=rep
    endif
 set rep=null
 set p=null
 return ret
endfunction

function Hydra_Attack takes nothing returns nothing
 local timer t=GetExpiredTimer()
 local integer i=GetData(t)
 local group targets=GetArrayGroup(i,1)
 local group hyG1=GetArrayGroup(i,2)
 local group hyG2=GetArrayGroup(i,3)
 local integer l=GetArrayInt(i,5)
 local integer n
 local integer j
 local unit u=GetArrayUnit(i,0)
 local unit tg
 local unit hy
 local real x
 local real y
 local real f
    
    if GetArrayInt(i,7)!=0 then
        call PauseTimer(t)
        call DestroyTimer(t)
        loop
            set hy=FirstOfGroup(hyG2)
            exitwhen hy==null
            call GroupRemoveUnit(hyG2,hy)
            call SetUnitOwner(hy,Player(15),false)
            call UnitApplyTimedLife(hy,0,1.043)
            set j=GetData(hy)
            call SetUnitAnimation(hy,"death"+Hydra_UnitAnimation(GetArrayInt(j,0),l))
            call DestroyArray(j)
        endloop
        loop
            exitwhen GetArrayInt(i,6)<=0
            call TriggerSleepAction(0.5)
        endloop
        call DestroyGroup(hyG2)
        call DestroyGroup(hyG1)
        call DestroyGroup(targets)
        call DestroyArray(i)
    else
        loop
            set hy=FirstOfGroup(hyG1)
            exitwhen hy==null
            call GroupRemoveUnit(hyG1,hy)
            if IsUnitInGroup(hy,hyG2) then
                set x=GetUnitX(hy)
                set y=GetUnitY(hy)
                set j=GetData(hy)
                set tg=GetArrayUnit(j,1)
                call GroupRemoveUnit(targets,tg)
                set tg=Hydra_GetTarget(tg,targets,l,u,x,y)
                if tg!=null then
                    call SetArrayHandle(j,1,tg)
                    call SetUnitFacing(hy,Atan2(GetUnitY(tg)-y,GetUnitX(tg)-x)*bj_RADTODEG)
                    call Hydra_AttackAnim(i,GetArrayInt(j,0),l,hy,CreateTimer())
                    call GroupAddUnit(targets,tg)
                else //no tragets availiable -> exit
                    call GroupAddUnit(hyG1,hy)
                    exitwhen true
                endif
                call TriggerSleepAction(0.)
            endif
        endloop
        
        set tg=null
        call TimerStart(t,Hydra_Cycle(l),false,function Hydra_OnCycle)
    endif  
 set targets=null
 set hyG2=null
 set hyG1=null
 set hy=null
 set u=null
 set t=null
endfunction

function Hydra_Death takes nothing returns nothing
 local trigger end=GetTriggeringTrigger()
 local integer i=GetData(end)
 local integer l=GetArrayInt(i,5)
 local integer j
 local unit hy
 local boolean exit= not(GetTriggerEventId()==EVENT_UNIT_DEATH)
    
    if not exit then
        set hy=GetTriggerUnit()
        call GroupRemoveUnit(GetArrayGroup(i,3),hy)
        set exit= (GetTriggerEvalCount(end)>=Hydra_Number(l))
        set j=GetData(hy)
        call SetUnitAnimation(hy,"death "+Hydra_UnitAnimation(GetArrayInt(j,0),l))
        call DestroyArray(j)
    endif
    if exit then
        call SetArrayInt(i,7,1)
        call TriggerRemoveAction(end,GetArrayTriggerAction(i,4))
        call DestroyTrigger(end)
    endif
 set end=null
 set hy=null
endfunction

function Hydra_Actions2 takes unit u,integer s,timer t,trigger end,group targets,group hyG1,group hyG2,real x,real y returns nothing
 local unit hy
 local integer l=GetUnitAbilityLevel(u,s)
 local integer n=Hydra_Number(l)
 local integer a=0
 local integer i=NewArray(8,false)
 local integer j=0
 local real xu
 local real yu
 local real d=Hydra_Area(l)
 local real z
 local real grad=(Hydra_FirstSpawnAngle(l)*bj_DEGTORAD)
 local real inc=((2.0*bj_PI)/n)
 local string suf
    
    call SetData(t,i)
    call SetData(end,i)
    
    call SetArrayHandle(i,0,u)
    call SetArrayHandle(i,1,targets)//targets
    call SetArrayHandle(i,2,hyG1)//hydras
    call SetArrayHandle(i,3,hyG2)//hydras2
    call SetArrayHandle(i,4,TriggerAddAction(end,function Hydra_Death))
    call SetArrayInt   (i,5,l)
    call SetArrayInt   (i,6,0)//fireballs
    call SetArrayInt   (i,7,0)//exit
    
    loop
        set a=a+1
        set yu=d*Sin(grad)
        set xu=d*Cos(grad)
        set hy=CreateUnit(GetOwningPlayer(u),Hydra_UnitId(a,l),x+xu,y+yu,grad*bj_RADTODEG)
        call SetUnitPathing(hy,false)
        call SetUnitXY(hy,x+xu,y+yu)
        call UnitAddType(hy,UNIT_TYPE_SUMMONED)
        set z=Hydra_Scale(a,l)
        call SetUnitScale(hy,z,z,z)
        set suf=Hydra_UnitAnimation(a,l)
        call SetUnitAnimation(hy,"birth "+suf)
        call QueueUnitAnimation(hy,"stand "+suf)
        call TriggerRegisterUnitEvent(end,hy,EVENT_UNIT_DEATH)
        call GroupAddUnit(hyG2,hy)
        call GroupAddUnit(hyG1,hy)
        set j=NewArray(3,false)
        call SetData(hy,j)
        call SetArrayInt(j,0,a)
        call SetArrayInt(j,1,0)//current target is no target
        exitwhen a>=n
        call TriggerSleepAction(0.)
        set grad=grad+inc
    endloop
    call TriggerRegisterTimerEvent(end,Hydra_Duration(l),false)
    call TimerStart(t,Hydra_Cycle(l),false,function Hydra_OnCycle)
 set hy=null
endfunction

function Hydra_Actions takes nothing returns nothing
 local location loc=GetSpellTargetLoc()
    call Hydra_Actions2(GetTriggerUnit(),GetSpellAbilityId(),CreateTimer(),CreateTrigger(),CreateGroup(),CreateGroup(),CreateGroup(),GetLocationX(loc),GetLocationY(loc))
    call RemoveLocation(loc)
 set loc=null
endfunction

function InitTrig_Hydra takes nothing returns nothing
call RegisterAbilityEvent(Hydra_SpellId(),"Hydra_Actions")
endfunction
09-25-2006, 01:59 PM#15
BertTheJasser
Still bugging. Added screenshoot again.
But now when the hero casts the spell again, then hydra works again, not like the last time.
Attached Images
File type: jpgStillBugging.JPG (93.2 KB)