scope FireMassing initializer init
//>>>>>>>>>>>>>>>>>>>>>>>>>SETUP<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<//
//Đây là phần cài đặt cho spell:
globals
private constant integer SPELL_ID = 'A001'//ID của dummy ability mà bạn dùng, phải là 1 abi target ground hoặc target unit
private constant integer DUMMY_UNIT_ID = 'e000'//cái này hình như thừa... cứ thử bỏ đi xem. Tại spell làm lâu rồi cũng chẳng nhớ LOL
private constant integer EFF_UNIT_ID = 'e002'//Unit đóng vai trò missle
private constant string EFF = "Abilities\\Spells\\Other\\Doom\\DoomDeath.mdl"//Hiệu ứng đặc biệt khi tên chạm enemy hoặc đã bay hết quãng đg cho phép
//"Abilities\\Weapons\\Rifle\\RifleImpact.mdl"
//"Abilities\\Spells\\Human\\SpellSteal\\SpellStealMissile.mdl"
//"Abilities\\Spells\\Other\\BreathOfFire\\BreathOfFireDamage.mdl"
//"Abilities\\Spells\\Other\\Doom\\DoomDeath.mdl"
endglobals
//Advance:
private function speed takes nothing returns real
return 0.01 //lager value, more slower (tốc độ của mũi tên, vì là time out của timer nên càng nhỏ thì mũi tên bay càng nhanh)
endfunction
private function range takes nothing returns real
return 1500.00 //quãng đường tối đa ma mũi tên có thể bay
endfunction
private function radius takes nothing returns real
return 100.00 //the radius for detecting collision (Bán kính phát hiện va chạm AOE/2 đó

)
endfunction
private function amount takes nothing returns integer
return 10 //the numbers of arrow per cast (số lượng mũi tên)
endfunction
private function dam takes integer aLevel returns real
return 100.00 * aLevel//dam per arrow (hàm tính dam dựa theo lvl skill)
endfunction
private function addOn takes unit trigUnit, unit dam2Unit returns nothing
//this option is for advance user, you can add your code here to Make
//more effect when the projectile impact to enemy. ex: knock back, dam over time...
// hàm này được gọi khi mũi tên va chạm với enemy, hàm này hiện để trống, muốn thêm cái gì vào đây thì thêm
//à quên trigUnit là caster, dam2Unit là unit bị bắn trúng
endfunction
//>>>>>>>>>>>>>>>>>>>>>>>ENDSETUP<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<//
//=================Confuse zone==============//
//Dont edit this bunk of code unless you
//really wanna do
//Phần dưới này để thư thư rồi giải thích tiếp nhé

//===========================================//
globals
private constant real MOVE = 10.0 //distance that the projectile will move Per
//*speed()* . You should'nt change this
private constant real deviation = 10.0 //deviation between projectile
endglobals
private struct Projectile
unit u//projectile
unit uT// trigger unit
real angle
real moved = 0
boolean stop = false
method control takes nothing returns nothing
local location moveLoc = PolarProjectionBJ(GetUnitLoc(.u), MOVE, .angle)
//valriable for collision detect:
local group cGrp = GetUnitsInRangeOfLocAll(radius(),moveLoc)
local unit uDam
//move the unit(projectile)
call SetUnitPositionLoc(.u,moveLoc)
//collision detect and dam enemy:
set uDam = FirstOfGroup(cGrp)
if uDam != null then
loop
exitwhen uDam == null
if IsUnitEnemy(uDam,GetOwningPlayer(.uT)) and IsUnitAliveBJ(uDam) then
call UnitDamageTargetBJ(.uT, uDam, dam(GetUnitAbilityLevel(.uT,SPELL_ID)),ATTACK_TYPE_MAGIC,DAMAGE_TYPE_MAGIC)
call addOn(.uT,uDam)
set .stop = true//need improve
endif
call GroupRemoveUnit(cGrp,uDam)
set uDam = FirstOfGroup(cGrp)
endloop
endif
//out of range detect:
if .moved < range() then
set .moved = .moved + MOVE//if still in range, then set the .moved value go up
else
set .stop = true
endif
//play animation
if .stop then
call DestroyEffect(AddSpecialEffectLoc(EFF,moveLoc))
endif
//remove leak
call RemoveLocation(moveLoc)
call DestroyGroup(cGrp)
set moveLoc = null
set cGrp = null
set uDam = null
endmethod
endstruct
globals
private integer Total = 0
private timer T = CreateTimer()
private Projectile array pArr
endglobals
private function timerLoop takes nothing returns nothing
local integer i = 0
loop
exitwhen(i >= Total)
if pArr
.stop then
call KillUnit(pArr.u)//kill the projectile to not display it any more
call pArr.destroy()//Not need this instance any more
set Total=Total-1//degrease the Total by 1
if Total > 0 then
set pArr=pArr[Total]
set i=i-1//if not the loops will forget to handle the pArr[Total] ^^
else
call PauseTimer(T)
endif
else
call pArr.control()
endif
set i = i + 1
endloop
//call BJDebugMsg("yeah")
endfunction
//extra function for formula caculate:
private function angleCalculate takes real angle, integer iAddOne returns real
local real result = 0
//==========for div number of *amount()*:
local real halfDev //deviation / 2
local real cen1
local real cen2
local integer cen1Index
local integer cen2Index
//==========for odd number of *amount()*:
local integer cenIndex
local real cen
//div:
if ModuloInteger(amount(),2)==0 then
//call BJDebugMsg("so chan")
set halfDev = deviation/2
set cen1 = angle - halfDev
set cen2 = angle + halfDev
set cen1Index = amount()/2
set cen2Index = cen1Index + 1
if iAddOne == cen1Index then
set result = cen1
elseif iAddOne < cen1Index then
set result = cen1 - deviation*(cen1Index - iAddOne)
elseif iAddOne == cen2Index then
set result = cen2
elseif iAddOne > cen2Index then
set result = cen2 + deviation*(iAddOne - cen2Index)
endif
//odd:
else
//call BJDebugMsg("so le")
set cen = angle
set cenIndex = ((amount() - 1)/2) + 1
if iAddOne == cenIndex then
set result = angle
elseif iAddOne > cenIndex then
set result = cen - (deviation*(iAddOne - cenIndex))
else
set result = cen + (deviation*(cenIndex - iAddOne))
endif
endif
return result
endfunction
//====================end=====================//
//Condition================================================================
private function condition takes nothing returns boolean
return GetSpellAbilityId() == SPELL_ID
endfunction
//Actions==================================================================
private function Actions takes nothing returns nothing
local player pT = GetOwningPlayer(GetTriggerUnit())
local location tar = GetSpellTargetLoc()
local location self = GetUnitLoc(GetTriggerUnit())
local real deg = AngleBetweenPoints(self,tar)
local Projectile p
//
local integer iPlus = 1
if Total == 0 then
call TimerStart (T, speed(), true, function timerLoop)
endif
//
loop
exitwhen iPlus > amount()
set p = Projectile.create()
set p.u = CreateUnitAtLoc(pT,EFF_UNIT_ID,self,angleCalculate(deg,iPlus))
set p.angle = angleCalculate(deg,iPlus)
set p.uT = GetTriggerUnit()
//call BJDebugMsg(R2S(angleCalculate(deg,iPlus)))
//call BJDebugMsg(I2S(Total))
set pArr[Total] = p
set Total = Total + 1
set iPlus = iPlus + 1
endloop
//remove leak
set pT = null
call RemoveLocation(tar)
call RemoveLocation(self)
set tar = null
set self = null
endfunction
//Initializer==============================================================
private function init takes nothing returns nothing
local trigger t = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( t, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddAction( t, function Actions )
call TriggerAddCondition(t,Condition(function condition))
endfunction
endscope
demo map: http://dl.dropbox.com/u/14083092/Map...FireRanger.w3x
Spell đơn giản thôi, bắn 1 lượng cung tùy ý ra phía trước. Có thể thêm bất cứ hiệu ứng nào vào unit bị trúng tên (dam over time hay knock back.... tùy)
Có gì giải thích sau nhé h đang bận với cái project