//*********************************************************************************************************************
//* Frost Orb v.1.2 by xD.Schurke
//* ------------------------------
//*
//* Requirements:
//* --------------
//* * vJass (JassNewGenPack)
//* * GroupRecycler
//*
//*
//*
//* Changes in version 1.1:
//* ----------
//* * Cleaned the script
//* * Removed unnecessary script lines
//* * Now there is a better overview
//* * Removed the interface-system by Hankey, Replaced it with the timer stacking method
//* * Added a Group Recycler (For more information check the GroupRecycler Trigger
//* * Changed + Removed some constants
//* * Reduced the range of the Orb-Missile to 85
//* * Removed DUMMY_DURATION constant
//*
//* Changes in version 1.2:
//* ----------
//* * Fixed a bug with the missile pathing
//*
//*
//*
//* 1. Copy the GroupRecycler to your map
//* 2. Copy the Frost Orb Trigger to your map
//* 3. Copy the Spells and Buffs (Obejct Editor) to your map => You maybe need to change the raw codes in Frost Orb
//* 4. Change nessesery things in the Frost Orb constants
//* 4.1 Check Dummy Raw-Code (If needed copy dummy-unit (Object Editor) and dummy model (Import Manager) dummy.mdx)
//* 4.2 Check Spell Raw-Codes
//*
//*********************************************************************************************************************
library FrostOrb initializer frostInt requires GroupRecycler
globals
private constant integer DUMMY = 'h000' //the dummy raw-code => Change to your map specific one
private constant integer SPELL_RAW = 'A000' //the spell raw-code => Change to your map specific one
private constant integer DUMMY_SPELL = 'A001' //the dummy-spell raw-code => Change to your map specific one
private constant integer DUMMY_SPELL_DEBUFF = 'B000' //the dummy-spell-debuff raw-code => Change to your map specific one
private constant integer TIMED_LIFE = 'BTLF' //the timed life buff raw code => DO NOT CHANGE
private constant string MISSILE_SFX = "Abilities\\Weapons\\ZigguratFrostMissile\\ZigguratFrostMissile.mdl" //the orb modell
private constant real MISSILE_DISTANCE = 85. //the distance between target and orb
private constant real MISSILE_SPEED = 12. //the orb speed increase/decrease for change speed
private constant real MISSILE_DURATION = 15. //the duration of the orb in seconds
private constant real MISSILE_DURATION_INCREASE = 6. //how many seconds are added per level
private constant real MISSILE_MOTION_UPDATE = 0.03 //for duration reason => DO NOT CHANGE
private constant real MISSILE_DAMAGE = 90. //the damage delt to the units hit by the orb
private constant real MISSILE_DAMAGE_INCREASE = 50. //the damage added per lvl
private constant real MISSILE_RADIUS = 80. //the radius where the orb deals damage to units
private constant integer MAX_HITS = 10 //how many units can be hit by the spell
private constant integer MAX_HITS_INCREASE = 8 //units added to spell per lvl who can be hit
//attatchement point
private constant string chest = "chest"
//Group Reason stuff => DO NOT CHANGE
group tmpG = CreateGroup()
player tmpP
boolexpr Cond
private timer Tim = CreateTimer()
private integer array Data
private integer Total = 0
endglobals
//Constant functions for damage/duration/hit formular
private constant function Hits takes integer lvl returns integer
return MAX_HITS+((lvl-1)*MAX_HITS_INCREASE)
endfunction
private constant function Damage takes integer lvl returns real
return MISSILE_DAMAGE+((lvl-1)*MISSILE_DAMAGE_INCREASE)
endfunction
private constant function Duration takes integer lvl returns real
return MISSILE_DURATION+((lvl-1)*MISSILE_DURATION_INCREASE)
endfunction
//group filter function
private function filter takes nothing returns boolean
return IsUnitEnemy(GetFilterUnit(),tmpP) and (GetUnitState(GetFilterUnit(),UNIT_STATE_LIFE)>0) and IsUnitType(GetFilterUnit(),UNIT_TYPE_GROUND) and (GetUnitTypeId(GetFilterUnit())!=DUMMY)
endfunction
//the struct for the orb
private struct FrostStruct
unit caster //the caster who casts the spell
unit target //the target of the Frost Orb
unit missile //the Frost Orb
effect sfx //Frost Orb Effect
real x = 0. //x of target
real y = 0. //y of target
real ang = 0 //angle for orb movement
real dur = 0 //duration counted
integer hit = 0 //how many units were hit by the orb
group g //to prevent multiple damaging in one surrounding
static method move takes nothing returns nothing
local FrostStruct dat
local integer i = 0
local unit u
local unit dummy
local real x = 0.
local real y = 0.
loop
exitwhen i >= Total
set dat = Data[i]
set dat.dur = dat.dur + MISSILE_MOTION_UPDATE
set dat.x = GetUnitX(dat.target)
set dat.y = GetUnitY(dat.target)
set x = dat.x + MISSILE_DISTANCE * Cos(dat.ang * bj_DEGTORAD)
set y = dat.y + MISSILE_DISTANCE * Sin(dat.ang * bj_DEGTORAD)
set tmpP = GetOwningPlayer(dat.caster)
call GroupEnumUnitsInRange(tmpG,x,y,MISSILE_RADIUS,Cond)
loop
set u = FirstOfGroup(tmpG)
exitwhen u == null
if IsUnitInGroup(u,dat.g) or GetUnitAbilityLevel(u,DUMMY_SPELL_DEBUFF) > 0 then
call GroupRemoveUnit(tmpG,u)
else
call UnitDamageTarget(dat.caster,u,Damage(GetUnitAbilityLevel(dat.caster,SPELL_RAW)),false,true,ATTACK_TYPE_NORMAL,DAMAGE_TYPE_MAGIC,WEAPON_TYPE_WHOKNOWS)
set dummy = CreateUnit(GetOwningPlayer(dat.caster),DUMMY,GetUnitX(u),GetUnitY(u),0)
call UnitAddAbility(dummy,DUMMY_SPELL)
call IssueTargetOrder(dummy,"thunderbolt",u)
call UnitApplyTimedLife(dummy,TIMED_LIFE,1.)
set dat.hit = dat.hit + 1
call GroupAddUnit(dat.g,u)
call GroupRemoveUnit(tmpG,u)
endif
endloop
call SetUnitPosition(dat.missile,x,y)
set dat.ang = dat.ang + MISSILE_SPEED
if dat.dur >= Duration(GetUnitAbilityLevel(dat.caster,SPELL_RAW)) or GetUnitState(dat.target,UNIT_STATE_LIFE) <= 0 or dat.hit >= Hits(GetUnitAbilityLevel(dat.caster,SPELL_RAW)) then
set Total = Total - 1
set Data[i] = Data[Total]
set i = i - 1
call FrostStruct.destroy(dat)
endif
set i = i + 1
endloop
set dummy = null
set u = null
endmethod
static method create takes nothing returns FrostStruct
local FrostStruct dat = FrostStruct.allocate()
if Total == 0 then
call TimerStart(Tim,MISSILE_MOTION_UPDATE,true,function FrostStruct.move)
endif
set Data[Total] = dat
set Total = Total + 1
return dat
endmethod
method onDestroy takes nothing returns nothing
call KillUnit(.missile)
call ReleaseGroup(.g)
set .g = null
set .caster = null
set .missile = null
set .target = null
set .sfx = null
endmethod
endstruct
//Condition
private function frostCond takes nothing returns boolean
return GetSpellAbilityId() == SPELL_RAW
endfunction
//Actions creates struct and sets values
private function frostAction takes nothing returns nothing
local FrostStruct F
local real x
local real y
set F = FrostStruct.create()
set F.g = NewGroup()
set F.caster = GetTriggerUnit()
set F.target = GetSpellTargetUnit()
set F.x = GetUnitX(F.target)
set F.y = GetUnitY(F.target)
set x = F.x + MISSILE_DISTANCE * Cos(F.ang * bj_DEGTORAD)
set y = F.y + MISSILE_DISTANCE * Sin(F.ang * bj_DEGTORAD)
set F.missile = CreateUnit(GetOwningPlayer(F.target),DUMMY,F.x,F.y,0)
set F.sfx = AddSpecialEffectTarget(MISSILE_SFX,F.missile,chest)
call SetUnitPathing(F.missile,false)
set F.ang = F.ang + MISSILE_SPEED
endfunction
//Event etc.
private function frostInt takes nothing returns nothing
local trigger int = CreateTrigger()
local integer index = 0
local unit u
loop
call TriggerRegisterPlayerUnitEvent(int, Player(index), EVENT_PLAYER_UNIT_SPELL_EFFECT, null)
set index = index + 1
exitwhen index == bj_MAX_PLAYER_SLOTS
endloop
call TriggerAddCondition(int,Condition(function frostCond))
call TriggerAddAction(int,function frostAction)
set int = null
set Cond=Condition(function filter)
//Preload
set u = CreateUnit(Player(14),DUMMY,999999,999999,0)
call UnitAddAbility(u,DUMMY_SPELL)
call RemoveUnit(u)
set u = null
call Preload(MISSILE_SFX)
call PreloadStart()
endfunction
endlibrary