Angel_Island
Much long, many time, wow
- Reaction score
- 56
Impale System (IMPS)
By Angel_Island
By Angel_Island
Code:
JASS:
library IMPS initializer InitTrig
//=====================================================================================\\
// \\
// Impale System (IMPS) \\
// By Angel_Island \\
// \\
// This system makes easy configurable impale spells. \\
// It allows impaling targets multiple times even when the target is in mid-air \\
// \\
// Requires: \\
// - A vJASS preprocessor like NewGen. \\
// - A dummy unit. \\
// \\
//=====================================================================================\\
//=====================================================================================\\
// \\
// How to implement: \\
// \\
// 1. Create a new trigger in your map. Convert it to custom text. Copy this \\
// entire script and paste it in the new trigger overwriting what was inside. \\
// Or if you want to do it the easy way, just copy this trigger to your map. \\
// \\
// 2. Create a dummy unit or copy the dummy in this map. Should have Id 'h000'. \\
// Else change it below in configurables. \\
// \\
// 3. Done! Try it out by making a spell using this system. \\
// \\
//=====================================================================================\\
//==============================================================================================================================================================\\
// \\
// How to use: \\
// \\
// call IMPS_Start(Caster,X,Y,Range,Damage,StunDuration,Angle) \\
// - Gives you a normal impale that uses x,y \\
// \\
// or \\
// \\
// call IMPS_StartLoc(Caster,Point,Range,Damage,StunDuration,Angle) \\
// - Gives you a normal impale that uses locations \\
// \\
// or \\
// \\
//call IMPS_StartLocEx(Caster,Point,CastPoint,Range,Damage,StunDuration,Angle,Area,Height,AirTime,SpikeSfx,HitSfx,StunSfx,AttPoint,RangeBased,MoveUnit,HideUnit)\\
// - Gives you a more customizable impale that uses locations \\
// \\
// or \\
// \\
//call IMPS_StartEx(Caster,X,Y,CastX,CastY,Range,Damage,StunDuration,Angle,Area,Height,AirTime,SpikeSfx,HitSfx,StunSfx,AttPoint,RangeBased,MoveUnit,HideUnit) \\
// - Gives you a more customizable impale that uses x,y \\
// \\
// Caster: The unit who casted the spell or whatever it did. \\
// Point: The point where the impale begins. \\
// X,Y: x,y coordinates of the Caster. \\
// CastPoint: The point where the spell is cast. Not needed if RangeBased = false \\
// CastX,CastY: x,y coordinates of target point. Not needed if RangeBased = false \\
// Range: How long the impale will go. Not needed if RangeBased = true. \\
// Damage: How much damage that will be dealt to the targets. \\
// StunDuration: How long the impale will stun the targets. Can be set to 0.00 without stunning forever. \\
// Angle: The angle the impale will go. Must be in degrees. \\
// Area: How big area the impale will have when picking targets. \\
// Height: How high up in the air the targets will fly. \\
// AirTime: How long time in the air the targets will be. \\
// SpikeSfx: Model for the spikes. \\
// HitSfx: Effect when targets are hit. \\
// StunSfx: Effect when targets are stunned. \\
// AttPoint: Where StunSfx is attached on the target \\
// RangeBased: This will decide if the impale will be based on how far away you cast your impale. Won't work if \\
// there is no target location. \\
// MoveUnit: Decides if the Caster will be moved to the end of the impale. \\
// HideUnit: Decides if you want to hide the Caster while the impale is in effect. Good for spells like \\
// Burrowstrike from DotA where the caster digs underground and pops up at the end of the impale \\
// \\
//==============================================================================================================================================================\\
//=====================================================================================\\
// \\
// Other functions: \\
// \\
// call IsUnitImpaled(Unit): Checks if the Unit is in mid-air caused by an impale\\
// Good for making things happen if the Unit is in \\
// mid-air. \\
// \\
//=====================================================================================\\
//CONFIGURABLES:
globals
private constant real HEIGHT = 500.00
//How high up the targets will fly. Used in IMPS_Start(Loc).
private constant real AREA = 175.00
//How big area the impale will have when picking targets. Used in IMPS_Start(Loc).
private constant real AIRTIME = 1.00
//How long time in the air the targets will be. Used in IMPS_Start(Loc).
constant string SPIKE_SFX = "Abilities\\Spells\\Undead\\Impale\\ImpaleMissTarget.mdl"
//Model for the spikes for IMPS_Start(Loc). This is not private so you can use this
//variable instead of have to type in everything.
constant string HIT_SFX = "Abilities\\Spells\\Undead\\Impale\\ImpaleHitTarget.mdl"
//Effect when targets are hit for IMPS_Start(Loc). Same reason as above why it isnt private.
constant string STUN_SFX = "Abilities\\Spells\\Human\\Thunderclap\\ThunderclapTarget.mdl"
//Effect when targets are stunned for IMPS_Start(Loc).
constant string ATT_POINT = "overhead"
//Where StunSfx is attached on the targets.
private constant real SPACE = 150.00
//Space between every spike. I recommend you leave this as it is.
private constant real SPIKE_INTERVAL = 0.10
//Interval between spawning spikes.
private constant real INTERVAL = 0.03
//Interval between height change. You should leave this as it is.
private constant integer STORM_CROW = 039;Arav039;
//Raw code for Storm crow form.
private constant integer DUMMY = 039;h000039;
//Raw code for Dummy.
endglobals
//=====================================================================//
// //
// DON'T TOUCH BELOW HERE UNLESS YOU KNOW WHAT YOU ARE DOING //
// //
//=====================================================================//
private keyword Data
globals
private Data array Dt
private unit array caster
private unit array ImpaledUnit
private integer array in
private integer array I
private integer I2 = 0
private integer Instances = 0
private integer CusVal = 0
private integer Loop = 1
private integer Loop2 = 1
private timer Timer = CreateTimer()
private timer Timer2 = CreateTimer()
private timer Timer3 = CreateTimer()
private real array n
private real array x
private real array y
private real array damage
private real array airtime
private real array stunduration
private real array height
private string array hitsfx
private string array stunsfx
private string array attpoint
private group array G
private group array StunG
private effect array stuneffect
private hashtable h = InitHashtable()
endglobals
//======================================================================
private struct Data
unit caster = null
effect sfx = null
real px = 0.00
real py = 0.00
real castrange = 0.00
real range = 0.00
real stunduration = 0.00
real sin = 0.00
real cos = 0.00
real area = 0.00
real airtime = 0.00
real damage = 0.00
real height = 0.00
string spikesfx = ""
string hitsfx = ""
string stunsfx = ""
string attpoint = ""
boolean based = false
boolean moveunit = false
boolean hideunit = false
static method create takes unit Caster, real X, real Y, real CastX, real CastY, real Range, real Damage, real StunDuration, real Angle, real Area, real Height, real AirTime, string SpikeSfx, string HitSfx, string StunSfx, string AttPoint, boolean RangeBased, boolean MoveUnit, boolean HideUnit returns Data
local Data d = Data.allocate()
local real dx = 0.00
local real dy = 0.00
set dx = CastX - X
set dy = CastY - Y
set d.caster = Caster
set d.px = X
set d.py = Y
set d.castrange = SquareRoot(dx * dx + dy * dy)
set d.range = Range
set d.damage = Damage
set d.stunduration = StunDuration
set d.sin = Sin(Angle)
set d.cos = Cos(Angle)
set d.area = Area
set d.height = Height
set d.airtime = AirTime
set d.spikesfx = SpikeSfx
set d.hitsfx = HitSfx
set d.stunsfx = StunSfx
set d.attpoint = AttPoint
set d.based = RangeBased
set d.moveunit = MoveUnit
set d.hideunit = HideUnit
return d
endmethod
endstruct
//=====================================================================
private function Check_Units takes nothing returns boolean
local unit u
local player p
set u = GetFilterUnit()
set p = GetOwningPlayer(caster[Loop])
return IsUnitEnemy(u,p) and GetWidgetLife(u) > 0 and IsUnitType(u,UNIT_TYPE_STRUCTURE) == false and u != caster[Loop] and IsUnitInGroup(u,G[Loop]) == false
endfunction
private function Check_Dummy takes nothing returns boolean
return GetUnitTypeId(GetTriggerUnit()) == DUMMY
endfunction
private function CountUnits takes nothing returns nothing
set bj_groupCountUnits = bj_groupCountUnits + 1
endfunction
//=====================================================================
private function Flying takes nothing returns nothing
local real xx
local real yy
local unit u
local unit un
set I[Loop2] = I[Loop2] + 1
set u = GetEnumUnit()
call PauseUnit(u,true)
call SaveReal(h,I[Loop2],Loop2,LoadReal(h,I[Loop2],Loop2) + (SquareRoot(height[Loop2]) * 2.00) / (airtime[Loop2] / INTERVAL))
call SetUnitFlyHeight(u,(height[Loop2]) - (SquareRoot(height[Loop2]) - LoadReal(h,I[Loop2],Loop2)) * (SquareRoot(height[Loop2]) - LoadReal(h,I[Loop2],Loop2)),0.00)
if GetUnitFlyHeight(u) <= (SquareRoot(height[Loop2]) * 2.00) / (airtime[Loop2] / INTERVAL) then
set I2 = I2 + 1
call PauseUnit(u,false)
call SetUnitPathing(u,true)
call SetUnitFlyHeight(u,GetUnitDefaultFlyHeight(u),0.00)
call UnitDamageTarget(caster[Loop2],u,damage[Loop2],true,false,ATTACK_TYPE_NORMAL,DAMAGE_TYPE_UNKNOWN,WEAPON_TYPE_WHOKNOWS)
call GroupRemoveUnit(G[Loop2],u)
if GetUnitState(u,UNIT_STATE_LIFE) > 0 and stunduration[Loop2] > 0.00 then
set CusVal = CusVal + 1
set StunG[CusVal] = CreateGroup()
call GroupAddUnit(StunG[CusVal],u)
set ImpaledUnit[CusVal] = u
set stuneffect[CusVal] = AddSpecialEffectTarget(stunsfx[Loop2],u,attpoint[Loop2])
set xx = GetUnitX(u)
set yy = GetUnitY(u)
set un = CreateUnit(GetOwningPlayer(caster[Loop2]),DUMMY,xx,yy,270.00)
call UnitApplyTimedLife(un,039;BTLF039;,stunduration[Loop2])
call SetUnitUserData(un,CusVal)
endif
set bj_groupCountUnits = 0
call ForGroup(G[Loop2],function CountUnits)
if bj_groupCountUnits == 0 and Dt[Loop2] == 0 then
call DestroyGroup(G[Loop2])
set I2 = 0
endif
endif
set u = null
endfunction
private function Flying_Init takes nothing returns nothing
local real xx
local real yy
local effect e
local unit u
set u = GetEnumUnit()
set xx = GetUnitX(u)
set yy = GetUnitY(u)
set e = AddSpecialEffect(hitsfx[Loop],xx,yy)
call DestroyEffect(e)
call UnitAddAbility(u,STORM_CROW)
call UnitRemoveAbility(u,STORM_CROW)
call PauseUnit(u,true)
call SetUnitPathing(u,false)
call GroupAddUnit(G[Loop],u)
set e = null
set u = null
endfunction
private function Call_Flying takes nothing returns nothing
loop
exitwhen Loop2 > Instances
call ForGroup(G[Loop2],function Flying)
set I[Loop2] = I2
set Loop2 = Loop2 + 1
endloop
set Loop2 = 1
endfunction
//=====================================================================
private function Stun takes nothing returns nothing
local real xx
local real yy
set xx = GetUnitX(GetEnumUnit())
set yy = GetUnitY(GetEnumUnit())
call SetUnitPosition(GetEnumUnit(),xx,yy)
endfunction
private function Call_Stun takes nothing returns nothing
local integer i = 1
loop
exitwhen i > CusVal
call ForGroup(StunG<i>,function Stun)
set i = i + 1
endloop
endfunction
private function Remove_Stun takes nothing returns nothing
call GroupRemoveUnit(StunG[GetUnitUserData(GetTriggerUnit())],ImpaledUnit[GetUnitUserData(GetTriggerUnit())])
call DestroyEffect(stuneffect[GetUnitUserData(GetTriggerUnit())])
endfunction
//=====================================================================
private function SpawnSpikes takes nothing returns nothing
local Data d = 0
local group g = CreateGroup()
local real dx = 0.00
local real dy = 0.00
loop
exitwhen Loop > Instances
if Dt[Loop] != 0 then
set d = Dt[Loop]
set caster[Loop] = d.caster
set airtime[Loop] = d.airtime
set damage[Loop] = d.damage
set stunduration[Loop] = d.stunduration
set height[Loop] = d.height
set hitsfx[Loop] = d.hitsfx
set stunsfx[Loop] = d.stunsfx
set attpoint[Loop] = d.attpoint
set in[Loop] = in[Loop] + 1
set x[Loop] = d.px + (SPACE * in[Loop]) * d.cos
set y[Loop] = d.py + (SPACE * in[Loop]) * d.sin
set d.sfx = AddSpecialEffect(d.spikesfx,x[Loop],y[Loop])
call DestroyEffect(d.sfx)
call GroupEnumUnitsInRange(g,x[Loop],y[Loop],d.area,Condition(function Check_Units))
call ForGroup(g,function Flying_Init)
call DestroyGroup(g)
set g = CreateGroup()
set dx = d.px - x[Loop]
set dy = d.py - y[Loop]
if d.based then
if SquareRoot(dx * dx + dy * dy) >= d.castrange then
if d.moveunit then
call SetUnitX(d.caster,d.px + (SPACE * in[Loop]) * d.cos)
call SetUnitY(d.caster,d.py + (SPACE * in[Loop]) * d.sin)
endif
if d.hideunit then
call ShowUnit(d.caster,true)
if GetLocalPlayer() == GetOwningPlayer(d.caster) then
call SelectUnit(d.caster, true)
endif
endif
set x[Loop] = 0
set y[Loop] = 0
set in[Loop] = 0
set Dt[Loop] = 0
set bj_groupCountUnits = 0
call ForGroup(G[Loop],function CountUnits)
if bj_groupCountUnits == 0 and Dt[Loop] == 0 then
call DestroyGroup(G[Loop])
set I2 = 0
endif
endif
elseif SquareRoot(dx * dx + dy * dy) >= d.range then
if d.moveunit then
call SetUnitX(d.caster,d.px + (SPACE * in[Loop]) * d.cos)
call SetUnitY(d.caster,d.py + (SPACE * in[Loop]) * d.sin)
endif
if d.hideunit then
call ShowUnit(d.caster,true)
if GetLocalPlayer() == GetOwningPlayer(d.caster) then
call SelectUnit(d.caster, true)
endif
endif
set x[Loop] = 0
set y[Loop] = 0
set in[Loop] = 0
set Dt[Loop] = 0
set bj_groupCountUnits = 0
call ForGroup(G[Loop],function CountUnits)
if bj_groupCountUnits == 0 and Dt[Loop] == 0 then
call DestroyGroup(G[Loop])
set I2 = 0
endif
endif
endif
set Loop = Loop + 1
endloop
set Loop = 1
set g = null
endfunction
//=====================================================================
function IsUnitImpaled takes unit u returns boolean
local integer i = 1
loop
exitwhen i > Instances
if IsUnitInGroup(u,G<i>) then
return true
endif
set i = i + 1
endloop
return false
endfunction
//=====================================================================
public function StartEx takes unit Caster, real X, real Y, real CastX, real CastY, real Range, real Damage, real StunDuration, real Angle, real Area, real Height, real AirTime, string SpikeSfx, string HitSfx, string StunSfx, string AttPoint, boolean RangeBased, boolean MoveUnit, boolean HideUnit returns boolean
local Data d = 0
if RangeBased == false then
if Area < 0.00 or StunDuration < 0.00 or Range <= 0.00 then
debug call BJDebugMsg("Error: Invalid input in IMPS_Start()")
return false
endif
elseif Area < 0.00 or StunDuration < 0.00 then
debug call BJDebugMsg("Error: Invalid input in IMPS_Start()")
return false
endif
set d = Data.create(Caster,X,Y,CastX,CastY,Range,Damage,StunDuration,(Angle * 0.01745328),Area,Height,AirTime,SpikeSfx,HitSfx,StunSfx,AttPoint,RangeBased,MoveUnit,HideUnit)
set Instances = Instances + 1
set G[Instances] = CreateGroup()
call TimerStart(Timer,SPIKE_INTERVAL,true,function SpawnSpikes)
call TimerStart(Timer2,INTERVAL,true,function Call_Flying)
call TimerStart(Timer3,0.03,true,function Call_Stun)
set Dt[Instances] = d
if HideUnit then
call ShowUnit(Caster,false)
endif
return true
endfunction
//====================================================================
public function StartLocEx takes unit Caster, location Point, location CastPoint, real Range, real Damage, real StunDuration, real Angle, real Area, real Height, real AirTime, string SpikeSfx, string HitSfx, string StunSfx, string AttPoint, boolean RangeBased, boolean MoveUnit, boolean HideUnit returns nothing
call IMPS_StartEx(Caster,GetLocationX(Point),GetLocationY(Point),GetLocationX(CastPoint),GetLocationY(CastPoint),Range,Damage,StunDuration,Angle,Area,Height,AirTime,SpikeSfx,HitSfx,StunSfx,AttPoint,RangeBased,MoveUnit,HideUnit)
endfunction
public function StartLoc takes unit Caster, location Point, real Range, real Damage, real StunDuration, real Angle returns nothing
call IMPS_StartEx(Caster,GetLocationX(Point),GetLocationY(Point),0.00,0.00,Range,Damage,StunDuration,Angle,AREA,HEIGHT,AIRTIME,SPIKE_SFX,HIT_SFX,STUN_SFX,ATT_POINT,false,false,false)
endfunction
public function Start takes unit Caster, real X, real Y, real Range, real Damage, real StunDuration, real Angle returns nothing
call IMPS_StartEx(Caster,X,Y,0.00,0.00,Range,Damage,StunDuration,Angle,AREA,HEIGHT,AIRTIME,SPIKE_SFX,HIT_SFX,STUN_SFX,ATT_POINT,false,false,false)
endfunction
//====================================================================
private function InitTrig takes nothing returns nothing
local trigger t = CreateTrigger()
local integer index = 0
loop
call TriggerRegisterPlayerUnitEvent(t,Player(index),EVENT_PLAYER_UNIT_DEATH,null)
set index = index + 1
exitwhen index == bj_MAX_PLAYER_SLOTS
endloop
call TriggerAddCondition(t,Condition(function Check_Dummy))
call TriggerAddAction(t,function Remove_Stun)
endfunction
endlibrary</i></i>
This is my first time coding in vJass. It was little hard to understand at first, but later it became easy and I made this Impale System and I want to know what you think about my first vJass code.
Updates:
Version 1.30: 2 new functions and more configurables
Version 1.20: Some fixes, removed location usage and removed UnitUserData Usage
Version 1.10: Some fixes, code improvement and new function
Version 1.00: Initial Release
Version 1.20: Some fixes, removed location usage and removed UnitUserData Usage
Version 1.10: Some fixes, code improvement and new function
Version 1.00: Initial Release