//TESH.scrollpos=0
//TESH.alwaysfold=0
Name | Type | is_array | initial_value |
//TESH.scrollpos=0
//TESH.alwaysfold=0
//***********************************************************************************
//* By Kingz: *
//* Basic Stuff Library *
//* A library i made to speed up my coding of the submision *
//* Contains several usefull functions and several functions i use *
//* are simmilar to existing ones. *
//* Also contains the Max/Min values of the maps X/Y which are used as boundaries *
//* Used in all of the spells in this submision to provide easier coding *
//***********************************************************************************
library MathBasic initializer XY
globals
real MaxX // used for the maps Max X
real MaxY // used for the maps Max Y
real MinX // used for the maps Min X
real MinY // used for the maps Min Y
private constant real OffsetAngle = 0 // used for the Z facing function but is model based,for this model the value is 0
endglobals
//parabola function for the missile - Credits go to Moyack
constant function ParabolaZ takes real h,real d,real cd returns real
return (4*h / d)*(d - cd)*(cd / d)
endfunction
//when you need that extra true
constant function dummyFilter takes nothing returns boolean
return true
endfunction
//polar projection x
function PPX takes real x,real dist,real rad returns real
return x + dist * Cos(rad)
endfunction
//polar projection y
function PPY takes real y,real dist,real rad returns real
return y + dist * Sin(rad)
endfunction
//radian between locations
function RBL takes real x1, real y1, real x2, real y2 returns real
return Atan2(y2 - y1, x2 - x1)
endfunction
//distance between locations
function DBL takes real x1, real y1, real x2, real y2 returns real
return SquareRoot((x2-x1) * (x2-x1) + (y2-y1) * (y2-y1))
endfunction
// used for dummy unit z facings
function SetUnitZFacing takes unit whichUnit, real facingAngle returns nothing
local integer i = R2I((facingAngle+OffsetAngle)*0.7+0.5)
if i>0 then
call SetUnitAnimationByIndex(whichUnit, i)
else
call SetUnitAnimationByIndex(whichUnit, i+252)
endif
endfunction
//sets up the min/max X/Y values
function XY takes nothing returns nothing
set MaxX = GetRectMaxX(bj_mapInitialPlayableArea)
set MaxY = GetRectMaxY(bj_mapInitialPlayableArea)
set MinX = GetRectMinX(bj_mapInitialPlayableArea)
set MinY = GetRectMinY(bj_mapInitialPlayableArea)
endfunction
endlibrary
//TESH.scrollpos=-1
//TESH.alwaysfold=0
library TimedFadeUnit
struct fade2
unit u
real per
real str
static thistype array index
static integer num = 0
static timer counter = CreateTimer()
static method CreateInstance takes nothing returns fade2
local fade2 this = fade2.allocate()
set fade2.index[fade2.num] = this
set fade2.num = fade2.num +1
return this
endmethod
static method onLoop takes nothing returns nothing
local fade2 this
local integer i = 0
loop
exitwhen i >= fade2.num
set this = fade2.index[i]
set this.per = this.per - this.str
call SetUnitVertexColor(this.u,255,255,255,R2I(this.per))
if this.per <= 0.00 then
call this.destroy()
set fade2.num = fade2.num - 1
set fade2.index[i] = fade2.index[num]
endif
set i = i+1
endloop
if fade2.num == 0 then
call PauseTimer(fade2.counter)
endif
endmethod
method onDestroy takes nothing returns nothing
call RemoveUnit(this.u)
set this.u = null
endmethod
endstruct
function FadeUnitTimed takes unit u, real timeout, real startper returns nothing
local fade2 this = fade2.CreateInstance()
set this.u = u
set this.per = (1.0 - startper) * 255
set this.str = (this.per / timeout) * 0.02
if fade2.num == 1 then
call TimerStart(fade2.counter,0.02,true,function fade2.onLoop)
endif
endfunction
endlibrary
//TESH.scrollpos=-1
//TESH.alwaysfold=0
library TimedAnimationStop
struct animation2
unit u
real t
static thistype array ind
static integer num = 0
static timer timeout = CreateTimer()
method onDestroy takes nothing returns nothing
set this.u = null
endmethod
static method Create takes nothing returns animation2
local animation2 this = animation2.allocate()
set animation2.ind[num] = this
set animation2.num = animation2.num +1
return(this)
endmethod
static method StopAnimation2 takes nothing returns nothing
local animation2 this
local integer i = 0
loop
exitwhen i >= animation2.num
set this = animation2.ind[i]
set this.t = this.t - 0.02
if this.t <= 0.00 then
call PauseUnit(this.u,true)
call SetUnitTimeScale(this.u,0)
call this.destroy()
set animation2.num = animation2.num - 1
set animation2.ind[i] = animation2.ind[animation2.num]
endif
set i = i +1
endloop
if animation2.num == 0 then
call PauseTimer(animation2.timeout)
endif
endmethod
endstruct
function StopAnimationTimed takes unit u, real time returns nothing
local animation2 this = animation2.Create()
set this.u = u
set this.t = time
if animation2.num == 1 then
call TimerStart(animation2.timeout,0.02,true,function animation2.StopAnimation2)
endif
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library GroupUtils initializer Init requires optional xebasic
//******************************************************************************
//* BY: Rising_Dusk
//*
//* This library is a combination of several features relevant to groups. First
//* and foremost, it contains a group stack that you can access dynamic groups
//* from. It also provides means to refresh groups and clear any shadow
//* references within them. The included boolexprs are there for backwards
//* compatibility with maps that happen to use them. Since the 1.24c patch,
//* null boolexprs used in GroupEnumUnits* calls no longer leak, so there is no
//* performance gain to using the BOOLEXPR_TRUE constant.
//*
//* Instead of creating/destroying groups, we have moved on to recycling them.
//* NewGroup pulls a group from the stack and ReleaseGroup adds it back. Always
//* remember to call ReleaseGroup on a group when you are done using it. If you
//* fail to do so enough times, the stack will overflow and no longer work.
//*
//* GroupRefresh cleans a group of any shadow references which may be clogging
//* its hashtable. If you remove a unit from the game who is a member of a unit
//* group, it will 'effectively' remove the unit from the group, but leave a
//* shadow in its place. Calling GroupRefresh on a group will clean up any
//* shadow references that may exist within it. It is only worth doing this on
//* groups that you plan to have around for awhile.
//*
//* Constants that can be used from the library:
//* [group] ENUM_GROUP As you might expect, this group is good for
//* when you need a group just for enumeration.
//* [boolexpr] BOOLEXPR_TRUE This is a true boolexpr, which is important
//* because a 'null' boolexpr in enumeration
//* calls results in a leak. Use this instead.
//* [boolexpr] BOOLEXPR_FALSE This exists mostly for completeness.
//*
//* This library also includes a simple implementation of a group enumeration
//* call that factors collision of units in a given area of effect. This is
//* particularly useful because GroupEnumUnitsInRange doesn't factor collision.
//*
//* In your map, you can just replace all instances of GroupEnumUnitsInRange
//* with GroupEnumUnitsInArea with identical arguments and your spells will
//* consider all units colliding with the area of effect. After calling this
//* function as you would normally call GroupEnumUnitsInRange, you are free to
//* do anything with the group that you would normally do.
//*
//* If you don't use xebasic in your map, you may edit the MAX_COLLISION_SIZE
//* variable below and the library will use that as the added radius to check.
//* If you use xebasic, however, the script will automatically use xe's
//* collision size variable.
//*
//* You are also able to use GroupUnitsInArea. This function returns all units
//* within the area, no matter what they are, which can be convenient for those
//* instances where you actually want that.
//*
//* Example usage:
//* local group MyGroup = NewGroup()
//* call GroupRefresh(MyGroup)
//* call ReleaseGroup(MyGroup)
//* call GroupEnumUnitsInArea(ENUM_GROUP, x, y, 350., BOOLEXPR_TRUE)
//* call GroupUnitsInArea(ENUM_GROUP, x, y, 350.)
//*
globals
//If you don't have xebasic in your map, this value will be used instead.
//This value corresponds to the max collision size of a unit in your map.
private constant real MAX_COLLISION_SIZE = 197.
//If you are insane and don't care about any of the protection involved in
//this library, but want this script to be really fast, set this to true.
private constant boolean LESS_SAFETY = false
endglobals
globals
//* Constants that are available to the user
group ENUM_GROUP = CreateGroup()
boolexpr BOOLEXPR_TRUE = null
boolexpr BOOLEXPR_FALSE = null
endglobals
globals
//* Hashtable for debug purposes
private hashtable ht = InitHashtable()
//* Temporary references for GroupRefresh
private boolean Flag = false
private group Refr = null
//* Arrays and counter for the group stack
private group array Groups
private integer Count = 0
//* Variables for use with the GroupUnitsInArea function
private real X = 0.
private real Y = 0.
private real R = 0.
private hashtable H = InitHashtable()
endglobals
private function HookDestroyGroup takes group g returns nothing
if g == ENUM_GROUP then
call BJDebugMsg(SCOPE_PREFIX+"Warning: ENUM_GROUP destroyed")
endif
endfunction
debug hook DestroyGroup HookDestroyGroup
private function AddEx takes nothing returns nothing
if Flag then
call GroupClear(Refr)
set Flag = false
endif
call GroupAddUnit(Refr, GetEnumUnit())
endfunction
function GroupRefresh takes group g returns nothing
set Flag = true
set Refr = g
call ForGroup(Refr, function AddEx)
if Flag then
call GroupClear(g)
endif
endfunction
function NewGroup takes nothing returns group
if Count == 0 then
set Groups[0] = CreateGroup()
else
set Count = Count - 1
endif
static if not LESS_SAFETY then
call SaveInteger(ht, 0, GetHandleId(Groups[Count]), 1)
endif
return Groups[Count]
endfunction
function ReleaseGroup takes group g returns boolean
local integer id = GetHandleId(g)
static if LESS_SAFETY then
if g == null then
debug call BJDebugMsg(SCOPE_PREFIX+"Error: Null groups cannot be released")
return false
elseif Count == 8191 then
debug call BJDebugMsg(SCOPE_PREFIX+"Error: Max groups achieved, destroying group")
call DestroyGroup(g)
return false
endif
else
if g == null then
debug call BJDebugMsg(SCOPE_PREFIX+"Error: Null groups cannot be released")
return false
elseif not HaveSavedInteger(ht, 0, id) then
debug call BJDebugMsg(SCOPE_PREFIX+"Error: Group not part of stack")
return false
elseif LoadInteger(ht, 0, id) == 2 then
debug call BJDebugMsg(SCOPE_PREFIX+"Error: Groups cannot be multiply released")
return false
elseif Count == 8191 then
debug call BJDebugMsg(SCOPE_PREFIX+"Error: Max groups achieved, destroying group")
call DestroyGroup(g)
return false
endif
call SaveInteger(ht, 0, id, 2)
endif
call GroupClear(g)
set Groups[Count] = g
set Count = Count + 1
return true
endfunction
private function Filter takes nothing returns boolean
return IsUnitInRangeXY(GetFilterUnit(), X, Y, R)
endfunction
private function HookDestroyBoolExpr takes boolexpr b returns nothing
local integer bid = GetHandleId(b)
if HaveSavedHandle(H, 0, bid) then
//Clear the saved boolexpr
call DestroyBoolExpr(LoadBooleanExprHandle(H, 0, bid))
call RemoveSavedHandle(H, 0, bid)
endif
endfunction
hook DestroyBoolExpr HookDestroyBoolExpr
private constant function GetRadius takes real radius returns real
static if LIBRARY_xebasic then
return radius+XE_MAX_COLLISION_SIZE
else
return radius+MAX_COLLISION_SIZE
endif
endfunction
function GroupEnumUnitsInArea takes group whichGroup, real x, real y, real radius, boolexpr filter returns nothing
local real prevX = X
local real prevY = Y
local real prevR = R
local integer bid = 0
//Set variables to new values
set X = x
set Y = y
set R = radius
if filter == null then
//Adjusts for null boolexprs passed to the function
set filter = Condition(function Filter)
else
//Check for a saved boolexpr
set bid = GetHandleId(filter)
if HaveSavedHandle(H, 0, bid) then
//Set the filter to use to the saved one
set filter = LoadBooleanExprHandle(H, 0, bid)
else
//Create a new And() boolexpr for this filter
set filter = And(Condition(function Filter), filter)
call SaveBooleanExprHandle(H, 0, bid, filter)
endif
endif
//Enumerate, if they want to use the boolexpr, this lets them
call GroupEnumUnitsInRange(whichGroup, x, y, GetRadius(radius), filter)
//Give back original settings so nested enumerations work
set X = prevX
set Y = prevY
set R = prevR
endfunction
function GroupUnitsInArea takes group whichGroup, real x, real y, real radius returns nothing
local real prevX = X
local real prevY = Y
local real prevR = R
//Set variables to new values
set X = x
set Y = y
set R = radius
//Enumerate
call GroupEnumUnitsInRange(whichGroup, x, y, GetRadius(radius), Condition(function Filter))
//Give back original settings so nested enumerations work
set X = prevX
set Y = prevY
set R = prevR
endfunction
private function True takes nothing returns boolean
return true
endfunction
private function False takes nothing returns boolean
return false
endfunction
private function Init takes nothing returns nothing
set BOOLEXPR_TRUE = Condition(function True)
set BOOLEXPR_FALSE = Condition(function False)
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library TimerUtils initializer init
//*********************************************************************
//* TimerUtils (red+blue+orange flavors for 1.24b+)
//* ----------
//*
//* To implement it , create a custom text trigger called TimerUtils
//* and paste the contents of this script there.
//*
//* To copy from a map to another, copy the trigger holding this
//* library to your map.
//*
//* (requires vJass) More scripts: htt://www.wc3c.net
//*
//* For your timer needs:
//* * Attaching
//* * Recycling (with double-free protection)
//*
//* set t=NewTimer() : Get a timer (alternative to CreateTimer)
//* ReleaseTimer(t) : Relese a timer (alt to DestroyTimer)
//* SetTimerData(t,2) : Attach value 2 to timer
//* GetTimerData(t) : Get the timer's value.
//* You can assume a timer's value is 0
//* after NewTimer.
//*
//* Multi-flavor:
//* Set USE_HASH_TABLE to true if you don't want to complicate your life.
//*
//* If you like speed and giberish try learning about the other flavors.
//*
//********************************************************************
//================================================================
globals
//How to tweak timer utils:
// USE_HASH_TABLE = true (new blue)
// * SAFEST
// * SLOWEST (though hash tables are kind of fast)
//
// USE_HASH_TABLE = false, USE_FLEXIBLE_OFFSET = true (orange)
// * kinda safe (except there is a limit in the number of timers)
// * ALMOST FAST
//
// USE_HASH_TABLE = false, USE_FLEXIBLE_OFFSET = false (red)
// * THE FASTEST (though is only faster than the previous method
// after using the optimizer on the map)
// * THE LEAST SAFE ( you may have to tweak OFSSET manually for it to
// work)
//
private constant boolean USE_HASH_TABLE = true
private constant boolean USE_FLEXIBLE_OFFSET = false
private constant integer OFFSET = 0x100000
private integer VOFFSET = OFFSET
//Timers to preload at map init:
private constant integer QUANTITY = 256
//Changing this to something big will allow you to keep recycling
// timers even when there are already AN INCREDIBLE AMOUNT of timers in
// the stack. But it will make things far slower so that's probably a bad idea...
private constant integer ARRAY_SIZE = 8190
endglobals
//==================================================================================================
globals
private integer array data[ARRAY_SIZE]
private hashtable ht
endglobals
//It is dependent on jasshelper's recent inlining optimization in order to perform correctly.
function SetTimerData takes timer t, integer value returns nothing
static if(USE_HASH_TABLE) then
// new blue
call SaveInteger(ht,0,GetHandleId(t), value)
elseif (USE_FLEXIBLE_OFFSET) then
// orange
static if (DEBUG_MODE) then
if(GetHandleId(t)-VOFFSET<0) then
call BJDebugMsg("SetTimerData: Wrong handle id, only use SetTimerData on timers created by NewTimer")
endif
endif
set data[GetHandleId(t)-VOFFSET]=value
else
// new red
static if (DEBUG_MODE) then
if(GetHandleId(t)-OFFSET<0) then
call BJDebugMsg("SetTimerData: Wrong handle id, only use SetTimerData on timers created by NewTimer")
endif
endif
set data[GetHandleId(t)-OFFSET]=value
endif
endfunction
function GetTimerData takes timer t returns integer
static if(USE_HASH_TABLE) then
// new blue
return LoadInteger(ht,0,GetHandleId(t) )
elseif (USE_FLEXIBLE_OFFSET) then
// orange
static if (DEBUG_MODE) then
if(GetHandleId(t)-VOFFSET<0) then
call BJDebugMsg("SetTimerData: Wrong handle id, only use SetTimerData on timers created by NewTimer")
endif
endif
return data[GetHandleId(t)-VOFFSET]
else
// new red
static if (DEBUG_MODE) then
if(GetHandleId(t)-OFFSET<0) then
call BJDebugMsg("SetTimerData: Wrong handle id, only use SetTimerData on timers created by NewTimer")
endif
endif
return data[GetHandleId(t)-OFFSET]
endif
endfunction
//==========================================================================================
globals
private timer array tT[ARRAY_SIZE]
private integer tN = 0
private constant integer HELD=0x28829022
//use a totally random number here, the more improbable someone uses it, the better.
endglobals
//==========================================================================================
function NewTimer takes nothing returns timer
if (tN==0) then
//If this happens then the QUANTITY rule has already been broken, try to fix the
// issue, else fail.
debug call BJDebugMsg("NewTimer: Warning, Exceeding TimerUtils_QUANTITY, make sure all timers are getting recycled correctly")
static if( not USE_HASH_TABLE) then
debug call BJDebugMsg("In case of errors, please increase it accordingly, or set TimerUtils_USE_HASH_TABLE to true")
set tT[0]=CreateTimer()
static if( USE_FLEXIBLE_OFFSET) then
if (GetHandleId(tT[0])-VOFFSET<0) or (GetHandleId(tT[0])-VOFFSET>=ARRAY_SIZE) then
//all right, couldn't fix it
call BJDebugMsg("NewTimer: Unable to allocate a timer, you should probably set TimerUtils_USE_HASH_TABLE to true or fix timer leaks.")
return null
endif
else
if (GetHandleId(tT[0])-OFFSET<0) or (GetHandleId(tT[0])-OFFSET>=ARRAY_SIZE) then
//all right, couldn't fix it
call BJDebugMsg("NewTimer: Unable to allocate a timer, you should probably set TimerUtils_USE_HASH_TABLE to true or fix timer leaks.")
return null
endif
endif
endif
else
set tN=tN-1
endif
call SetTimerData(tT[tN],0)
return tT[tN]
endfunction
//==========================================================================================
function ReleaseTimer takes timer t returns nothing
if(t==null) then
debug call BJDebugMsg("Warning: attempt to release a null timer")
return
endif
if (tN==ARRAY_SIZE) then
debug call BJDebugMsg("Warning: Timer stack is full, destroying timer!!")
//stack is full, the map already has much more troubles than the chance of bug
call DestroyTimer(t)
else
call PauseTimer(t)
if(GetTimerData(t)==HELD) then
debug call BJDebugMsg("Warning: ReleaseTimer: Double free!")
return
endif
call SetTimerData(t,HELD)
set tT[tN]=t
set tN=tN+1
endif
endfunction
private function init takes nothing returns nothing
local integer i=0
local integer o=-1
local boolean oops = false
static if( USE_HASH_TABLE ) then
set ht = InitHashtable()
loop
exitwhen(i==QUANTITY)
set tT[i]=CreateTimer()
call SetTimerData(tT[i], HELD)
set i=i+1
endloop
set tN = QUANTITY
else
loop
set i=0
loop
exitwhen (i==QUANTITY)
set tT[i] = CreateTimer()
if(i==0) then
set VOFFSET = GetHandleId(tT[i])
static if(USE_FLEXIBLE_OFFSET) then
set o=VOFFSET
else
set o=OFFSET
endif
endif
if (GetHandleId(tT[i])-o>=ARRAY_SIZE) then
exitwhen true
endif
if (GetHandleId(tT[i])-o>=0) then
set i=i+1
endif
endloop
set tN = i
exitwhen(tN == QUANTITY)
set oops = true
exitwhen not USE_FLEXIBLE_OFFSET
debug call BJDebugMsg("TimerUtils_init: Failed a initialization attempt, will try again")
endloop
if(oops) then
static if ( USE_FLEXIBLE_OFFSET) then
debug call BJDebugMsg("The problem has been fixed.")
//If this message doesn't appear then there is so much
//handle id fragmentation that it was impossible to preload
//so many timers and the thread crashed! Therefore this
//debug message is useful.
elseif(DEBUG_MODE) then
call BJDebugMsg("There were problems and the new timer limit is "+I2S(i))
call BJDebugMsg("This is a rare ocurrence, if the timer limit is too low:")
call BJDebugMsg("a) Change USE_FLEXIBLE_OFFSET to true (reduces performance a little)")
call BJDebugMsg("b) or try changing OFFSET to "+I2S(VOFFSET) )
endif
endif
endif
endfunction
endlibrary
//TESH.scrollpos=-1
//TESH.alwaysfold=0
//***************************************************************************
//*
//* TimedHandles - By TriggerHappy187
//*
//***************************************************************************
//*
//* Installation
//* Simply copy this script into your map, as well as TimerUtils.
//*
//***************************************************************************
//*
//* Documentation
//*
//* All this script does it associates a handle to a
//* timer and then destroys the handle upon the timer's expiration.
//*
//***************************************************************************
//*
//* The Public Functions
//*
//* $DESTROY$Timed - Starts the handle and it's timer, once it expires
//* the handle will be destroyed.
//*
//***************************************************************************
//*
//* Examples
//*
//* call DestroyEffectTimed(AddSpecialEffect("MODELNAME", X, X), 2)
//* call DestroyEffectTimed(AddSpecialEffectTarget("MODELNAME", unit, "attachment-point"), 2)
//*
//***************************************************************************
library TimedHandles requires TimerUtils
//! textmacro TIMEDHANDLES takes HANDLE,DESTROY
struct $HANDLE$timed
$HANDLE$ $HANDLE$_var
private static method remove takes nothing returns nothing
local timer t = GetExpiredTimer()
local $HANDLE$timed d = GetTimerData(t)
call $DESTROY$(d.$HANDLE$_var)
call ReleaseTimer(t)
call d.destroy()
endmethod
static method create takes $HANDLE$ h, real timeout returns $HANDLE$timed
local $HANDLE$timed t = $HANDLE$timed.allocate()
local timer ti = NewTimer()
set t.$HANDLE$_var = h
call SetTimerData(ti, t)
call TimerStart(ti, timeout, false, function $HANDLE$timed.remove)
return t
endmethod
endstruct
function $DESTROY$Timed takes $HANDLE$ h, real duration returns nothing
call $HANDLE$timed.create(h, duration)
endfunction
//! endtextmacro
//! runtextmacro TIMEDHANDLES("effect","DestroyEffect")
//! runtextmacro TIMEDHANDLES("lightning","DestroyLightning")
//! runtextmacro TIMEDHANDLES("weathereffect","RemoveWeatherEffect")
//! runtextmacro TIMEDHANDLES("item","RemoveItem")
//! runtextmacro TIMEDHANDLES("ubersplat","DestroyUbersplat")
endlibrary
//TESH.scrollpos=-1
//TESH.alwaysfold=0
//a simple library which is used to inline GroupAddGroup() function
//made by Anachron
library Group2Group
globals
private group tmp = null
endglobals
private function addGroupUnit takes nothing returns nothing
call GroupAddUnit(tmp, GetEnumUnit())
endfunction
function Group2Group takes group src, group tar returns group
set tmp = tar
call ForGroup(src, function addGroupUnit)
return tar
endfunction
endlibrary
//TESH.scrollpos=-1
//TESH.alwaysfold=0
library Windcut initializer InitWindCut requires TimerUtils,GroupUtils,MathBasic,TimedFadeUnit,TimedAnimationStop,Group2Group
//SETTINGS
globals
// ID's
private constant integer Spell_ID = 'A000' // spell ID must match this value
private constant integer Dummy_ID = 'e000' // dummy unit Id must match this value
// end of ID setup
private constant boolean InvulnerableCaster = false // if true caster is invulnerable
// damage
private constant real BaseDamage = 60.00 // base damage per slash
private constant real DamageInc = 25 // damage added on base damage with every levelup of the ability
// end of damage options
// eyecandy
private constant string SlashEff = "Objects\\Spawnmodels\\Human\\HumanBlood\\BloodElfSpellThiefBlood.mdl" // effect created on unit strike
private constant string WeaponEff = "Abilities\\Spells\\NightElf\\Blink\\BlinkCaster.mdl" // effect created on illusions blade
private constant string TrailEff = "Abilities\\Weapons\\GlaiveMissile\\GlaiveMissileTarget.mdl" // trail effect which is created on the ground as the hero moves
private constant integer ESR = 3 // ESR = Effect Spam Ration, increase in this = less effects, decrease = more effects (used for trail effects)
// end of eyecandy options
// fade options
private constant real CasterFade = 0.55 // takes a value from 0.00 to 1.00; 0.00 is transparent, 1.00 is normal value of every unit.
// 0.7 = 70% visibility, 30% transparency
private constant real ImageFade = 0.45 // same as CasterFade but for illusions
private constant real FadeTime = 0.3 // fade time for illusions, 0.3 = 0.3 seconds of delay before the trail illusions behind the heroes are removed
private constant real AnimStopValue = 0.85 // varies from model to model, takes a value when the animation is stoped
// blademaster's animation of attack ("attack") is 1.167 seconds so this is
// a user defined value, there is no equation for it
private constant real FadeTimeEx = 3.00 // this value is used for the illusions that play the attack animation
// this value should be larget than FadeTime to show the full eyecandy
// and the effect of TimedAnimationStop
// end of fade options
// speed related things
private constant real FPS = 30.00 // optimal values from 30 to 60
private constant real ChargeSpeed = 1025 * (1/FPS) // speed of the hero,uses WC3 movement speed values, don't touch anything after the sign *
private constant real AoE = 366.66 // AoE which is actualy used for a strange AoE calculated by distance from caster to cast point
// end of speed options
endglobals
//END OF SETTINGS
// Don't Touch the stuff bellow this point
globals
private unit TU = null
private player TP = null
private real TR = 0.00
private group FG = CreateGroup()
private constant real MinOffset = 50.00
endglobals
private function GroupFilter takes nothing returns boolean
return GetWidgetLife(GetFilterUnit()) > .405 and IsUnitInGroup(GetFilterUnit(),FG)==false and GetFilterUnit() != TU and IsUnitType(GetFilterUnit(),UNIT_TYPE_STRUCTURE)==false and IsUnitType(GetFilterUnit(),UNIT_TYPE_FLYING)==false and IsUnitEnemy(GetFilterUnit(),TP) and IsUnitType(GetFilterUnit(),UNIT_TYPE_MECHANICAL)==false
endfunction
private function groupfunc takes nothing returns nothing
call GroupAddUnit(FG,GetEnumUnit())
endfunction
private constant function GetDamage takes integer lvl returns real
return BaseDamage + (lvl-1)*DamageInc
endfunction
private function ExtractInteger takes real r returns integer
local integer i = R2I(r)
local real s = r - I2R(i)
if s >= 0.50 then
set i = i+1
endif
return i
endfunction
private struct windcut
unit u
unit tar
group g
group d
timer t
real x
real y
real tx
real ty
real rad
real tpx
real tpy
real dmg
method onDestroy takes nothing returns nothing
call SetUnitVertexColor(this.u,255,255,255,255)
if InvulnerableCaster then
call SetUnitInvulnerable(this.u,false)
endif
call SetUnitTimeScale(this.u,1)
set this.u = null
call GroupClear(this.g)
call GroupClear(this.d)
call ReleaseGroup(this.g)
call ReleaseGroup(this.d)
set this.g = null
set this.d = null
endmethod
static method Create takes nothing returns windcut
local windcut this = windcut.allocate()
return(this)
endmethod
static method motion takes nothing returns nothing
local windcut this = GetTimerData(GetExpiredTimer())
local unit tu = CreateUnit(GetOwningPlayer(this.u),Dummy_ID,this.x,this.y,this.rad*bj_RADTODEG)
call SetUnitX(tu,this.x)
call SetUnitY(tu,this.y)
call SetUnitFacing(this.u,this.rad*bj_RADTODEG)
if this.tar != null then
set this.tx = GetUnitX(this.tar)
set this.ty = GetUnitY(this.tar)
set this.rad = RBL(this.x,this.y,this.tx,this.ty)
set this.x = this.x + ChargeSpeed * Cos(this.rad)
set this.y = this.y + ChargeSpeed * Sin(this.rad)
call SetUnitX(this.u,this.x)
call SetUnitY(this.u,this.y)
if TrailEff != "" and GetRandomInt(0,ESR) == ESR then
call DestroyEffectTimed(AddSpecialEffect(TrailEff,this.x,this.y),1)
endif
if DBL(this.x,this.y,this.tx,this.ty) <= 128 and this.tar != null then
call UnitDamageTarget(this.u,this.tar,this.dmg,true,false,null,null,null)
if WeaponEff != "" then
call DestroyEffectTimed(AddSpecialEffectTarget(WeaponEff,tu,"weapon"),FadeTimeEx/2)
endif
if SlashEff != "" then
call DestroyEffectTimed(AddSpecialEffectTarget(SlashEff,this.tar,"chest"),FadeTimeEx/2)
endif
call SetUnitAnimation(tu,"attack")
call FadeUnitTimed(tu,FadeTimeEx,ImageFade)
call StopAnimationTimed(tu,0.80)
call GroupRemoveUnit(this.g,this.tar)
set this.tar = FirstOfGroup(this.g)
else
call FadeUnitTimed(tu,FadeTime,ImageFade)
endif
else
if DBL(this.x,this.y,this.tpx,this.tpy) <= MinOffset then
call RemoveUnit(tu)
call PauseTimer(GetExpiredTimer())
call ReleaseTimer(GetExpiredTimer())
set this.t = null
call this.destroy()
else
if TrailEff != "" and GetRandomInt(0,ESR) == ESR then
call DestroyEffectTimed(AddSpecialEffect(TrailEff,this.x,this.y),1)
endif
set this.rad = RBL(this.x,this.y,this.tpx,this.tpy)
set this.x = this.x + ChargeSpeed * Cos(this.rad)
set this.y = this.y + ChargeSpeed * Sin(this.rad)
call SetUnitX(this.u,this.x)
call SetUnitY(this.u,this.y)
call FadeUnitTimed(tu,FadeTime,ImageFade)
endif
endif
if this.x > MaxX or this.x < MinX or this.y > MaxY or this.y < MinY then
set this.tar = null
set this.x = this.x - ChargeSpeed * Cos(this.rad)
set this.y = this.y - ChargeSpeed * Sin(this.rad)
set this.tpx = this.x
set this.tpy = this.y
endif
endmethod
endstruct
private function condition2run takes nothing returns boolean
local windcut this
local real d
local integer groupnum
local integer i
local real x
local real y
if GetSpellAbilityId() == Spell_ID then
set this = windcut.Create()
set this.g = NewGroup()
set this.d = NewGroup()
set this.u = GetTriggerUnit()
set this.t = NewTimer()
set this.x = GetUnitX(this.u)
set this.y = GetUnitY(this.u)
set this.tpx = GetSpellTargetX()
set this.tpy = GetSpellTargetY()
set this.rad = RBL(this.x,this.y,this.tpx,this.tpy)
set this.dmg = GetDamage(GetUnitAbilityLevel(this.u,Spell_ID))
call SetUnitVertexColor(this.u,255,255,255, 255 - R2I(CasterFade*255))
if InvulnerableCaster then
call SetUnitInvulnerable(this.u,true)
endif
call SetUnitTimeScale(this.u,0)
set d = DBL(this.x,this.y,this.tpx,this.tpy)
set groupnum = ExtractInteger(d / AoE)
set i = 0
set x = this.x
set y = this.y
if groupnum < 1 then
set groupnum = 1
endif
loop
exitwhen i > groupnum
set TU = this.u
set TP = GetOwningPlayer(TU)
call GroupEnumUnitsInRange(this.d,x,y,AoE,Filter(function GroupFilter))
call ForGroup(this.d,function groupfunc)
call Group2Group(this.d,this.g)
set x = x + (AoE) * Cos(this.rad)
set y = y + (AoE) * Sin(this.rad)
call GroupClear(this.d)
set i = i+1
endloop
call GroupClear(FG)
call SetTimerData(this.t,integer(this))
call TimerStart(this.t,1/FPS,true,function windcut.motion)
set this.tar = FirstOfGroup(this.g)
set this.tx = GetUnitX(this.tar)
set this.ty = GetUnitY(this.tar)
set this.rad = RBL(this.x,this.y,this.tx,this.ty)
endif
return false
endfunction
private function InitWindCut takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t,EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(t,Condition(function condition2run))
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=1
//*********************************************************************************
// CREDITS *
//*********************************************************************************
//***************************************************************************************************************** *
//Credits to Rising_Dusk *
//Credits to Vexorian for so many reasons(do i even have to name them?) *
//Credits to TriggerHappy187 for TimedHandles library *
//Credits to Volvox for making the terrain. *
//Credits to Eccho for the test map. *
//*****************************************************************************************************************
function InitTrig_Credits takes nothing returns nothing
endfunction