//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// ----------------------------------------- CUSTOM MULTISHOT BY WereElf ------------------------------------------ //
// This is simply a Multishot, which is a lot better than the Barrage based one. //
// The differences between this Multishot and the Barrage based one are: //
// //
// 1) This multishot can be configured to hit only enemies infront of the shooter, while Barrage based can only //
// target ALL the enemies in range (certain amount of them). //
// //
// 2) This multishot works with Orb effects (if you use the "Orbs" add-on library. //
// //
// 3) You can make your own "orb effects" when you use this Multishot, since you get a "On Hit" event. //
// //
// 4) You can set the targets allowed to 1 and 2, while for the Barrage based one - the minimum is 3. //
// //
// 5) You can use this multishot for SPELLS! //
// //
// 6) You can put some weird configurations for this multishot (like - hit allied buildings, and enemy units). //
// //
// I could keep on listing the possibillities, offered by this library, but I wouldn't. I pointed out the most //
// important ones. //
// //
// HOW TO MAKE IT WORK: //
// //
// 0.a) You need a damage detecting system on your map. The multishot is built, using 1 of the most basic DDS(es), //
// so it will work with any DDS. However, if you are using a different one - you need to go to the bottom of this //
// library, and change the variables in the last textmacro to the ones, used by the other DDS. //
// //
// 0.b) You need to have a dummy on your map. //
// //
// 1) Make a custom buff on your map, which will be used ONLY by the Multishot skills. //
// //
// 2) Make as many as you need skills, based on Acid Bomb, make them cost 0 mana, deal 0 damage, and make them //
// APPLY THE BUFF YOU MADE IN STEP (1). //
// //
// 3) Scroll down to the globals block of this library, and set the variables to "your" values. //
// //
// 4) When you want to make a trigger, using Multishot, just call "MultishotTarget" or "MultishotPoint", according //
// to your needs. //
// //
// 5) You could make a library with some pre-set Multishot functions (like MultishoRt in the sample map), so you //
// don't have to put all the arguments when you call Multishot, but simply the ones you need. //
// //
// If you have the AdvancedMultishot library (add-on), you can also use "MultishotTargetAdvanced" and //
// "MultishotPointAdvanced". The advanced functions are able to hit magic immune enemies, even if you have "Magic //
// immune units resist ultimates" set to true. //
// //
// THE ARGUMENTS THE FUNCTIONS TAKE: //
// //
// MultishotTarg (both normal and the advanced) take: //
// 1 (unit) - Shooter - who is shooting //
// 2 (unit) - Target - who is the original target of the shot //
// 3 (real) - Damage - the damage the shot should deal //
// 4 (integer) - Targets - how many targets its allowed to shoot at once //
// 5 (real) - Arc - this determines the width of the area multishot chooses targets from. Set it to 180 if you want //
// ALL the units in range to get shot //
// 6 (real) - Range - the range multishot chooses enemies from. //
// 7 (boolean) - Always hits main targer - does the main target always get shot, or it only has a chance to get //
// shot (if more than the max amount of units are in range) //
// 8 (attacktype) - Attack type - the attack type of the shooter. Its used for correct armor estimation, and thats //
// the type of damage dealt in the end. //
// 9 (integer) - Missile ability - the ability id of the Multishots missile. //
// 10 (real) - Offset angle - (example:) if the main target is at 45 deg from the shooter, if this is set to 45, //
// multishot will act like the target is at 90 degrees. //
// 11 (boolean) - Fixed damage - if you want to deal some fixed value of damage, not based on the damage dealt - //
// set this to true, otherwise - false. //
// 12 (damagetype) - Damage type - if "Fixed damage" is set to false - this will act as "DAMAGE_TYPE_NORMAL", no //
// matter what. Otherwise - this is the damage type multishot deals. //
// 13 (boolexpr) - Conditions - What units shall it target //
// NEXT ONE IS ONLY FOR THE ADVANCED VERSION //
// 14 (real) - Missile speed - simply put-in the missiles speed //
// //
// MultishotPoint (both normal and the advanced) take: //
// 1 (unit) Caster - who is shooting //
// 2 (real) Damage - the damage dealt //
// 3 (integer) Targets - how many targets its allowed to shoot at once //
// 4 (real) Arc - this determines the width of the area multishot chooses targets from. Set it to 180 if you want //
// ALL the units in range to get shot //
// 5 (real) Range - the range multishot chooses enemies from //
// 6 (attacktype) Attack Type - the attack type of the damage dealt //
// 7 (integer) Missile ability - the ability id of the Multishots missile //
// 8 (real) Offset angle - (example:) if the main target is at 45 deg from the shooter, if this is set to 45, //
// multishot will act like the target is at 90 degrees //
// 9 (damagetype) Damage type - the damage type of the damage dealth //
// 10 (real) Target X - the x of the targeted point //
// 11 (real) Target Y - the y of the targeted point //
// 12 (boolexpr) - Conditions - What units shall it target //
// NEXT ONE IS ONLY FOR THE ADVANCED VERSION //
// 13 (real) Missile speed - simply put-in the missiles speed //
// //
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
library MultiMisc
public struct DamProperties
real amount
attacktype aType
damagetype dType
unit source
unit mainTarget
group shotGroup
integer missile
integer unitsShot = 0
boolean advanced
integer alreadyShot = 0
boolean preDummy
unit dummy
timer clearer
static method create takes nothing returns DamProperties
local DamProperties DP = DamProperties.allocate()
set DP.shotGroup = CreateGroup()
set DP.clearer = CreateTimer()
set DP.mainTarget = null
return DP
endmethod
method onDestroy takes nothing returns nothing
call GroupClear(this.shotGroup)
call DestroyGroup(this.shotGroup)
call DestroyTimer(this.clearer)
endmethod
endstruct
public function ClearLeaks takes nothing returns nothing
local timer t = GetExpiredTimer()
local integer tid = GetHandleId(t)
local integer id = LoadInteger(Multishot_Table, tid, 'dmid')
local DamProperties damage = LoadInteger(Multishot_Table, id, 'damp')
call UnitApplyTimedLife(damage.dummy, 'BTLF', 0.01)
call DamProperties.destroy(damage)
call FlushChildHashtable(Multishot_Table, id)
call FlushChildHashtable(Multishot_Table, tid)
set t = null
endfunction
endlibrary
library Multishot initializer Init requires MultiMisc, optional AdvancedMultishot
// DEBUG_MULTISHOT displays how the parabola looks like
// WANT_DAMAGE_BLOCK is a boolean. If set to true - Multishot will automatically block the incoming damage. Set it to false only
// if you want to do the damage block by yourself in the Multishot calling function.
// HP_BONUS_ABILITY is the Item ability, giving 30000 HP to the target unit for the damage block, and for the 'armor test'
// BUFF_APPLIED_ID is the Id of the buff, applied by the Multishot.
// DUMMY_ID is the Id of your dummy unit.
// TEST_DAMAGE_AMOUNT is the amount of damage the target takes to estimate its armor. Higher values give more precise results, but they may instantly kill the target.
// SPELL_ORDER is the string of the order, issued to the dummy to make it cast the multishot arrow. You could change it if
// you are using another spell as base, but acidbomb is the only good spell for this purpose.
// DUMMY_LIFE_TIME is the time the dummy stays alive. Set this to an amount, enough for the multishot to hit all its targets.
// Don't touch the rest.
globals
private constant boolean DEBUG_MULTISHOT = false
private constant boolean WANT_DAMAGE_BLOCK = false
private constant integer HP_BONUS_ABILITY = 'A02P'
private constant integer BUFF_APPLIED_ID = 'B005'
private constant integer DUMMY_ID = 'h00C'
private constant real MAX_COLLISION_SIZE = 196.00
private constant real TEST_DAMAGE_AMOUNT = 15000.00
public constant string SPELL_ORDER = "acidbomb"
public constant boolean WANT_MULTISHOT_HIT_EVENT = true
public constant real MAX_DUMMY_LIFE_TIME = 20.00 // higher values allow slower missiles.
public boolean Damage = false
public hashtable Table = InitHashtable()
private group g = CreateGroup()
private effect array debug_effect // used only when DEBUG_MULTISHOT is true
endglobals
// This sctuct is used when blocking the original damage.
private struct DamBlocker
real health
unit u
static method create takes unit u returns DamBlocker
local DamBlocker DB
set DB = DamBlocker.allocate()
set DB.u = u
set DB.health = GetWidgetLife(u)
return DB
endmethod
static method BlockDamage takes nothing returns nothing
local timer t = GetExpiredTimer()
local thistype this = LoadInteger(Table, GetHandleId(t), 'blcr')
call UnitRemoveAbility(this.u, HP_BONUS_ABILITY)
call SetWidgetLife(this.u, this.health)
call thistype.destroy(this)
call FlushChildHashtable(Table, GetHandleId(t))
call DestroyTimer(t)
set t = null
endmethod
endstruct
// Calculates the unit's base damage, by multiplaying the damage dealt by the target's Armor rating
private function GetBaseDamage takes MultiMisc_DamProperties damage, real dam returns nothing
local timer time
local real max_hp
local DamBlocker DB = DamBlocker.create(damage.mainTarget)
if GetUnitAbilityLevel(damage.mainTarget, 'BNab') > 0 then
call UnitRemoveAbility(damage.mainTarget, 'BNab')
endif
static if WANT_DAMAGE_BLOCK then
if GetUnitAbilityLevel(DB.u, HP_BONUS_ABILITY) == 0 then
set time = CreateTimer()
call SaveInteger(Table, GetHandleId(time), 'blcr', DB)
call TimerStart(time, 0.00, false, function DamBlocker.BlockDamage)
set time = null
endif
endif
call UnitAddAbility(damage.mainTarget, HP_BONUS_ABILITY)
set max_hp = GetUnitState(damage.mainTarget, UNIT_STATE_MAX_LIFE)
call SetWidgetLife(damage.mainTarget, max_hp)
call UnitDamageTarget(damage.dummy, damage.mainTarget, TEST_DAMAGE_AMOUNT, true, false, damage.aType, DAMAGE_TYPE_NORMAL, WEAPON_TYPE_WHOKNOWS)
set damage.amount = (TEST_DAMAGE_AMOUNT/(max_hp - GetWidgetLife(damage.mainTarget)))*dam
call SetWidgetLife(damage.mainTarget, max_hp)
static if not WANT_DAMAGE_BLOCK then
call UnitRemoveAbility(damage.mainTarget, HP_BONUS_ABILITY)
call SetWidgetLife(damage.mainTarget, DB.health)
call DamBlocker.destroy(DB)
endif
endfunction
function DrawParabola takes real range, real arc, real x, real y, real tarx, real tary, real ofst returns nothing
local real a
local real b
local real m = range*Sin(arc/2)
local real parabola = (range-(range*Cos(arc/2 * bj_DEGTORAD)*Cos(arc/2 * bj_DEGTORAD)))/( 4.00 * Cos(arc/2 * bj_DEGTORAD))
local integer count = 0
local real tx = x
local real ty = y
local real init_ang = (RSignBJ(parabola) - 1)*bj_PI/2 + Atan2(tary-y,tarx-x) + ofst*bj_DEGTORAD
local real xFocus = x + parabola*Cos(init_ang)
local real yFocus = y + parabola*Sin(init_ang)
loop
exitwhen count > 20
set x = tx - Cos(init_ang)*parabola + Cos(init_ang + bj_PI/2)*(count - 10)*m/10
set y = ty - Sin(init_ang)*parabola + Sin(init_ang + bj_PI/2)*(count - 10)*m/10
set b = SquareRoot(4*parabola*parabola + (count - 10)*m*(count - 10)*m/100)
set a = (init_ang + bj_PI/2) - Atan2(yFocus - y, xFocus - x)
if a == bj_PI/2 then
set a = parabola
else
set a = b*Cos(a)/Sin(2*a)
endif
set x = x + Cos(init_ang)*a
set y = y + Sin(init_ang)*a
call DestroyEffect(debug_effect[count])
set debug_effect[count] = AddSpecialEffect("Abilities\\Spells\\NightElf\\Barkskin\\BarkSkinTarget.mdl", x, y)
set count = count + 1
endloop
endfunction
function ConfigureDamProp takes unit u, damagetype dType, attacktype aType, unit mainTarget, integer missile, boolean advanced returns MultiMisc_DamProperties
local MultiMisc_DamProperties this
if GetUnitTypeId(u) == DUMMY_ID then
set this = LoadInteger(Table, GetHandleId(u), 'damp') + 0
if this == 0 then
set this = MultiMisc_DamProperties.create()
call SaveInteger(Table, GetHandleId(u), 'damp', this)
endif
set this.dummy = u
set this.source = udg_MS_Source
set this.preDummy = true
else
set this = MultiMisc_DamProperties.create()
set this.dummy = CreateUnit(GetOwningPlayer(u), DUMMY_ID, GetUnitX(u), GetUnitY(u), 0.00)
call SaveInteger(Table, GetHandleId(this.dummy), 'damp', this)
call UnitApplyTimedLife(this.dummy, 'BTLF', MAX_DUMMY_LIFE_TIME + 0.05)
set this.source = u
set this.preDummy = false
endif
call UnitAddAbility(this.dummy, missile)
set this.dType = dType
set this.aType = aType
set this.mainTarget = mainTarget
set this.missile = missile
set this.advanced = advanced
call SaveInteger(Table, GetHandleId(this.clearer), 'dmid', GetHandleId(this.dummy))
call TimerStart(this.clearer, MAX_DUMMY_LIFE_TIME, false, function MultiMisc_ClearLeaks)
return this
endfunction
function ShootAllTargets takes MultiMisc_DamProperties damage, real range, real arc, real tarx, real tary, real ofst, boolexpr condition, real speed returns nothing
local real x = GetUnitX(damage.dummy)
local real y = GetUnitY(damage.dummy)
local player p = GetOwningPlayer(damage.source)
local real xTarget
local real yTarget
local unit FoG
local real parabola = (range-(range*Cos(arc/2 * bj_DEGTORAD)*Cos(arc/2 * bj_DEGTORAD)))/( 4.00 * Cos(arc/2 * bj_DEGTORAD))
local real init_ang = (RSignBJ(parabola) - 1)*bj_PI/2 + Atan2(tary-y,tarx-x) + ofst*bj_DEGTORAD
local real xFocus = x + parabola*Cos(init_ang)
local real yFocus = y + parabola*Sin(init_ang)
local real tempAngle
local boolean b
call GroupEnumUnitsInRange(g, x, y, range + MAX_COLLISION_SIZE, condition)
if damage.mainTarget != null and IsUnitInGroup(damage.mainTarget, damage.shotGroup) then
call GroupRemoveUnit(g, damage.mainTarget)
endif
call GroupRemoveUnit(g, damage.source)
loop
set FoG = FirstOfGroup(g)
exitwhen FoG == null
set xTarget = GetUnitX(FoG)
set yTarget = GetUnitY(FoG)
set tempAngle = Atan2(yTarget-yFocus,xTarget-xFocus) - init_ang
if condition == null then
set b = IsUnitEnemy(FoG, p) and not IsUnitType(FoG, UNIT_TYPE_DEAD) and (xTarget-xFocus)*(xTarget-xFocus)+(yTarget-yFocus)*(yTarget-yFocus) <= (( 2.00*parabola)/( 1 - Cos(tempAngle)))*(( 2.00*parabola)/( 1 - Cos(tempAngle))) and IsUnitInRangeXY(FoG, x, y, range)
else
set b = not IsUnitType(FoG, UNIT_TYPE_DEAD) and (xTarget-xFocus)*(xTarget-xFocus)+(yTarget-yFocus)*(yTarget-yFocus) <= (( 2.00*parabola)/( 1 - Cos(tempAngle)))*(( 2.00*parabola)/( 1 - Cos(tempAngle))) and IsUnitInRangeXY(FoG, x, y, range)
endif
if b then
if speed > 0 then
static if LIBRARY_AdvancedMultishot then
call MS_Shoot(damage, x, y, speed, FoG)
endif
else
call IssueTargetOrder(damage.dummy, SPELL_ORDER, FoG)
endif
call GroupAddUnit(damage.shotGroup, FoG)
set damage.unitsShot = damage.unitsShot + 1
endif
call GroupRemoveUnit(g, FoG)
endloop
endfunction
function ShootRandomTargets takes MultiMisc_DamProperties damage, integer targets, real range, real arc, real tarx, real tary, real ofst, boolexpr condition, real speed returns nothing
local integer left_c = 0
local integer right_c = 0
local unit array units
local real x = GetUnitX(damage.dummy)
local real y = GetUnitY(damage.dummy)
local player p = GetOwningPlayer(damage.source)
local unit FoG
local integer dice
local real xTarget
local real yTarget
local real parabola = (range-(range*Cos(arc/2 * bj_DEGTORAD)*Cos(arc/2 * bj_DEGTORAD)))/( 4.00 * Cos(arc/2 * bj_DEGTORAD))
local real init_ang = (RSignBJ(parabola) - 1)*bj_PI/2 + Atan2(tary-y,tarx-x) + ofst*bj_DEGTORAD
local real xFocus = x + parabola*Cos(init_ang)
local real yFocus = y + parabola*Sin(init_ang)
local real tempAngle
local boolean b
if damage.mainTarget != null and IsUnitInGroup(damage.mainTarget, damage.shotGroup) then
call GroupRemoveUnit(g, damage.mainTarget)
set targets = targets - 1
endif
call GroupEnumUnitsInRange(g, x, y, range + MAX_COLLISION_SIZE, condition)
call GroupRemoveUnit(g, damage.source)
loop
set FoG = FirstOfGroup(g)
exitwhen FoG == null
set xTarget = GetUnitX(FoG)
set yTarget = GetUnitY(FoG)
set tempAngle = Atan2(yTarget-yFocus,xTarget-xFocus) - init_ang
if R2I(tempAngle/(2*bj_PI)) != 0 then
set tempAngle = ModuloReal(tempAngle, 2*bj_PI)
endif
if condition == null then
set b = IsUnitEnemy(FoG, p) and not IsUnitType(FoG, UNIT_TYPE_DEAD) and (xTarget-xFocus)*(xTarget-xFocus)+(yTarget-yFocus)*(yTarget-yFocus) <= (( 2.00*parabola)/( 1 - Cos(tempAngle)))*(( 2.00*parabola)/( 1 - Cos(tempAngle))) and IsUnitInRangeXY(FoG, x, y, range)
else
set b = not IsUnitType(FoG, UNIT_TYPE_DEAD) and (xTarget-xFocus)*(xTarget-xFocus)+(yTarget-yFocus)*(yTarget-yFocus) <= (( 2.00*parabola)/( 1 - Cos(tempAngle)))*(( 2.00*parabola)/( 1 - Cos(tempAngle))) and IsUnitInRangeXY(FoG, x, y, range)
endif
if b then
if tempAngle >= 0 and tempAngle < bj_PI then
set left_c = left_c + 1
set dice = GetRandomInt(1, left_c)
if dice <= targets and ( dice <= (targets + 1)/2 or (units[left_c] == null and left_c <= targets)) then
if left_c <= targets and ( left_c <= (targets + 1)/2 or units[left_c] == null ) then
set units[left_c] = units[dice]
endif
set units[dice] = FoG
endif
else
set right_c = right_c + 1
set dice = GetRandomInt(1, right_c)
if dice <= targets and ( dice <= (targets + 1)/2 or (units[targets + 1 - right_c] == null and right_c <= targets)) then
if right_c <= targets and ( right_c <= (targets + 1)/2 or units[targets + 1 - right_c] == null ) then
set units[targets + 1 - right_c] = units[targets + 1 - dice]
endif
set units[targets + 1 - dice] = FoG
endif
endif
endif
call GroupRemoveUnit(g, FoG)
endloop
set dice = 1
loop
exitwhen dice > targets
if units[dice] != null then
if speed > 0 then
static if LIBRARY_AdvancedMultishot then
call MS_Shoot(damage, x, y, speed, units[dice])
endif
else
call IssueTargetOrder(damage.dummy, SPELL_ORDER, units[dice])
endif
call GroupAddUnit(damage.shotGroup, units[dice])
set damage.unitsShot = damage.unitsShot + 1
set units[dice] = null
elseif targets - right_c > dice then
set dice = targets - right_c - 1
endif
set dice = dice + 1
endloop
endfunction
function MultishotTarget takes unit shooter, unit multiTarget, real initialDamage, integer targets, real arc, real initRange, boolean alwaysHitsMainTarget, attacktype attackType, integer missileArt, real offsetAngle, boolean fixedDamage, damagetype damageType, boolexpr condition returns nothing
local MultiMisc_DamProperties damage
if not Damage then
static if DEBUG_MULTISHOT then
call DrawParabola(initRange, arc, GetUnitX(shooter), GetUnitY(shooter), GetUnitX(multiTarget), GetUnitY(multiTarget), offsetAngle)
endif
set damage = ConfigureDamProp(shooter, damageType, attackType, multiTarget, missileArt, false)
if fixedDamage then
set damage.amount = initialDamage
else
call GetBaseDamage(damage, initialDamage)
endif
if alwaysHitsMainTarget then
call IssueTargetOrder(damage.dummy, SPELL_ORDER, damage.mainTarget)
call GroupAddUnit(damage.shotGroup, damage.mainTarget)
set damage.unitsShot = damage.unitsShot + 1
if targets == 1 then
set udg_MS_Current_Group = damage.shotGroup
set udg_MS_UnitsInGroup = damage.unitsShot
set udg_MS_Dummy = damage.dummy
return
endif
endif
if targets == 0 or targets > 1000 then
call ShootAllTargets(damage, initRange, arc, GetUnitX(multiTarget), GetUnitY(multiTarget), offsetAngle, condition, 0.00)
else
call ShootRandomTargets(damage, targets, initRange, arc, GetUnitX(multiTarget), GetUnitY(multiTarget), offsetAngle, condition, 0.00)
endif
set udg_MS_Current_Group = damage.shotGroup
set udg_MS_UnitsInGroup = damage.unitsShot
set udg_MS_Dummy = damage.dummy
endif
endfunction
function MultishotTargetAdvanced takes unit shooter, unit multiTarget, real initialDamage, integer targets, real arc, real initRange, boolean alwaysHitsMainTarget, attacktype attackType, integer missileArt, real offsetAngle, boolean fixedDamage, damagetype damageType, boolexpr condition, real shotSpeed returns nothing
local MultiMisc_DamProperties damage
static if LIBRARY_AdvancedMultishot then
if not Damage then
static if DEBUG_MULTISHOT then
call DrawParabola(initRange, arc, GetUnitX(shooter), GetUnitY(shooter), GetUnitX(multiTarget), GetUnitY(multiTarget), offsetAngle)
endif
set damage = ConfigureDamProp(shooter, damageType, attackType, multiTarget, missileArt, false)
if fixedDamage then
set damage.amount = initialDamage
else
call GetBaseDamage(damage, initialDamage)
endif
if alwaysHitsMainTarget then
call MS_Shoot(damage, GetUnitX(damage.dummy), GetUnitY(damage.dummy), shotSpeed, multiTarget)
call GroupAddUnit(damage.shotGroup, damage.mainTarget)
set damage.unitsShot = damage.unitsShot + 1
if targets == 1 then
set udg_MS_Current_Group = damage.shotGroup
set udg_MS_UnitsInGroup = damage.unitsShot
set udg_MS_Dummy = damage.dummy
return
endif
endif
if targets == 0 or targets > 1000 then
call ShootAllTargets(damage, initRange, arc, GetUnitX(multiTarget), GetUnitY(multiTarget), offsetAngle, condition, shotSpeed)
else
call ShootRandomTargets(damage, targets, initRange, arc, GetUnitX(multiTarget), GetUnitY(multiTarget), offsetAngle, condition, shotSpeed)
endif
set udg_MS_Current_Group = damage.shotGroup
set udg_MS_UnitsInGroup = damage.unitsShot
set udg_MS_Dummy = damage.dummy
endif
else
call MultishotTarget(shooter, multiTarget, initialDamage, targets, arc, initRange, alwaysHitsMainTarget, attackType, missileArt, offsetAngle, fixedDamage, damageType, condition)
endif
endfunction
function MultishotPoint takes unit shooter, real initialDamage, integer targets, real arc, real initRange, attacktype attackType, integer missileArt, real offsetAngle, damagetype damageType, real xSpell, real ySpell, boolexpr condition returns nothing
local MultiMisc_DamProperties damage
static if DEBUG_MULTISHOT then
call DrawParabola(initRange, arc, GetUnitX(shooter), GetUnitY(shooter), xSpell, ySpell, offsetAngle)
endif
set damage = ConfigureDamProp(shooter, damageType, attackType, null, missileArt, false)
set damage.amount = initialDamage
if targets == 0 or targets > 1000 then
call ShootAllTargets(damage, initRange, arc, xSpell, ySpell, offsetAngle, condition, 0.00)
else
call ShootRandomTargets(damage, targets, initRange, arc, xSpell, ySpell, offsetAngle, condition, 0.00)
endif
set udg_MS_Current_Group = damage.shotGroup
set udg_MS_UnitsInGroup = damage.unitsShot
set udg_MS_Dummy = damage.dummy
endfunction
function MultishotPointAdvanced takes unit shooter, real initialDamage, integer targets, real arc, real initRange, attacktype attackType, integer missileArt, real offsetAngle, damagetype damageType, real xSpell, real ySpell, boolexpr condition, real shotSpeed returns nothing
local MultiMisc_DamProperties damage
static if LIBRARY_AdvancedMultishot then
static if DEBUG_MULTISHOT then
call DrawParabola(initRange, arc, GetUnitX(shooter), GetUnitY(shooter), xSpell, ySpell, offsetAngle)
endif
set damage = ConfigureDamProp(shooter, damageType, attackType, null, missileArt, false)
set damage.amount = initialDamage
if targets == 0 or targets > 1000 then
call ShootAllTargets(damage, initRange, arc, xSpell, ySpell, offsetAngle, condition, shotSpeed)
else
call ShootRandomTargets(damage, targets, initRange, arc, xSpell, ySpell, offsetAngle, condition, shotSpeed)
endif
set udg_MS_Current_Group = damage.shotGroup
set udg_MS_UnitsInGroup = damage.unitsShot
set udg_MS_Dummy = damage.dummy
else
call MultishotPoint(shooter, initialDamage, targets, arc, initRange, attackType, missileArt, offsetAngle, damageType, xSpell, ySpell, condition)
endif
endfunction
function MultishotLight takes unit shooter, unit multiTarget, real initialDamage, integer targets, real arc, real initRange, boolean alwaysHitsMainTarget, attacktype attackType, integer missileArt, real offsetAngle, boolean fixedDamage, damagetype damageType returns nothing
local MultiMisc_DamProperties damage
if not Damage then
static if DEBUG_MULTISHOT then
call DrawParabola(initRange, arc, GetUnitX(shooter), GetUnitY(shooter), GetUnitX(multiTarget), GetUnitY(multiTarget), offsetAngle)
endif
set damage = ConfigureDamProp(shooter, damageType, attackType, multiTarget, missileArt, false)
if fixedDamage then
set damage.amount = initialDamage
else
call GetBaseDamage(damage, initialDamage)
endif
if alwaysHitsMainTarget then
call IssueTargetOrder(damage.dummy, SPELL_ORDER, damage.mainTarget)
call GroupAddUnit(damage.shotGroup, damage.mainTarget)
set damage.unitsShot = damage.unitsShot + 1
if targets == 1 then
set udg_MS_Current_Group = damage.shotGroup
set udg_MS_UnitsInGroup = damage.unitsShot
set udg_MS_Dummy = damage.dummy
return
endif
endif
if targets == 0 or targets > 1000 then
call ShootAllTargets(damage, initRange, arc, GetUnitX(multiTarget), GetUnitY(multiTarget), offsetAngle, null, 0.00)
else
call ShootRandomTargets(damage, targets, initRange, arc, GetUnitX(multiTarget), GetUnitY(multiTarget), offsetAngle, null, 0.00)
endif
set udg_MS_Current_Group = damage.shotGroup
set udg_MS_UnitsInGroup = damage.unitsShot
set udg_MS_Dummy = damage.dummy
endif
endfunction
function MultishotLightAdvanced takes unit shooter, unit multiTarget, real initialDamage, integer targets, real arc, real initRange, boolean alwaysHitsMainTarget, attacktype attackType, integer missileArt, real offsetAngle, boolean fixedDamage, damagetype damageType, real shotSpeed returns nothing
static if LIBRARY_AdvancedMultishot then
local MultiMisc_DamProperties damage
if not Damage then
static if DEBUG_MULTISHOT then
call DrawParabola(initRange, arc, GetUnitX(shooter), GetUnitY(shooter), GetUnitX(multiTarget), GetUnitY(multiTarget), offsetAngle)
endif
set damage = ConfigureDamProp(shooter, damageType, attackType, multiTarget, missileArt, false)
if fixedDamage then
set damage.amount = initialDamage
else
call GetBaseDamage(damage, initialDamage)
endif
if alwaysHitsMainTarget then
call MS_Shoot(damage, GetUnitX(damage.dummy), GetUnitY(damage.dummy), shotSpeed, multiTarget)
call GroupAddUnit(damage.shotGroup, damage.mainTarget)
set damage.unitsShot = damage.unitsShot + 1
if targets == 1 then
set udg_MS_Current_Group = damage.shotGroup
set udg_MS_UnitsInGroup = damage.unitsShot
set udg_MS_Dummy = damage.dummy
return
endif
endif
if targets == 0 or targets > 1000 then
call ShootAllTargets(damage, initRange, arc, GetUnitX(multiTarget), GetUnitY(multiTarget), offsetAngle, null, shotSpeed)
else
call ShootRandomTargets(damage, targets, initRange, arc, GetUnitX(multiTarget), GetUnitY(multiTarget), offsetAngle, null, shotSpeed)
endif
set udg_MS_Current_Group = damage.shotGroup
set udg_MS_UnitsInGroup = damage.unitsShot
set udg_MS_Dummy = damage.dummy
endif
else
call MultishotLight(shooter, multiTarget, initialDamage, targets, arc, initRange, alwaysHitsMainTarget, attackType, missileArt, offsetAngle, fixedDamage, damageType)
endif
endfunction
//! textmacro MulthishotOnHit takes SOURCE, VICTIM, AMOUNT, EVENT
// Checks if a unit, that has taken damage, has the Buff, applied by the Multishot. If it has it - applies the MS damage.
// When a unit is hit by the multishot's missile - the buff is removed, and the damage is applied
// It also sets a variable to 0.00 and then to 1.00 for the Extra triggers to run.
private function MultishotDelay takes nothing returns boolean
local MultiMisc_DamProperties damage
if GetUnitAbilityLevel($VICTIM$, BUFF_APPLIED_ID ) > 0 then
call UnitRemoveAbility( $VICTIM$, BUFF_APPLIED_ID )
static if AdvancedMultishot_ALWAYS_USE_ADVANCED then
if damage.advanced then
return false
endif
endif
set damage = LoadInteger(Table, GetHandleId($SOURCE$), 'damp')
set udg_MS_Damage = damage.amount
if WANT_MULTISHOT_HIT_EVENT then
set udg_MS_Dummy = $SOURCE$
set udg_MS_Hit_Unit = $VICTIM$
set udg_MS_Source = damage.source
set udg_MS_Current_Group = damage.shotGroup
set udg_MS_Main_Target = damage.mainTarget
set udg_MS_Missile = damage.missile
set udg_MS_UnitsInGroup = damage.unitsShot
set udg_MS_Hit_Event = 1.00
set udg_MS_Hit_Event = 0.00
endif
set Damage = true
call UnitDamageTarget( udg_MS_Source, $VICTIM$, udg_MS_Damage, true, true, damage.aType, damage.dType, null )
set Damage = false
set damage.alreadyShot = damage.alreadyShot + 1
if damage.alreadyShot == damage.unitsShot then
call TimerStart(damage.clearer, 0.00, false, function MultiMisc_ClearLeaks)
endif
endif
return false
endfunction
// Initiation Trigger :P
function Init takes nothing returns nothing
set gg_trg_Multishot_v2_2_c = CreateTrigger( )
call TriggerRegisterVariableEvent( gg_trg_Multishot_v2_2_c, "$EVENT$", EQUAL, 0 ) // change the 0 to something else if needed.
call TriggerAddCondition( gg_trg_Multishot_v2_2_c, Condition( function MultishotDelay ) )
endfunction
//! endtextmacro
//! runtextmacro MulthishotOnHit("udg_DamageEventSource","udg_DamageEventTarget","udg_DamageEventAmount","udg_DamageEvent")
endlibrary
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/* ----------------------- ORBS = ADD-ON LIBRARY FOR WereElf's CUSOM MULTISHOT (By WereElf) ------------------------
This library allows MS to work with Orb effects for units with the Multishot ability. When it's used - ALL the units,
shot get affected by the orb effect.
The way it works is simple: When a unit is hit by Multishot - this library checks if the hit was done by a "special"
missile type. If it is - it summons a SPECIAL DUMMY, with enabled attack, gives it the right orb ability, and makes it
attack the target. A trigger is created. When the unit takes damage from the special dummy - the dummy is ordered to stop,
the trigger is destroyed, and the dummy is given a timed life.
NOTE: don't use the missile abilities, used for the orbs for normal Multishot, UNLESS you want the units' normal attacks
to act like the orbs.
REQUIREMENTS:
1) WereElf's Custom Multishot library (ofcourse)
2) A SPECIAL dummy, with attack enabled!!
3) Object editor:
- Each orb (of the ones listed below), which you want to use on your map must have 2 versions - a normal one (which is
already there), and one custom, for the Multishot
- Each orb type needs TWO custom orb abilities - 1 for the dummy, and one for the item.
* For the dummy - it should have its damage bonus set to 0.
* For the item - it needs to have its properties WITHOUT the effect of the orb. Since we don't want the orb effect
to apply before the shot has reached the unit.
- Each orb type requires a missile ability, with different Id, and different missile art (the orb's missile art)
4) You need to make a trigger: when a unit, which uses the multishot picks up an orb - replace it with the custom orb.
And when such orb is dropped - replace it with normal one.
5) Give the orb abilities, with no effect (just damage bonus) to the items.
6) The WANT_MULTISHOT_HIT_EVENT in the Multishot library must be set to true.
7) When all of the above is done - set the variables in the globals block below.
HOW TO USE:
- Before calling the Multishot function for a hero (or a unit with inventory) - call "GetActualMissile" function, and
give as arguments ( the shooter, the Id of the unit's default missile )
*/
library OrbsAddOn initializer Init
globals
// The ID of the SPECIAL dummy (you need to make a dummy with enabled attack)
constant integer ORB_DUMMY = 'h000'
// How much life do you want mask of death to steal on units with multishot
constant real LIFE_STEAL = 0.20 // from each unit hit
// The IDs of the Orb ITEMS.
constant integer ORB_OF_FROST = 'I001'
constant integer ORB_OF_CORRUPTION = 'I003'
constant integer ORB_OF_DARKNESS = 'I000'
constant integer ORB_OF_LIGHTNING = 'I005'
constant integer ORB_OF_FIRE = 'I002'
constant integer ORB_OF_SLOW = 'I006'
constant integer ORB_OF_VENOM = 'I007'
constant integer MASK_OF_DEATH = 'I004'
// The IDs of the Orb MISSILES.
constant integer FROST_MISSILE = 'A008'
constant integer CORRUPTION_MISSILE = 'A00E'
constant integer DARKNESS_MISSILE = 'A00H'
constant integer LIGHTNING_MISSILE = 'A00L'
constant integer FIRE_MISSILE = 'A00N'
constant integer SLOW_MISSILE = 'A00Q'
constant integer VENOM_MISSILE = 'A00O'
constant integer LIFE_STEAL_MISSILE = 'A00W'
// The IDs of the Dummy Orbs (with the effect, without the damage bonus)
constant integer DUMMY_FROST = 'A00T'
constant integer DUMMY_CORRUPTION = 'A00F'
constant integer DUMMY_DARKNESS = 'A00J'
constant integer DUMMY_LIGHTNING = 'A009'
constant integer DUMMY_SLOW = 'A00V'
constant integer DUMMY_VENOM = 'A00U'
// Used for triggering the Orb of Fire
private group FireGroup = CreateGroup()
endglobals
// When this function is called - it checks all of the inventory slots if they contain orbs.
// If an orb is found - the missile Id of the orb is returned (and the loop stops)
// If no orb is found - it returns the unit's default missile.
function GetActualMissile takes unit u, integer default_missile returns integer
local integer i = 0
local integer j
loop
exitwhen i > bj_MAX_INVENTORY
set j = GetItemTypeId(UnitItemInSlot(u, i))
if j == ORB_OF_FROST then
return FROST_MISSILE
elseif j == ORB_OF_CORRUPTION then
return CORRUPTION_MISSILE
elseif j == ORB_OF_DARKNESS then
return DARKNESS_MISSILE
elseif j == ORB_OF_LIGHTNING then
return LIGHTNING_MISSILE
elseif j == ORB_OF_FIRE then
return FIRE_MISSILE
elseif j == ORB_OF_VENOM then
return VENOM_MISSILE
elseif j == ORB_OF_SLOW then
return SLOW_MISSILE
elseif j == MASK_OF_DEATH then
return LIFE_STEAL_MISSILE
endif
set i = i + 1
endloop
return default_missile
endfunction
// ORB OF FIRE EFFECT
// Simply triggers the splash.
private function OrbOfFire takes nothing returns nothing
local real x = GetUnitX(udg_MS_Hit_Unit)
local real y = GetUnitY(udg_MS_Hit_Unit)
local unit u
local player p = GetOwningPlayer(udg_MS_Source)
call GroupEnumUnitsInRange(FireGroup, x, y, 175, null)
loop
set u = FirstOfGroup(FireGroup)
exitwhen u == null
if u != udg_MS_Hit_Unit and IsUnitEnemy( u , p ) then
call UnitDamageTarget(udg_MS_Dummy, u, udg_MS_Damage/5, true, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_NORMAL, WEAPON_TYPE_WHOKNOWS)
endif
call GroupRemoveUnit(FireGroup, u)
endloop
set p = null
endfunction
// LIFE STEAL EFFECT
// Heals the shooter for % of the damage dealt. Special effect appears only when the main target is hit,
private function LifeSteal takes nothing returns nothing
local real hp = GetWidgetLife(udg_MS_Source)
call SetWidgetLife(udg_MS_Source, hp + LIFE_STEAL*udg_MS_Damage)
if udg_MS_Hit_Unit == udg_MS_Main_Target then
call DestroyEffect(AddSpecialEffectTarget("Abilities\\Spells\\Undead\\VampiricAura\\VampiricAuraTarget.mdl", udg_MS_Source, "origin"))
endif
endfunction
// Orb function caller
// When the special dummy hits the target unit - the trigger is destroyed, and the dummy is given 0.01 sec timed life.
private function DummyHit takes nothing returns boolean
if GetUnitTypeId(udg_DamageEventSource) == ORB_DUMMY then
call IssueImmediateOrder(udg_DamageEventSource, "stop")
call UnitApplyTimedLife(udg_DamageEventSource, 'BTLF', 0.01)
endif
return false
endfunction
// When a unit is hit by the Multishot - it checks if the missile is any of the orb missiles.
// If it is - it summons the special dummy, gives it the orb ability, and makes it attack the unit.
// It also creates a trigger to register when the dummy hits the unit.
// Unless it's orb of fire. In that case - it calls the function above.
//! textmacro OrbDummy takes TYPE, EXTRA
set d = CreateUnit(GetOwningPlayer(udg_MS_Source), ORB_DUMMY, GetUnitX(udg_MS_Hit_Unit) - 50, GetUnitY(udg_MS_Hit_Unit), 0.00)
call UnitApplyTimedLife(d, 'BTLF', 1)
call UnitAddAbility( d, DUMMY_$TYPE$ )
$EXTRA$
call IssueTargetOrder( d, "attack", udg_MS_Hit_Unit )
set d = null
//! endtextmacro
private function Trig_On_Hit_Actions takes nothing returns boolean
local unit d
if udg_MS_Missile == FIRE_MISSILE then
call OrbOfFire()
return false
elseif udg_MS_Missile == LIFE_STEAL_MISSILE then
call LifeSteal()
return false
endif
if udg_MS_Missile == CORRUPTION_MISSILE then
//! runtextmacro OrbDummy("CORRUPTION","")
elseif udg_MS_Missile == DARKNESS_MISSILE then
//! runtextmacro OrbDummy("DARKNESS","")
elseif udg_MS_Missile == LIGHTNING_MISSILE then
//! runtextmacro OrbDummy("LIGHTNING","")
elseif udg_MS_Missile == FROST_MISSILE then
//! runtextmacro OrbDummy("FROST","")
elseif udg_MS_Missile == SLOW_MISSILE then
//! runtextmacro OrbDummy("SLOW","")
elseif udg_MS_Missile == VENOM_MISSILE then
//! runtextmacro OrbDummy("VENOM","call UnitAddAbility( d, 'Apo2' )")
endif
return false
endfunction
//===========================================================================
private function Init takes nothing returns nothing
local trigger t = CreateTrigger()
set gg_trg_Custom_Orb_Effects = CreateTrigger()
call TriggerRegisterVariableEvent( gg_trg_Custom_Orb_Effects, "udg_MS_Hit_Event", EQUAL, 0 )
call TriggerAddCondition( gg_trg_Custom_Orb_Effects, Condition(function Trig_On_Hit_Actions) )
call TriggerRegisterVariableEvent( t, "udg_DamageEvent", EQUAL, 0 )
call TriggerAddCondition( t, Condition(function DummyHit))
set t = null
endfunction
endlibrary
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// --------------------------------- ADVANCED - PART OF WereElf's CUSTOM MULTISHOT -------------------------------- //
// This library is used to make Multishot able to target, and damage Magic Immune enemies, when they can resist //
// ultimates (a gameplay constant is used for that). //
// When you have this library + the Multishot library, you can use "MultishotTargetAdvaned" and //
// "MultishotPointAdvanced" functions. //
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
library AdvancedMultishot requires MultiMisc
globals
// ALWAYS_USE_ADVANCED allows you to use ONLY the advanced version, even if the enemies are NOT immune to magic.
// It's still only used only when calling the Advanced function.
public constant boolean ALWAYS_USE_ADVANCED = false
private timer Looper = CreateTimer()
private boolean On = false
private constant real REFRESH_RATE = 0.03125
endglobals
// This struct is also used against Magic Immune enemies - it removes their immunity, so the Multishot missile can be cast
// and then it returns their immunities.
private struct ImmunityList
boolean main = false
boolean i1 = false
boolean i2 = false
boolean i3 = false
boolean i4 = false
unit u
// 'Amim', 'ACm2', 'ACm3' and 'ACmi' are magic immunities. They are usually constant, unless you use only custom magic immunities.
static method create takes unit u returns ImmunityList
local ImmunityList IL = ImmunityList.allocate()
set IL.u = u
if GetUnitAbilityLevel(u, 'Amim') > 0 then
call UnitRemoveAbility(u, 'Amim')
set IL.i1 = true
set IL.main = true
endif
if GetUnitAbilityLevel(u, 'ACm2') > 0 then
call UnitRemoveAbility(u, 'ACm2')
set IL.i2 = true
set IL.main = true
endif
if GetUnitAbilityLevel(u, 'ACm3') > 0 then
call UnitRemoveAbility(u, 'ACm3')
set IL.i3 = true
set IL.main = true
endif
if GetUnitAbilityLevel(u, 'ACmi') > 0 then
call UnitRemoveAbility(u, 'ACmi')
set IL.i4 = true
set IL.main = true
endif
return IL
endmethod
method onDestroy takes nothing returns nothing
if .i1 then
call UnitAddAbility(.u, 'Amim')
endif
if .i2 then
call UnitAddAbility(.u, 'ACm2')
endif
if .i3 then
call UnitAddAbility(.u, 'ACm3')
endif
if .i4 then
call UnitAddAbility(.u, 'ACmi')
endif
endmethod
endstruct
private struct TimeManager
real x
real y
real speed
unit targ
MultiMisc_DamProperties damage
readonly thistype next
readonly thistype prev
static method operator first takes nothing returns thistype
return thistype(0).next
endmethod
static method operator last takes nothing returns thistype
return thistype(0).prev
endmethod
static method create takes real x, real y, unit u, real speed, MultiMisc_DamProperties DP returns thistype
local thistype this = thistype.allocate()
set thistype(0).next.prev = this
set this.next = thistype(0).next
set this.prev = thistype(0)
set thistype(0).next = this
set this.x = x
set this.y = y
set this.speed = speed*REFRESH_RATE
set this.targ = u
set this.damage = DP
return this
endmethod
method onDestroy takes nothing returns nothing
if this.first == this.last then
set On = false
endif
set this.next.prev = this.prev
set this.prev.next = this.next
endmethod
static method refresh takes nothing returns nothing
local thistype this = thistype.first
local real x
local real y
local real h
local real w
local real dist
local real a
loop
exitwhen this == 0
if not IsUnitType(this.targ, UNIT_TYPE_DEAD) then
set x = GetUnitX(this.targ)
set y = GetUnitY(this.targ)
set w = x - this.x
set h = y - this.y
set dist = w*w + h*h
if dist <= this.speed*this.speed then
set udg_MS_Damage = this.damage.amount
if Multishot_WANT_MULTISHOT_HIT_EVENT then
set udg_MS_Dummy = this.damage.dummy
set udg_MS_Hit_Unit = this.targ
set udg_MS_Source = this.damage.source
set udg_MS_Current_Group = this.damage.shotGroup
set udg_MS_Main_Target = this.damage.mainTarget
set udg_MS_Missile = this.damage.missile
set udg_MS_UnitsInGroup = this.damage.unitsShot
set udg_MS_Hit_Event = 1.00
set udg_MS_Hit_Event = 0.00
endif
set Multishot_Damage = true
call UnitDamageTarget( this.damage.source, this.targ, udg_MS_Damage, true, false, this.damage.aType, this.damage.dType, null )
set Multishot_Damage = false
set this.damage.alreadyShot = this.damage.alreadyShot + 1
if this.damage.alreadyShot == this.damage.unitsShot then
call TimerStart(this.damage.clearer, 0.00, false, function MultiMisc_ClearLeaks)
endif
call thistype.destroy(this)
else
set a = Atan2(h, w)
set this.x = this.x + this.speed*Cos(a)
set this.y = this.y + this.speed*Sin(a)
endif
else
call thistype.destroy(this)
endif
set this = this.next
endloop
if On then
call TimerStart(Looper, REFRESH_RATE, false, function TimeManager.refresh)
endif
endmethod
endstruct
// This function removes the unit's magic immunities (so it can shoot them), shoots them, and if they have had magic immunity
// it calculates the time the shot needs to reach the target (roughly), and calls the function above to start a timer,
// Which will artificially damage the unit, when the timer expires.
// Then it returns the units' immunities.
function MS_Shoot takes MultiMisc_DamProperties DP, real x, real y, real shotSpeed, unit target returns nothing
local real delay
local ImmunityList IL = ImmunityList.create(target)
local TimeManager TM
call IssueTargetOrder(DP.dummy, Multishot_SPELL_ORDER, target)
if IL.main or ALWAYS_USE_ADVANCED then
set TM = TimeManager.create(x, y, target, shotSpeed, DP)
if not On then
call TimerStart(Looper, REFRESH_RATE, false, function TimeManager.refresh)
set On = true
endif
endif
call ImmunityList.destroy(IL)
endfunction
endlibrary
//! novjass
MultishotTarg (both normal and the advanced) take:
1 (unit) - Shooter - who is shooting
2 (unit) - Target - who is the original target of the shot
3 (real) - Damage - the damage the shot should deal
4 (integer) - Targets - how many targets its allowed to shoot at once
5 (real) - Arc - this determines the width of the area multishot chooses targets from. Set it to 180 if you want ALL the units in range to get shot
6 (real) - Range - the range multishot chooses enemies from.
7 (boolean) - Always hits main targer - does the main target always get shot, or it only has a chance to get shot (if more than the max amount of units are in range)
8 (attacktype) - Attack type - the attack type of the shooter. Its used for correct armor estimation, and thats the type of damage dealt in the end.
9 (integer) - Missile ability - the ability id of the Multishots missile.
10 (real) - Offset angle - (example:) if the main target is at 45 deg from the shooter, if this is set to 45, multishot will act like the target is at 90 degrees.
11 (boolean) - Fixed damage - if you want to deal some fixed value of damage, not based on the damage dealt - set this to true, otherwise - false.
12 (damagetype) - Damage type - if "Fixed damage" is set to false - this will act as "DAMAGE_TYPE_NORMAL", no matter what. Otherwise - this is the damage type multishot deals.
13 (boolexpr) - Conditions - What units shall it target
'NEXT ONE IS ONLY FOR THE ADVANCED VERSION'
14 (real) - Missile speed - simply put-in the missiles speed
MultishotPoint (both normal and the advanced) take:
1 (unit) Caster - who is shooting
2 (real) Damage - the damage dealt
3 (integer) Targets - how many targets its allowed to shoot at once
4 (real) Arc - this determines the width of the area multishot chooses targets from. Set it to 180 if you want ALL the units in range to get shot
5 (real) Range - the range multishot chooses enemies from
6 (attacktype) Attack Type - the attack type of the damage dealt
7 (integer) Missile ability - the ability id of the Multishots missile
8 (real) Offset angle - (example:) if the main target is at 45 deg from the shooter, if this is set to 45, multishot will act like the target is at 90 degrees
9 (damagetype) Damage type - the damage type of the damage dealth
10 (real) Target X - the x of the targeted point
11 (real) Target Y - the y of the targeted point
12 (boolexpr) - Conditions - What units shall it target
'NEXT ONE IS ONLY FOR THE ADVANCED VERSION'
13 (real) Missile speed - simply put-in the missiles speed
MultishotBasic takes the same arguments as MultishotTarget, without the boolexpr. Its set to target only enemies.
//! endnovjass
library MultishoRt requires Multishot, optional OrbsAddOn
globals
private player ConditionPlayer
endglobals
function FilterEnemies takes nothing returns boolean
return IsUnitEnemy(GetFilterUnit(), ConditionPlayer)
endfunction
function FilterAllies takes nothing returns boolean
return IsUnitAlly(GetFilterUnit(), ConditionPlayer) and GetFilterUnit() != GetTriggerUnit()
endfunction
function MultishotNormal takes integer targets, real arc, real range, attacktype attackType, integer missile returns nothing
call MultishotLightAdvanced(udg_DamageEventSource, udg_DamageEventTarget, udg_DamageEventAmount, targets, arc, range, true, attackType, missile, 0.00, false, DAMAGE_TYPE_NORMAL, 900.00)
endfunction
function MultishotSpell takes unit caster, unit target, integer targets, real arc, real range, real damage, integer missile returns nothing
set ConditionPlayer = GetOwningPlayer(caster)
call MultishotTarget(caster, target, damage, targets, arc, range, true, ATTACK_TYPE_NORMAL, missile, 0.00, true, DAMAGE_TYPE_MAGIC, Condition(function FilterEnemies))
endfunction
function MultishotPointShort takes unit caster, real x, real y, real damage, integer missile returns nothing
set ConditionPlayer = GetOwningPlayer(caster)
call MultishotPoint(caster, damage, 0, 25, 1000, ATTACK_TYPE_NORMAL, missile, 0.00, DAMAGE_TYPE_MAGIC, x, y, Condition(function FilterEnemies))
endfunction
function MultishotHeal takes unit caster, location loc, real amount, integer missile returns nothing
set ConditionPlayer = GetOwningPlayer(caster)
call MultishotPointAdvanced(caster, amount, 0, 90, 500, ATTACK_TYPE_NORMAL, missile, 0.00, DAMAGE_TYPE_NORMAL, GetLocationX(loc), GetLocationY(loc), Condition(function FilterAllies), 500.00)
endfunction
function MultishotOrb takes integer targets, real arc, real range, integer missile returns nothing
local real speed
local integer temp = missile
static if LIBRARY_OrbsAddOn then
set missile = GetActualMissile(udg_DamageEventSource, missile)
if missile == temp then
set speed = 900
else
set speed = 1050
endif
else
set speed = 900
endif
set ConditionPlayer = GetOwningPlayer(udg_DamageEventSource)
call MultishotLightAdvanced(udg_DamageEventSource, udg_DamageEventTarget, udg_DamageEventAmount, targets, arc, range, true, ATTACK_TYPE_HERO, missile, 0.00, false, DAMAGE_TYPE_NORMAL, speed)
endfunction
endlibrary