//*
//* Thievery
//* - by jim7777
//*
//* This ability is based on the ability of Zidane Tribal in Final Fantasy IX
//* This spell is fully MUI
//*
//* Installation:
//* -Copy this trigger, the GroupUtils libraries (if you don't have it on your map)
//* -Copy the 2 dummy units and the ability into your map
//* -Edit the configurables to fit your needs
//* -DO NOT FORGET to edit the calculate function to suit your needs!!!
//* -Test your map
//* -Lastly, enjoy it!
//*
//*****************************************************************************
library Thievery initializer Init requires GroupUtils
//CONFIGURABLES
globals
private constant integer ABILITY_ID = 'A000' // RawCode of the ability (Thievery)
private constant integer DUMMY_ID = 'h000' // RawCode of the dummy unit (Thievery Dummy)
private constant integer ATTACKER_ID = 'n000' //RawCode of the attacker unit (Dummy Thievery Attacker)
private constant real INTERVAL = 0.3 //interval seconds between each minor damage.
private constant real MINOR_DMG = 30. //damage dealt every after interval
private constant real RANGE = 400. //maximum range of units to be affected
private constant real FINAL_DMG = 100. // set the base of the final damage here to be multiplied to the ability level
private constant string SFX = "Abilities\\Spells\\Other\\Incinerate\\FireLordDeathExplode.mdl" //SFX for final blast
private constant string SFX2 = "Abilities\\Spells\\Undead\\ReplenishMana\\ReplenishManaCaster.mdl" //SFX for final blast
private constant string SFX3 = "Abilities\\Spells\\Orc\\WarStomp\\WarStompCaster.mdl" //SFX for final blast
private constant string PERSFX = "Abilities\\Spells\\Human\\MarkOfChaos\\MarkOfChaosTarget.mdl"
private constant attacktype ATTACK_TYPE = ATTACK_TYPE_HERO //Attack type when dealing damage
private constant damagetype DAMAGE_TYPE = DAMAGE_TYPE_NORMAL //Damage type when dealing damage
private constant boolean ENABLE_RECYCLING = false
//set this to false if you want more special effects, set this to true if you want to work the spell faster but no special effects
// ENABLE_RECYLING is very important as it will almost change the spell if you want it more effects but use more memory (because of periodically creating units) or vice-versa
endglobals
//Set some calculations here on how it would calculate the final damage
private function Calculate takes unit u returns real
local real r
local integer level = GetUnitAbilityLevel(u,ABILITY_ID)
set r = FINAL_DMG*level // Deals FINAL_DMG*level of ability final damage (simple math will do this and you could do this in the way you like. This is just a sample
// FINAL_DMG should be set in your globals or use a custom one if you want
return r
endfunction
//End of setting damage
//* *//
//*--------------- END OF CONFIGURATION ---------------*//
//*
globals
private hashtable thiefht = InitHashtable()
endglobals
private function ThiefSetUnitId takes unit u, unit caster, integer value returns nothing
local integer i = LoadInteger(thiefht,StringHash("thiefcastables"),GetHandleId(caster)) + 1
call SaveUnitHandle(thiefht,value,GetHandleId(caster),u)
call SaveInteger(thiefht,StringHash("thiefcastables"),GetHandleId(caster),i)
endfunction
private function ThiefEndRecycle takes unit caster returns nothing
call SaveInteger(thiefht,StringHash("thiefcastables"),GetHandleId(caster),0)
endfunction
private function Conditions takes nothing returns boolean
return GetSpellAbilityId() == ABILITY_ID
endfunction
private function ShowSFX takes unit u returns nothing
local real x
local real y
local real ux = GetUnitX(u)
local real uy = GetUnitY(u)
local integer i = 1
loop
exitwhen(i > 4)
set x = ux + RANGE * Cos(1.570796*i)
set y = uy + RANGE * Sin(1.570796*i)
call DestroyEffect(AddSpecialEffect(SFX2,x,y))
call DestroyEffect(AddSpecialEffect(SFX3,x,y))
set i = i + 1
endloop
endfunction
private struct Thief
unit caster
unit dummy
location target
integer count = 0
real dmg
boolean GroupDmg
boolean MinorDmg
static integer array Index
static integer Total = 0
static timer time = null
static method GroupDamage takes nothing returns nothing
local Thief dat
local unit f = GetEnumUnit()
local integer i = 0
loop
exitwhen i >= thistype.Total
set dat = thistype.Index[i]
if IsUnitEnemy(f,GetOwningPlayer(dat.caster)) and dat.GroupDmg then
call UnitDamageTarget(dat.caster,f,dat.dmg,true,true,ATTACK_TYPE,DAMAGE_TYPE,null)
endif
set i = i + 1
endloop
set f = null
endmethod
static method MinorDamage takes nothing returns nothing
local Thief dat
local unit f = GetEnumUnit()
local integer i = 0
loop
exitwhen i >= thistype.Total
set dat = thistype.Index[i]
if IsUnitEnemy(f,GetOwningPlayer(dat.caster)) and dat.MinorDmg then
call UnitDamageTarget(dat.caster,f,MINOR_DMG,true,true,ATTACK_TYPE,DAMAGE_TYPE,null)
endif
set i = i + 1
endloop
set f = null
endmethod
static method onLoop takes nothing returns nothing
local Thief dat
local real rnd = GetRandomReal(0,75)
local real ang
local real dist = GetRandomReal(100,500)
local real x
local real y
local group g = NewGroup()
local unit f
local unit d
local integer i = 0
loop
exitwhen i >= thistype.Total
set dat = thistype.Index[i]
set ang = GetUnitFacing(dat.caster) + GetRandomReal(0,360)
set x = GetUnitX(dat.dummy)
set y = GetUnitY(dat.dummy)
if ENABLE_RECYCLING == true then
call DestroyEffect(AddSpecialEffect(PERSFX,x,y))
if LoadInteger(thiefht,StringHash("thiefcastables"),GetHandleId(dat.caster)) == 0 then
set d = CreateUnit(GetOwningPlayer(dat.caster),ATTACKER_ID,x,y,ang)
call ThiefSetUnitId(d,dat.caster,dat)
else
set d = LoadUnitHandle(thiefht,dat,GetHandleId(dat.caster))
endif
else
set d = CreateUnit(GetOwningPlayer(dat.caster),ATTACKER_ID,x,y,ang)
endif
set dat.count = dat.count + 1
if dat.count > 8 then
call DestroyEffect(AddSpecialEffect(SFX,GetUnitX(dat.dummy),GetUnitY(dat.dummy)))
call GroupUnitsInArea(g, GetUnitX(dat.dummy), GetUnitY(dat.dummy), RANGE)
set dat.GroupDmg = true
call ForGroup(g,function Thief.GroupDamage)
set dat.GroupDmg = false
call ShowSFX(dat.dummy)
call PauseUnit(dat.caster,false)
call RemoveLocation(dat.target)
call RemoveUnit(dat.dummy)
call ThiefEndRecycle(dat.caster)
if ENABLE_RECYCLING == true then
call UnitApplyTimedLife(d,'BTLF',0.8)
set d = null
endif
call dat.destroy()
set thistype.Total = thistype.Total - 1
set thistype.Index[i] = thistype.Index[thistype.Total]
set i = i - 1
else
set x = GetUnitX(dat.dummy) + dist * Cos(ang * 0.017453292)
set y = GetUnitY(dat.dummy) + dist * Sin(ang * 0.017453292)
if dat.count == 1 then
call SetUnitAnimation(dat.dummy,"stand")
call IssuePointOrderLoc(d,"attackground",Location(x,y))
else
call IssuePointOrderLoc(d, "attackground",Location(x,y))
call GroupUnitsInArea(g, GetUnitX(dat.dummy), GetUnitY(dat.dummy), RANGE)
set dat.MinorDmg = true
call ForGroup(g,function Thief.MinorDamage)
set dat.MinorDmg = false
endif
endif
call ReleaseGroup(g)
if ENABLE_RECYCLING == false then
call UnitApplyTimedLife(d,'BTLF',0.8)
set d = null
endif
set i = i + 1
endloop
if thistype.Total == 0 then
call PauseTimer(thistype.time)
endif
set f = null
set g = null
endmethod
static method start takes unit u, location t returns Thief
local Thief dat = Thief.allocate()
local real facing = GetUnitFacing(u) - 45
local real x = GetLocationX(t)
local real y = GetLocationY(t)
call PauseUnit(u,true)
set dat.GroupDmg = false
set dat.MinorDmg = false
set dat.caster = u
set dat.target = t
set dat.dmg = Calculate(u)
set dat.dummy = CreateUnit(GetOwningPlayer(u),DUMMY_ID,x,y,facing)
call SetUnitAnimation(dat.dummy,"birth")
if thistype.Total == 0 then
call TimerStart(thistype.time, INTERVAL, true, function thistype.onLoop)
endif
set thistype.Index[thistype.Total] = dat
set thistype.Total = thistype.Total + 1
return dat
endmethod
endstruct
private function Actions takes nothing returns nothing
call Thief.start(GetTriggerUnit(),GetSpellTargetLoc())
endfunction
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 Conditions))
set Thief.time = CreateTimer()
call Preload(SFX)
call Preload(SFX2)
call Preload(SFX3)
call Preload(PERSFX)
set t = null
endfunction
endlibrary