Moderator
M
Moderator
13 Nov 2011
Bribe: Approved. Another good resource.
Bribe: Approved. Another good resource.
//==============================================================================
// SHADOW FIELD SPELLPACK v1.4
// BY Ayanami
//==============================================================================
//==============================================================================
// REQUIREMENTS
//==============================================================================
//
// - JNGP
// - Alloc
// - RegisterPlayerUnitEvent
// - SpellEffectEvent
// - Timer32
// - WorldBounds
//
//==============================================================================
//==============================================================================
// IMPLEMENTATION
//==============================================================================
//
// 1) Copy the whole "Required Systems" Trigger folder & paste in map
// 2) Save the map, it will take a bit longer than usual
// 3) After saving, close the map and re-open it
// 4) Delete or disable the trigger "Objects"
// 5) Copy all 8 abilities under "Undead" & paste in map
// 6) Copy the single buff under "Undead" & paste in map
// 7) Ensure that the following abilities have their buff set properly:
// Presence of the Dark Lord - Presence of the Dark Lord
// 8) Copy the whole "Shadowfiend" Trigger folder
// 9) Go through all the spell Configurations
//
//==============================================================================
library Shadowraze uses Alloc, RegisterPlayerUnitEvent, SpellEffectEvent, WorldBounds
//===========================================================================
// CONFIGURABLES
//===========================================================================
globals
private constant integer ABILID = 'ABSR' // raw code of ability "Shadowraze"
private constant integer ABILIDZ = 'ASR0' // raw code of ability "Shadowraze (Z)"
private constant integer ABILIDX = 'ASR1' // raw code of ability "Shadowraze (X)"
private constant integer ABILIDC = 'ASR2' // raw code of ability "Shadowraze (C)"
private constant integer DUMMYID = 'sHAD' // raw code of unit "Shadowraze Dummy", acts as the visual effect itself
private constant real ANIMDUR = 2.0 // duration of DUMMYID
private constant integer RED = 0 // red vertex color of DUMMYID
private constant integer GREEN = 0 // green vertex color of DUMMYID
private constant integer BLUE = 0 // blue vertex color of DUMMYID
private constant integer TRANS = 255 // transparency of DUMMYID, where 0 is fully transparent
private constant real SCALE = 1.2 // scale size of DUMMYID
private constant real PERIOD = 0.1 // checking period for dummy expiration
private constant real ENUM_RADIUS = 176. // max collision size of a unit in your map
private constant attacktype ATK = ATTACK_TYPE_NORMAL // attack type of damage
private constant damagetype DMG = DAMAGE_TYPE_MAGIC // damage type of damage
endglobals
// damage dealt
private function GetDamage takes integer level returns real
return 75.0 * level
endfunction
// area of effect
private function GetArea takes integer level returns real
return 250.0
endfunction
// range of "Shadowraze (Z)"
private function GetRangeZ takes integer level returns real
return 200.0
endfunction
// range of "Shadowraze (X)"
private function GetRangeX takes integer level returns real
return 450.0
endfunction
// range of "Shadowraze (C)"
private function GetRangeC takes integer level returns real
return 700.0
endfunction
// target types allowed for dealing damage
private function GetFilter takes unit caster, unit target returns boolean
return /*
*/ not IsUnitType(target, UNIT_TYPE_DEAD) and /* // target is alive
*/ IsUnitEnemy(target, GetOwningPlayer(caster)) and /* // target is an enemy of caster
*/ not IsUnitType(target, UNIT_TYPE_STRUCTURE) // target is not a structure
endfunction
//===========================================================================
// END CONFIGURABLES
//===========================================================================
globals
private constant player NEUTRAL_PASSIVE = Player(PLAYER_NEUTRAL_PASSIVE)
private group G = bj_lastCreatedGroup
endglobals
private struct Main extends array
implement Alloc
private thistype next
private thistype prev
private unit u
private real dur
private static timer linkTimer = CreateTimer()
private method destroy takes nothing returns nothing
set this.next.prev = this.prev
set this.prev.next = this.next
if thistype(0).next == 0 then
call PauseTimer(thistype.linkTimer)
endif
call RemoveUnit(this.u)
call this.deallocate()
endmethod
private static method iterate takes nothing returns nothing
local thistype this = thistype(0)
loop
set this = this.next
exitwhen this == 0
if this.dur <= 0 then
call this.destroy()
else
set this.dur = this.dur - PERIOD
endif
endloop
endmethod
private static method onCast takes nothing returns boolean
local thistype this
local unit caster = GetTriggerUnit()
local unit u
local integer spellid = GetSpellAbilityId()
local integer level
local real r
local real a
local real x
local real y
set level = GetUnitAbilityLevel(caster, ABILID)
if spellid == ABILIDZ then
set r = GetRangeZ(level)
elseif spellid == ABILIDX then
set r = GetRangeX(level)
else
set r = GetRangeC(level)
endif
set a = GetUnitFacing(caster) * bj_DEGTORAD
set x = GetUnitX(caster) + r * Cos(a)
set y = GetUnitY(caster) + r * Sin(a)
if x >= WorldBounds.minX and x <= WorldBounds.maxX and y >= WorldBounds.minY and y <= WorldBounds.maxY then
set this = thistype.allocate()
set this.u = CreateUnit(NEUTRAL_PASSIVE, DUMMYID, x, y, a * bj_RADTODEG)
set this.dur = ANIMDUR
set a = GetArea(level)
set r = GetDamage(level)
call SetUnitVertexColor(this.u, RED, GREEN, BLUE, TRANS)
call SetUnitScale(this.u, SCALE, SCALE, SCALE)
call GroupEnumUnitsInRange(G, x, y, a + ENUM_RADIUS, null)
loop
set u = FirstOfGroup(G)
exitwhen u == null
call GroupRemoveUnit(G, u)
if GetFilter(caster, u) and IsUnitInRangeXY(u, x, y, a) then
call UnitDamageTarget(caster, u, r, true, false, ATK, DMG, null)
endif
endloop
if thistype(0).next == 0 then
call TimerStart(thistype.linkTimer, PERIOD, true, function thistype.iterate)
endif
set thistype(0).next.prev = this
set this.next = thistype(0).next
set thistype(0).next = this
set this.prev = thistype(0)
endif
set caster = null
return false
endmethod
private static method onLearn takes nothing returns boolean
local unit u
local integer level
if ABILID == GetLearnedSkill() then
set u = GetTriggerUnit()
set level = GetUnitAbilityLevel(u, ABILID)
if level == 1 then
call UnitAddAbility(u, ABILIDZ)
call UnitAddAbility(u, ABILIDX)
call UnitAddAbility(u, ABILIDC)
else
call SetUnitAbilityLevel(u, ABILIDZ, level)
call SetUnitAbilityLevel(u, ABILIDX, level)
call SetUnitAbilityLevel(u, ABILIDC, level)
endif
endif
set u = null
return false
endmethod
private static method onInit takes nothing returns nothing
local unit u
call RegisterSpellEffectEvent(ABILIDZ, function thistype.onCast)
call RegisterSpellEffectEvent(ABILIDX, function thistype.onCast)
call RegisterSpellEffectEvent(ABILIDC, function thistype.onCast)
call RegisterPlayerUnitEvent(EVENT_PLAYER_HERO_SKILL, function thistype.onLearn)
//preload
set u = CreateUnit(NEUTRAL_PASSIVE, DUMMYID, 0, 0, 0)
call UnitAddAbility(u, ABILIDZ)
call UnitAddAbility(u, ABILIDX)
call UnitAddAbility(u, ABILIDC)
call RemoveUnit(u)
set u = null
endmethod
endstruct
endlibrary
library Necromastery uses Alloc, RegisterPlayerUnitEvent, T32
globals
private integer array DAMAGEID[4]
endglobals
//===========================================================================
// CONFIGURABLES
//===========================================================================
globals
private constant integer ABILID = 'ABNe' // raw code of ability "Necromastery"
public constant integer DUMABILID = 'ANe0' // raw code of ability "Necromastery (Display)"
private constant integer DUMMYID = 'nECD' // raw code of unit "Necromastery Dummy"
private constant integer DAMAGE = 2 // damage bonus per soul
private constant real COL = 50.0 // collision size of the soul
private constant real SPEED = 500.0 // distance traveled by the soul per second
private constant real TRUESPEED = SPEED * T32_PERIOD // distance traveled by the soul per period
private constant string DEATHART = "Abilities\\Weapons\\AvengerMissile\\AvengerMissile.mdl" // death art used upon soul expiration
private constant string DEATHARTPOINT = "chest" // attachment point of DEATHART
endglobals
private function InitFunc takes nothing returns nothing
local integer i = 0
local unit u = CreateUnit(Player(13), DUMMYID, 0, 0, 0)
set DAMAGEID[0] = 'dmg0' // raw code of ability "Damage (10000's) (Necromastery)"
set DAMAGEID[1] = 'dmg1' // raw code of ability "Damage (1000's) (Necromastery)"
set DAMAGEID[2] = 'dmg2' // raw code of ability "Damage (100's) (Necromastery)"
set DAMAGEID[3] = 'dmg3' // raw code of ability "Damage (10's) (Necromastery)"
set DAMAGEID[4] = 'dmg4' // raw code of ability "Damage (1's) (Necromastery)"
//preload
loop
exitwhen i > 4
call UnitAddAbility(u, DAMAGEID[i])
set i = i + 1
endloop
call UnitAddAbility(u, DUMABILID)
call RemoveUnit(u)
set u = null
endfunction
// maximum number of souls
private function GetMaxSoul takes integer level returns integer
if level == 1 then
return 8
elseif level == 2 then
return 15
elseif level == 3 then
return 23
elseif level == 4 then
return 30
endif
return 0
endfunction
// amount of souls lost on death, where 1.0 = 100%
private function GetSoulLost takes integer level returns real
return 0.50
endfunction
//===========================================================================
// END CONFIGURABLES
//===========================================================================
globals
private constant real TRUE_COLLISION = COL * COL
endglobals
private struct Main extends array
implement Alloc
private unit killer
private unit dummy
private method destroy takes nothing returns nothing
call RemoveUnit(this.dummy)
call this.stopPeriodic()
call this.deallocate()
endmethod
private static method setDamage takes unit u returns nothing
local integer damage = DAMAGE * (GetUnitAbilityLevel(u, DUMABILID) - 1)
local integer factor = 10000
local integer level
local integer i = 0
loop
exitwhen i > 4
set level = damage / factor
call SetUnitAbilityLevel(u, DAMAGEID[i], level + 1)
set damage = damage - (level * factor)
set factor = factor / 10
set i = i + 1
endloop
endmethod
private method periodic takes nothing returns nothing
local integer level
local real x = GetUnitX(this.dummy)
local real y = GetUnitY(this.dummy)
local real dx = GetUnitX(this.killer) - x
local real dy = GetUnitY(this.killer) - y
local real a
local real height
local real dist = dx * dx + dy * dy
if dist <= TRUE_COLLISION then
set level = GetUnitAbilityLevel(this.killer, DUMABILID)
if level < GetMaxSoul(GetUnitAbilityLevel(this.killer, ABILID)) + 1 then
call UnitRemoveAbility(this.killer, DUMABILID)
call UnitAddAbility(this.killer, DUMABILID)
call SetUnitAbilityLevel(this.killer, DUMABILID, level + 1)
call setDamage(this.killer)
endif
call DestroyEffect(AddSpecialEffectTarget(DEATHART, this.killer, DEATHARTPOINT))
call this.destroy()
elseif IsUnitType(this.killer, UNIT_TYPE_DEAD) or GetUnitTypeId(this.killer) == 0 then
call this.destroy()
else
set a = Atan2(dy, dx)
call SetUnitX(this.dummy, x + TRUESPEED * Cos(a))
call SetUnitY(this.dummy, y + TRUESPEED * Sin(a))
set height = GetUnitFlyHeight(this.dummy)
call SetUnitFlyHeight(this.dummy, height + ((GetUnitFlyHeight(this.killer) + 100) - height) / (dist / TRUESPEED), 0)
endif
endmethod
implement T32x
private static method onDeath takes nothing returns boolean
local thistype this
local unit u = GetTriggerUnit()
local unit killer = GetKillingUnit()
local integer ulevel = GetUnitAbilityLevel(u, ABILID)
local integer klevel = GetUnitAbilityLevel(killer, ABILID)
local integer i
local real x
local real y
if ulevel > 0 then
set i = R2I((GetUnitAbilityLevel(u, DUMABILID) - 1) * GetSoulLost(ulevel))
call UnitRemoveAbility(u, DUMABILID)
call UnitAddAbility(u, DUMABILID)
call SetUnitAbilityLevel(u, DUMABILID, i + 1)
call setDamage(u)
elseif klevel > 0 then
set this = this.allocate()
set x = GetUnitX(u)
set y = GetUnitY(u)
set this.killer = killer
set this.dummy = CreateUnit(Player(13), DUMMYID, x, y, Atan2(GetUnitY(this.killer) - y, GetUnitX(this.killer) - x) * bj_RADTODEG)
call this.startPeriodic()
endif
set u = null
set killer = null
return false
endmethod
private static method onLearn takes nothing returns boolean
local unit u = GetTriggerUnit()
local integer i
if GetLearnedSkill() == ABILID then
if GetUnitAbilityLevel(u, DUMABILID) == 0 then
call UnitAddAbility(u, DUMABILID)
set i = 0
loop
exitwhen i > 4
call UnitAddAbility(u, DAMAGEID[i])
set i = i + 1
endloop
endif
endif
set u = null
return false
endmethod
private static method onInit takes nothing returns nothing
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_DEATH, function thistype.onDeath)
call RegisterPlayerUnitEvent(EVENT_PLAYER_HERO_SKILL, function thistype.onLearn)
call InitFunc()
endmethod
endstruct
endlibrary
library RequiemOfSouls uses Alloc, SpellEffectEvent, T32, WorldBounds, Necromastery
//===========================================================================
// CONFIGURABLES
//===========================================================================
globals
private constant integer ABILID = 'ABRS' // raw code of ability "Requiem of Souls"
private constant integer DUMABILID = 'ARS0' // raw code of ability "Requiem of Souls (Reduction)"
private constant integer DUMMYID = 'rOSD' // raw code of unit "Requiem of Souls Dummy"
private constant integer CASTERID = 'cAST' // raw code of unit "Caster Dummy"
private constant integer SOULCOUNT = 2 // number of souls required to create a "line"
private constant real SOULAOE = 150.0 // area of effect of each "line"
private constant real SPEED = 1000.0 // distance travelled by "line" per second
private constant real TRUESPEED = SPEED * T32_PERIOD // distance travelled by "line" per period
private constant real REDUCTIONAOE = 675.0 // area of effect where units will be affected by damage and move speed reduction
private constant real INTERVAL = 200.0 // distance interval where effect is spawned
private constant string EFFECT = "Objects\\Spawnmodels\\Undead\\UndeadDissipate\\UndeadDissipate.mdl" // effect spawned every interval
private constant real ENUM_RADIUS = 176. // max collision size of a unit in your map
private constant attacktype ATK = ATTACK_TYPE_NORMAL // attack type of damage
private constant damagetype DMG = DAMAGE_TYPE_MAGIC // damage type of damage
endglobals
private function GetDamage takes integer level returns real
return 40.0 + (40.0 * level) // damage dealt per line of soul
endfunction
private function GetArea takes integer level returns real
return 1350.0 + (25.0 * level) // area of effect
endfunction
// target types allowed for dealing damage
private function GetFilter takes unit caster, unit target returns boolean
return /*
*/ not IsUnitType(target, UNIT_TYPE_DEAD) and /* // target is alive
*/ IsUnitEnemy(target, GetOwningPlayer(caster)) and /* // target is an enemy of caster
*/ not IsUnitType(target, UNIT_TYPE_STRUCTURE) // target is not a structure
endfunction
//===========================================================================
// END CONFIGURABLES
//===========================================================================
globals
private constant player NEUTRAL_PASSIVE = Player(PLAYER_NEUTRAL_PASSIVE)
private group G = bj_lastCreatedGroup
endglobals
private struct Main extends array
implement Alloc
private unit u
private unit dummy
private group g
private real dmg
private real dist
private real a
private real interval
private static unit castDummy
private method destroy takes nothing returns nothing
call RemoveUnit(this.dummy)
call DestroyGroup(this.g)
call this.stopPeriodic()
call this.deallocate()
endmethod
private method periodic takes nothing returns nothing
local unit u
local real x = GetUnitX(this.dummy)
local real y = GetUnitY(this.dummy)
if this.dist <= 0 then
call DestroyEffect(AddSpecialEffect(EFFECT, x, y))
call this.destroy()
else
if this.interval <= 0 then
call DestroyEffect(AddSpecialEffect(EFFECT, x, y))
set this.interval = INTERVAL
else
set this.interval = this.interval - TRUESPEED
endif
set this.dist = this.dist - TRUESPEED
set x = x + TRUESPEED * Cos(this.a)
set y = y + TRUESPEED * Sin(this.a)
if x >= WorldBounds.minX and x <= WorldBounds.maxX and y >= WorldBounds.minY and y <= WorldBounds.maxY then
call SetUnitX(this.dummy, x)
call SetUnitY(this.dummy, y)
call GroupEnumUnitsInRange(G, x, y, SOULAOE + ENUM_RADIUS, null)
loop
set u = FirstOfGroup(G)
exitwhen u == null
call GroupRemoveUnit(G, u)
if GetFilter(this.u, u) and not IsUnitInGroup(u, this.g) then
call UnitDamageTarget(this.u, u, this.dmg, true, false, ATK, DMG, null)
call GroupAddUnit(this.g, u)
endif
endloop
endif
endif
endmethod
implement T32x
private static method onCast takes nothing returns boolean
local thistype this
local unit caster = GetTriggerUnit()
local unit u
local integer level = GetUnitAbilityLevel(caster, ABILID)
local integer i = (GetUnitAbilityLevel(caster, Necromastery_DUMABILID) - 1) / SOULCOUNT
local real a = 0
local real aRate
local real x
local real y
if i > 0 then
set aRate = (2 * bj_PI) / i
endif
set x = GetUnitX(caster)
set y = GetUnitY(caster)
loop
exitwhen i == 0
set this = thistype.allocate()
set this.u = caster
set this.dummy = CreateUnit(GetTriggerPlayer(), DUMMYID, x, y, a)
set this.g = CreateGroup()
set this.dmg = GetDamage(level)
set this.dist = GetArea(level)
set this.a = a
set this.interval = INTERVAL
call this.startPeriodic()
set a = a + aRate
set i = i - 1
endloop
call SetUnitAbilityLevel(castDummy, DUMABILID, level)
call GroupEnumUnitsInRange(G, x, y, REDUCTIONAOE + ENUM_RADIUS, null)
loop
set u = FirstOfGroup(G)
exitwhen u == null
call GroupRemoveUnit(G, u)
if GetFilter(caster, u) and IsUnitInRangeXY(u, x, y, REDUCTIONAOE) then
call IssueTargetOrder(castDummy, "cripple", u)
endif
endloop
set caster = null
return false
endmethod
private static method onInit takes nothing returns nothing
call RegisterSpellEffectEvent(ABILID, function thistype.onCast)
set castDummy = CreateUnit(NEUTRAL_PASSIVE, CASTERID, 0, 0, 0)
call UnitAddAbility(castDummy, DUMABILID)
endmethod
endstruct
endlibrary