The Undaddy
Creating with the power of rage
- Reaction score
- 55
Rainbow Strike
by The Undaddy
Requires NewGenby The Undaddy
Fairly Big Image Ahead*
Description
Rainbow Strike
Summons up to [7] colored orbs to circle the target unit,eventually hitting it and dealing damage,also dealing damage to all units they pass trough* (not only once but every time an orb passes trough a unit).Also some orbs cast another ability when colliding with the unit.
*The units must also be with a maximum of 55 flying height difference from the orbs.
Summons up to [7] colored orbs to circle the target unit,eventually hitting it and dealing damage,also dealing damage to all units they pass trough* (not only once but every time an orb passes trough a unit).Also some orbs cast another ability when colliding with the unit.
*The units must also be with a maximum of 55 flying height difference from the orbs.
Alternatively, tooltip ingame:
Rainbow Strike
The keeper of the grove uses his connection with nature to summon 7 orbs containing the colors of the rainbow to strike his foes.
Level 1:
Summons the first three colors of the rainbow.
Deals a total of 25 damage to the target and 5 damage every time and orb passes through an enemy unit
Casts Purge
Level 2:
Summons the first five colors of the rainbow.
Deals a total of 50 damage to the target and 10 damage every time and orb passes through an enemy unit
Casts Purge and Shadow Strike
Level 3:
Summons all seven colors of the rainbow.
Deals a total of 75 damage to the target and 15 damage every time and orb passes through an enemy unit
Casts Purge, Shadow Strike and Thunder Clap
The keeper of the grove uses his connection with nature to summon 7 orbs containing the colors of the rainbow to strike his foes.
Level 1:
Summons the first three colors of the rainbow.
Deals a total of 25 damage to the target and 5 damage every time and orb passes through an enemy unit
Casts Purge
Level 2:
Summons the first five colors of the rainbow.
Deals a total of 50 damage to the target and 10 damage every time and orb passes through an enemy unit
Casts Purge and Shadow Strike
Level 3:
Summons all seven colors of the rainbow.
Deals a total of 75 damage to the target and 15 damage every time and orb passes through an enemy unit
Casts Purge, Shadow Strike and Thunder Clap
Here comes the code:
JASS:
scope RainbowStrike initializer Init
globals
private group G = CreateGroup()
private group InRange = CreateGroup()
private group InRangeCpy = CreateGroup()
private player p
private unit u
private real r
private real gz
private location l = Location(0,0)
private constant integer ABILITY_ID = 039;A000039; //Obviously,the raw code of the spell used
private constant integer ELEMENT_ID = 039;e000039; //The raw code of the units that will cricle the taarget
private constant real DIST_FROM_TRG = 270 //The radius of the circle around the target
private constant real TIME_TO_REACH = 0.4 //The initial time it takes the orbs for them to take their places [this is not a dead-on amount of time,more like and approximation]
private constant integer DUMMY_ID = 039;e002039; //Raw code of the dummy unit that will cast spells on respective orbs [more below]
private constant attacktype ATTACK_TYPE = ATTACK_TYPE_HERO
private constant damagetype DAMAGE_TYPE = DAMAGE_TYPE_NORMAL
private constant weapontype WEAPON_TYPE = WEAPON_TYPE_WHOKNOWS
private constant string ATTACH_STRING = "origin"
private constant string MODEL_FILE = "Abilities\\Weapons\\ChimaeraLightningMissile\\ChimaeraLightningMissile.mdl"
private integer array EL_R
private integer array EL_G
private integer array EL_B
private integer array ABIL
private integer array TYPE //1 - target ,2 - no target,3 - point target
private string array ORDER
endglobals
function Define takes nothing returns nothing
set EL_R[0] = 255 //These are the colors of the elements summoned in RGB format
set EL_G[0] = 0
set EL_B[0] = 0
set EL_R[1] = 255
set EL_G[1] = 127
set EL_B[1] = 0
set EL_R[2] = 255
set EL_G[2] = 255
set EL_B[2] = 0
set EL_R[3] = 0
set EL_G[3] = 255
set EL_B[3] = 0
set EL_R[4] = 0
set EL_G[4] = 0
set EL_B[4] = 255
set EL_R[5] = 70
set EL_G[5] = 0
set EL_B[5] = 130
set EL_R[6] = 238
set EL_G[6] = 130
set EL_B[6] = 238
set ABIL[0] = 039;A001039; //these are the abilities the dummy will cast on the respective orbs
set TYPE[0] = 1 //This is target type,once again 1 is for unit target,2 is for no target and 3 is for point target
set ORDER[0] = "purge" //This is the order that must be issued in order for the dummy to cast the correct ability
set ABIL[1] = 0
set TYPE[1] = 0
set ABIL[2] = 0
set TYPE[2] = 0
set ABIL[3] = 039;A002039;
set TYPE[3] = 1
set ORDER[3] = "shadowstrike"
set ABIL[4] = 0
set TYPE[4] = 0
set ABIL[5] = 0
set TYPE[5] = 0
set ABIL[6] = 039;A003039;
set ORDER[6] = "thunderclap"
set TYPE[6] = 2
endfunction
private constant function ELEMENT_QUANTITY takes integer lvl returns integer //Obviously,how many elements are summoned
return 3 + (lvl-1)*2
endfunction
private constant function CHARGE_INTERVAL takes integer lvl returns real //This is the time one orb waits to attack after the previous one
return 0.8/(lvl - (lvl-1)*0.5)
endfunction
private constant function INITIAL_PERIOD takes integer lvl returns real //For how long the orbs will rotate before they start charging
return 1.2 + lvl*0.3
endfunction
private constant function CHARGE_SPEED takes integer lvl returns real //This is how fast the element charges
return 500.
endfunction
private constant function ANGLE_INCR_PER_SEC takes integer lvl returns real //This is how fast the orbs rotate around the unit, degrees/second
return 220.
endfunction
private constant function DAMAGE takes integer lvl returns real //Impact damage
return lvl*25.
endfunction
private constant function PASS_DAMAGE takes integer lvl returns real //Pass-through damage
return lvl*5.
endfunction
//Note: If cast on an enemy unit the damage dealt to the target will be
// NumberOfElements*(Damage + PassDamage)
private function SetUnitZ takes unit u,real z returns nothing
call MoveLocation(l,GetUnitX(u),GetUnitY(u))
if u != null then
call UnitAddAbility(u,039;Amrf039;)
call UnitRemoveAbility(u,039;Amrf039;)
call SetUnitFlyHeight(u,z - GetLocationZ(l),0)
endif
endfunction
private function GetUnitZ takes unit u returns real
local real z
call MoveLocation(l,GetUnitX(u),GetUnitY(u))
set z = GetLocationZ(l)
if u != null then
return z + GetUnitFlyHeight(u)
endif
return 0.
endfunction
private function GetPolarProjX takes real x, real angle, real dist returns real
return x + dist * Cos(angle * bj_DEGTORAD)
endfunction
private function GetPolarProjY takes real y, real angle, real dist returns real
return y + dist * Sin(angle * bj_DEGTORAD)
endfunction
private function IsEnemy takes nothing returns boolean
local unit u = GetFilterUnit()
local boolean bool
set bool = (IsUnitEnemy(u,p) and RAbsBJ(GetUnitZ(u) - gz) < 55) and GetUnitState(u, UNIT_STATE_LIFE) > .405
set u = null
return bool
endfunction
private function dmgenum takes nothing returns nothing
call DestroyEffect(AddSpecialEffectTarget(MODEL_FILE,GetEnumUnit(),ATTACH_STRING))
call UnitDamageTarget(u,GetEnumUnit(),r,false,false,ATTACK_TYPE,DAMAGE_TYPE,WEAPON_TYPE)
endfunction
private struct SpellData
unit target
unit caster
player owner
integer level
integer mode
unit array element[40]
real array ToAngle[40]
real array covered[40]
real array dtt[40]
group array damaged[40]
real allheight
real chspd
integer elements
integer charging
integer removed
real angincr
real period
real elapsed
real damage
real passdamage
method periodic takes nothing returns boolean
local integer a = 0
local real fulldist
local real dist
local real angle
local real x = GetUnitX(.target)
local real y = GetUnitY(.target)
local real z = GetUnitZ(.target)
local real Ex
local real Ey
local real Ox
local real Oy
local real height
local unit dummy
local boolean distb = true
local boolean heightb = false
if .mode == 0 then
set height = z - GetUnitZ(.element[0])
if height <= (height + .allheight)/(TIME_TO_REACH*T32_FPS) then
set heightb = true
endif
loop
exitwhen a >= .elements
set Ex = GetUnitX(.element[a])
set Ey = GetUnitY(.element[a])
set Ox = GetPolarProjX(x,.ToAngle[a],DIST_FROM_TRG)
set Oy = GetPolarProjY(y,.ToAngle[a],DIST_FROM_TRG)
set dist = SquareRoot((Ox- Ex)*(Ox - Ex) + (Oy - Ey)*(Oy - Ey))
set fulldist = dist + .covered[a]
set angle = bj_RADTODEG * Atan2(Oy - Ey, Ox - Ex)
if dist <= fulldist/(TIME_TO_REACH*T32_FPS) then
call SetUnitX(.element[a],Ox)
call SetUnitY(.element[a],Oy)
set .dtt[a] = DIST_FROM_TRG
else
set distb = false
call SetUnitX(.element[a],GetPolarProjX(Ex,angle,fulldist/(TIME_TO_REACH*T32_FPS)))
call SetUnitY(.element[a],GetPolarProjY(Ey,angle,fulldist/(TIME_TO_REACH*T32_FPS)))
set .covered[a] = .covered[a] + fulldist/(TIME_TO_REACH*T32_FPS)
endif
if heightb then
call SetUnitZ(.element[a],z + 25)
else
call SetUnitZ(.element[a],GetUnitZ(.element[a]) + (.allheight + height)/(TIME_TO_REACH*T32_FPS) + 25)
endif
set a = a + 1
endloop
if distb and heightb then
set .mode = 1
return false
endif
set .allheight = .allheight + (.allheight + height)/(TIME_TO_REACH*T32_FPS)
else
set .elapsed = .elapsed + T32_PERIOD
if .elapsed >= .period and .charging + .removed < .elements then
set .elapsed = .elapsed - .period
set .charging = .charging + 1
endif
set a = .removed
loop
exitwhen a >= .elements
set Ex = GetUnitX(.element[a])
set Ey = GetUnitY(.element[a])
set p = .owner
set gz = z
call GroupEnumUnitsInRange(InRange,Ex,Ey,100,Condition(function IsEnemy))
call GroupAddGroup(InRange,InRangeCpy)
//set bj_wantDestroyGroup = true
call GroupRemoveGroup(.damaged[a],InRange)
set u = .caster
set r = .passdamage
call ForGroup(InRange,function dmgenum)
call GroupClear(.damaged[a])
call GroupAddGroup(InRangeCpy,.damaged[a])
call GroupClear(InRange)
call GroupClear(InRangeCpy)
set .ToAngle[a] = .ToAngle[a] - .angincr
set Ox = GetPolarProjX(x,.ToAngle[a],.dtt[a])
set Oy = GetPolarProjY(y,.ToAngle[a],.dtt[a])
call SetUnitX(.element[a],Ox)
call SetUnitY(.element[a],Oy)
call SetUnitZ(.element[a],z + 25)
//if .dtt >= DIST_FROM_TRG then
call SetUnitFacing(.element[a],.ToAngle[a] - 90)
//else
// call SetUnitFacing(.element[a],-.ToAngle[a])
//endif
set a = a + 1
endloop
set a = .removed
loop
exitwhen a >= .charging + .removed
if .dtt[a] <= 0 then
call KillUnit(.element[a])
set .removed = .removed + 1
set .charging = .charging - 1
//EFFECT CODE
call UnitDamageTarget(.caster,.target,.damage,false,false,ATTACK_TYPE,DAMAGE_TYPE,WEAPON_TYPE)
if ABIL[a] != 0 then
set dummy = CreateUnit(GetOwningPlayer(.caster),DUMMY_ID,x,y,0)
call SetUnitPosition(dummy,x,y)
call UnitApplyTimedLife(dummy,0,5)
call UnitAddAbility(dummy,ABIL[a])
if TYPE[a] == 1 then
call IssueTargetOrder(dummy,ORDER[a],.target)
elseif TYPE[a] == 2 then
call IssueImmediateOrder(dummy,ORDER[a])
elseif TYPE[a] == 3 then
call IssuePointOrder(dummy,ORDER[a],x,y)
endif
set dummy = null
endif
endif
set .dtt[a] = .dtt[a] - .chspd
set a = a + 1
endloop
if .removed == .elements then
call .destroy()
return true
endif
endif
return false
endmethod
static method create takes unit trg, unit cst, integer lvl returns thistype
local SpellData sd = SpellData.allocate()
local integer a = 0
local real random = GetRandomInt(0,360)
local real x = GetUnitX(cst)
local real y = GetUnitY(cst)
local real ang = bj_RADTODEG * Atan2(GetUnitY(trg) - y, GetUnitX(trg) - x)
local real spwnx = GetPolarProjX(x,ang,200)
local real spwny = GetPolarProjY(y,ang,200)
set sd.owner = GetOwningPlayer(cst)
set sd.elements = ELEMENT_QUANTITY(lvl)
set sd.period = CHARGE_INTERVAL(lvl)
set sd.target = trg
set sd.caster = cst
set sd.level = lvl
set sd.mode = 0
set sd.elapsed = 0
set sd.removed = 0
set sd.charging = 0
set sd.allheight = 0
set sd.elapsed = -INITIAL_PERIOD(lvl) + sd.period
set sd.angincr = ANGLE_INCR_PER_SEC(lvl)/T32_FPS
set sd.chspd = CHARGE_SPEED(lvl)/T32_FPS
set sd.damage = DAMAGE(lvl)/sd.elements
set sd.passdamage = PASS_DAMAGE(lvl)
loop
exitwhen a >= sd.elements
set sd.element[a] = CreateUnit(sd.owner,ELEMENT_ID,spwnx,spwny,0)
set sd.ToAngle[a] = (360/sd.elements)*(a + 1) + random
set sd.covered[a] = 0
if sd.damaged[a] == null then
//call BJDebugMsg("damaged[" + I2S(a) + "] created")
set sd.damaged[a] = CreateGroup()
endif
call SetUnitVertexColor(sd.element[a],EL_R[a],EL_G[a],EL_B[a],255)
set a = a + 1
endloop
call sd.startPeriodic()
return sd
endmethod
implement T32
endstruct
function Cdt takes nothing returns boolean
if GetSpellAbilityId() == ABILITY_ID then
call SpellData.create(GetSpellTargetUnit(),GetTriggerUnit(),GetUnitAbilityLevel(GetTriggerUnit(),ABILITY_ID))
endif
return false
endfunction
function Init takes nothing returns nothing
local trigger t = CreateTrigger()
call Define()
call TriggerRegisterAnyUnitEventBJ(t,EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(t,Condition(function Cdt))
endfunction
endscope
Systems Used: T32
Gladly accepting any remarks on how to improve my coding :thup:
Changelog:
Code:
v1.02 Minor flaws fixed
Added an effect when units are hit
v1.01 Reduced function calls
Now uses global unit groups
Uses a global location for SetUnitZ and GetUnitZ
Fixed a typo in the tooltip
Attack type,damage type and weapon type are now configurable
v1.00 Initial release
I know the testmap sucks, but it'll do.