- Joined
- Mar 3, 2006
- Messages
- 1,564
I am really having a very strange bug regarding HandleId. I don't know how to explain it but I will try.
I am trying to make a chain spell so here are the Initial triggers (ignore leaks and any other bugs)
All highlighted lines are part of the bug (or what I think it is)
Now, to the
I have tried many things at it gave me strange results:
- When the spell is cast once and waited for it to end the last unit takes normal damage. No problems for this one.
- When I hold Shift and click twice on a target, every unit takes twice damage except the last one in the chain that took the damage one time.
- At first I solved this problem by changing the filter in the GetNearest function I added GetWidgetLife and it worked normally when cast many times. (don't know why)
- Next time I removed GetWidgetLife and changed the timer time to 0.02 and ,strangely, the spell worked normally.
- I reset the timer to 0.01 and decided to track the unit handle Id so I added a line to view the Id and here is the results I get:
(Note: The result will varry from each run)
- for single cast:
target[1] = 1048731
target[1] = 1048730
target[1] = 1048729
- for 3 casts:
target[1] = 1048731
target[1] = 1048730
target[2] = 1048731
target[1] = 1048729
target[2] = 1048730
target[3] = 1048731
target[2] = 1048750
target[3] = 1049101
I don't understand how the id changed, I hope someone explain this to me. And sorry for all this long post.
I am trying to make a chain spell so here are the Initial triggers (ignore leaks and any other bugs)
All highlighted lines are part of the bug (or what I think it is)
JASS:
scope ChainFire initializer Init_ChainFire
globals
private constant integer ABILTY_ID = 'A001'
private constant integer CHFIRE_ID = 'c000'
private constant timer cf_timer = CreateTimer()
@private constant real CF_TIMER_INTERVAL = 0.01000@
private constant real STEP_DIST = 16.00
private constant real CHEK_DIST = 24.00
private constant real DAMAGE = 55.00
private constant integer JUMP = 4
private integer index = 0
private integer array temp_dat
private hashtable unit_flag = InitHashtable()
private constant attacktype ATKTYPE = ATTACK_TYPE_NORMAL // Spell Attack Type
private constant damagetype DMGTYPE = DAMAGE_TYPE_FIRE // Fire Damage Type
endglobals
function GetNearestUnitOfUnitExGroup takes unit source, real radius, integer ht_index returns unit
local group g = CreateGroup()
local group temp_g = CreateGroup()
local real locX = GetUnitX(source)
local real locY = GetUnitY(source)
local real dx
local real dy
local unit ref_u
local unit any_u
local unit temp_u
local real dist_ref_u
local real dist_any_u
call GroupEnumUnitsInRange(temp_g,locX,locY,radius,null)
loop
set temp_u = FirstOfGroup(temp_g)
exitwhen temp_u == null
@if temp_u != LoadUnitHandle(unit_flag,ht_index,GetHandleId(temp_u)) /*and GetWidgetLife(temp_u) >= 0.405 and IsUnitEnemy(temp_u,Player(0))*/ then@
call GroupAddUnit(g,temp_u)
endif
call GroupRemoveUnit(temp_g,temp_u)
endloop
call DestroyGroup(temp_g)
set ref_u = FirstOfGroup(g)
call GroupRemoveUnit(g,ref_u)
loop
set any_u = FirstOfGroup(g)
exitwhen any_u == null
set dx = GetUnitX(ref_u) - locX
set dy = GetUnitY(ref_u) - locY
set dist_ref_u = SquareRoot(dx*dx + dy*dy)
set dx = GetUnitX(any_u) - locX
set dy = GetUnitY(any_u) - locY
set dist_any_u = SquareRoot(dx*dx + dy*dy)
if dist_ref_u > dist_any_u then
set ref_u = any_u
endif
call GroupRemoveUnit(g,any_u)
endloop
call DestroyGroup(g)
return ref_u
endfunction
struct data
unit caster
unit target
unit cfd // Chain Fire Dummy
integer jump
real face
static method MoveCF takes nothing returns nothing
local thistype dat
local integer i = 0
local real x // Current X of Chain Fire Missile
local real y // Current Y of Chain Fire Missile
local real tx // Target X
local real ty // Target Y
local real ptx // Previous Target X
local real pty // Previous Target Y
local real dx
local real dy
local real dist
loop
exitwhen i >= index
set dat = temp_dat[i]
set x = GetUnitX(dat.cfd)
set y = GetUnitY(dat.cfd)
set tx = GetUnitX(dat.target)
set ptx = tx
set ty = GetUnitY(dat.target)
set pty = ty
set dx = tx - x
set dy = ty - y
set dist = SquareRoot(dx*dx + dy*dy)
if dist < CHEK_DIST then
call UnitDamageTarget(dat.caster, dat.target,DAMAGE, false, false, ATKTYPE, DMGTYPE, null)
@call SaveUnitHandle(unit_flag,dat,GetHandleId(dat.target),dat.target)@
set dat.jump = dat.jump - 1
if dat.jump <= 0 then // end the spell
set index = index - 1
set temp_dat[i] = temp_dat[index]
set i = i - 1
call KillUnit(dat.cfd)
set dat.caster = null
set dat.target = null
call FlushChildHashtable( unit_flag , dat )
if index == 0 then
call PauseTimer(cf_timer)
endif
call dat.deallocate()
else
// seek the next target
@set dat.target = GetNearestUnitOfUnitExGroup(dat.target,500.0,dat)@
@call BJDebugMsg("target["+I2S(dat)+"] = "+I2S(GetHandleId(dat.target)))@
// if there is no unit then end the spell, also
if dat.target == null then
call BJDebugMsg("Spell Ended no new target")
set dat.jump = 0
set index = index - 1
set temp_dat[i] = temp_dat[index]
set i = i - 1
call KillUnit(dat.cfd)
set dat.caster = null
set dat.target = null
call FlushChildHashtable( unit_flag , dat )
if index == 0 then
call PauseTimer(cf_timer)
endif
call dat.deallocate()
else
// set the facing and locations again as done in StartCF method
// since tx and ty have not been set to another value then use it again
set dx = GetUnitX(dat.target) - ptx
set dy = GetUnitY(dat.target) - pty
set dat.face = Atan2(dy,dx)
call SetUnitFacing(dat.cfd,dat.face * bj_RADTODEG)
endif
endif
else
call SetUnitX(dat.cfd,x + STEP_DIST * Cos(dat.face))
call SetUnitY(dat.cfd,y + STEP_DIST * Sin(dat.face))
endif
set i = i + 1
endloop
endmethod
static method StartCF takes unit caster, unit target returns nothing
local thistype dat = thistype.allocate()
local real cx // Caster X
local real cy // Caster Y
local real tx // Target X
local real ty // Target Y
local real dx
local real dy
set temp_dat[index] = dat
set dat.caster = caster
set dat.target = target
set dat.jump = JUMP
set cx = GetUnitX(caster)
set cy = GetUnitY(caster)
set tx = GetUnitX(target)
set ty = GetUnitY(target)
set dx = tx - cx
set dy = ty - cy
set dat.face = Atan2(dy,dx)
set dat.cfd = CreateUnit(GetOwningPlayer(caster),CHFIRE_ID,cx,cy,dat.face*bj_RADTODEG)
if index ==0 then
call TimerStart(cf_timer,CF_TIMER_INTERVAL,true,function thistype.MoveCF)
endif
set index = index + 1
endmethod
endstruct
function CF_Actions takes nothing returns nothing
if GetSpellAbilityId() == ABILTY_ID then
call data.StartCF(GetTriggerUnit(),GetSpellTargetUnit())
endif
endfunction
function Init_ChainFire takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddAction(t,function CF_Actions)
endfunction
endscope
bug
When the spell is cast rapidly (i.e. hold Shift + Many Clicks on the target) the last unit in the chain takes the damage from the first cast only and ignores the rest although the missile dummy goes towards it.
- When the spell is cast once and waited for it to end the last unit takes normal damage. No problems for this one.
- When I hold Shift and click twice on a target, every unit takes twice damage except the last one in the chain that took the damage one time.
- At first I solved this problem by changing the filter in the GetNearest function I added GetWidgetLife and it worked normally when cast many times. (don't know why)
- Next time I removed GetWidgetLife and changed the timer time to 0.02 and ,strangely, the spell worked normally.
- I reset the timer to 0.01 and decided to track the unit handle Id so I added a line to view the Id and here is the results I get:
(Note: The result will varry from each run)
- for single cast:
target[1] = 1048731
target[1] = 1048730
target[1] = 1048729
- for 3 casts:
target[1] = 1048731
target[1] = 1048730
target[2] = 1048731
target[1] = 1048729
target[2] = 1048730
target[3] = 1048731
target[2] = 1048750
target[3] = 1049101
I don't understand how the id changed, I hope someone explain this to me. And sorry for all this long post.
Last edited: