| 03-05-2008, 06:44 AM | #1 | |
The Effect System is a system that allows you to create complex effects easily and attach them to a certain units. Version: 1.5 I'm back!! First let me say I'm sorry that it took me so long to update this map due to the fact that I'm lazy... The system has faced so many bugs and problem when I'm implying vex's Magic Timer on it, nothing good happens so instead of using one, I wrote myself a more simple timer system and it runs well after several testing and now it is ready for approval! Download : Here Requires : - Basic Jass knowledge. (No vJass knowledge is required, no worries) - Caster System (14.3 and above, credits to Vexorian) - (1.5 update) Now it comes with a mini Caster System library that contains the Caster System functions that only used in the Effect System. (For more information please refer to the ReadMe in the map) Features : - Easily create certain periodic effect, circular effect, spiral effect, and many more, depends on how you manipulate the effect functions. - Flexibility: manipulate the parameters of the shapes created in many ways. - Uses vJass, 1 timer runs all the effect. - Timed effects, automatically cleans up destroyed effect, preventing any possible leaks. - Self-clean up for all effects, these effects will destroy/clean itself up once the attached target dies. (Note that effects added by using AddSpecialEffect(...) will still leaks when the unit it attached to are removed/decays unless you do DestroyEffect() on it) - Detailed explanation of the function usage. - Certain useful examples. Mini Caster System (With the functions that used only in the Effect System) JASS:library CasterSystem initializer init globals //Dummy unit type rawcode, for this one I'm using the dummy used in the Caster System private constant integer DummyUnitId = 'e000' // Medivh's Crow form ability, don't need to change this rawcode unless you modified that ability private constant integer FlyingHeightHack = 'Amrf' //==============================================================================// // Private globals required by the dummy recycling system, you don't need to // // change anything from here and below. // //==============================================================================// private constant real cs_RectLimitOffSet = 50.0 private real cs_game_maxx private real cs_game_maxy private real cs_game_miny private real cs_game_minx private group CasterGroup private unit CurrentEffect endglobals function CS_MoveUnit takes unit u, real x, real y returns boolean local boolean b=true if (x<cs_game_minx) then set b=false elseif (x>cs_game_maxx) then set b=false elseif (y>cs_game_maxy) then set b=false elseif (y<cs_game_miny) then set b=false endif if (b) then call SetUnitX(u, x) call SetUnitY(u, y) endif return b endfunction function GetACaster takes nothing returns unit set CurrentEffect = FirstOfGroup(CasterGroup) if CurrentEffect == null then set CurrentEffect=CreateUnit(Player(15),DummyUnitId,0,0,0) call UnitAddAbility(CurrentEffect,'Aloc') call UnitAddAbility(CurrentEffect,FlyingHeightHack) call UnitRemoveAbility(CurrentEffect,FlyingHeightHack) else call GroupRemoveUnit(CasterGroup,CurrentEffect) endif return CurrentEffect endfunction function RecycleCaster takes unit u returns nothing if GetWidgetLife(u)>=0.405 and u!=null then call ResetUnitLookAt(u) call SetUnitVertexColor(u,255,255,255,255) call SetUnitScale(u,1,1,1) call SetUnitTimeScale(u,1) call SetUnitFlyHeight(u,0,0) call SetUnitTurnSpeed(u,0.6) call GroupAddUnit(CasterGroup,u) endif endfunction private function init takes nothing returns nothing set CasterGroup = CreateGroup() set cs_game_maxx=GetRectMaxX(bj_mapInitialPlayableArea)-cs_RectLimitOffSet set cs_game_maxy=GetRectMaxY(bj_mapInitialPlayableArea)-cs_RectLimitOffSet set cs_game_miny=GetRectMinY(bj_mapInitialPlayableArea)+cs_RectLimitOffSet set cs_game_minx=GetRectMinX(bj_mapInitialPlayableArea)+cs_RectLimitOffSet endfunction endlibrary Effect System Code JASS:library EffectSystem requires CasterSystem //*************************************************************************** //* * //* Effect System 1.5 * //* ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ * //* Requires: * //* ¯¯¯¯¯¯¯¯¯ * //* - The CSCache, CSSafety, CasterSystem. * //* - Visit [url]http://wc3campaigns.net/vexorian[/url] for more information for the * //* CasterSystem. * //* * //*************************************************************************** //=========================================================================== //Effect System configuration constants //=========================================================================== globals //Maxinum number of effects for circular effect and spiral effect, if you //create an effect with a number > MaxEffectNumber will cause an error when //saving, keep this value low for more instance of circular effect available. private constant integer MaxEffectNumber = 18 //maximum effects will be 18. //The periodic timeout for all the effects in the system, (lower value is //lag friendly, but effects looks better, higher value reduces lag in //game, but the effects look crappy), it is set to 0.035 by default, I don't //encourage any changes of this value, unless you know what you are doing. private constant real EffectTimerCycle = 0.035 endglobals //*************************************************************************** //* * //* Don't touch anything below unless you know what you are doing. * //* * //*************************************************************************** //=========================================================================== //Effect system core timer //=========================================================================== interface ExpireMethod method onExpire takes nothing returns nothing defaults nothing endinterface public struct EffectTimer extends ExpireMethod static timer T static EffectTimer head static EffectTimer tail EffectTimer next EffectTimer last static method onInit takes nothing returns nothing set EffectTimer.T = CreateTimer() set EffectTimer.head = -1 set EffectTimer.tail = -1 endmethod static method create takes nothing returns EffectTimer local EffectTimer this = EffectTimer.allocate() set this.last = EffectTimer.tail set this.next = -1 if EffectTimer.head==-1 then set EffectTimer.head = this call TimerStart(EffectTimer.T,EffectTimerCycle,false,function EffectTimer.timerloop) endif if EffectTimer.tail!=-1 then set EffectTimer.tail.next = this endif set EffectTimer.tail = this return this endmethod method onDestroy takes nothing returns nothing if this.next==-1 and this.last==-1 then set EffectTimer.head=-1 set EffectTimer.tail=-1 elseif this.next==-1 then set EffectTimer.tail=this.last set this.last.next = -1 elseif this.last==-1 then set EffectTimer.head=this.next set this.next.last = -1 else set this.last.next = this.next set this.next.last = this.last endif endmethod static method timerloop takes nothing returns nothing local EffectTimer et = EffectTimer.head if et!=-1 then loop call et.onExpire() set et=et.next exitwhen et==-1 endloop call TimerStart(EffectTimer.T,EffectTimerCycle,false,function EffectTimer.timerloop) endif endmethod endstruct //=========================================================================== //Mathematics Calculations //=========================================================================== globals private location L = Location(0,0) endglobals function ES_GetUnitZ takes unit u returns real call MoveLocation(L,GetUnitX(u),GetUnitY(u)) return GetLocationZ(L)+GetUnitFlyHeight(u) endfunction //=========================================================================== //Instant Effects //=========================================================================== function CreateInstantEffect takes string model, real x, real y returns nothing call DestroyEffect(AddSpecialEffect(model,x,y)) endfunction //! define CreateInstantEffect(model,x,y) DestroyEffect(AddSpecialEffect(model,x,y)) function CreateInstantEffectTarget takes string model, widget target, string where returns nothing call DestroyEffect(AddSpecialEffectTarget(model,target,where)) endfunction //! define CreateInstantEffectTarget(model,target,where) DestroyEffect(AddSpecialEffectTarget(model,target,where)) //=========================================================================== //Delayed Effects //=========================================================================== private struct DelayedEffectData extends EffectTimer effect e unit target = null real life boolean point = false method onDestroy takes nothing returns nothing call DestroyEffect(.e) if .point then call RecycleCaster(.target) endif endmethod method onExpire takes nothing returns nothing if .target==null or GetWidgetLife(.target)<=0.405 then set .life = 0 endif if .life>0 then set .life=.life-EffectTimerCycle elseif .life !=-1 then call .destroy() endif endmethod endstruct function DestroyDelayedEffect takes DelayedEffectData dat returns nothing set dat.life=0 endfunction function CreateDelayedEffectTarget takes string model, unit target, string where, real timeout returns DelayedEffectData local DelayedEffectData dat = DelayedEffectData.create() set dat.target = target set dat.e = AddSpecialEffectTarget(model,target,where) if timeout>0 then set dat.life=timeout else set dat.life=-1 endif return dat endfunction function CreateDelayedEffect takes string model, real x, real y, real timeout returns DelayedEffectData local DelayedEffectData dat = DelayedEffectData.create() set dat.target = GetACaster() call CS_MoveUnit(dat.target,x,y) set dat.e = AddSpecialEffectTarget(model,dat.target,"origin") set dat.point = true if timeout>0 then set dat.life=timeout else set dat.life=-1 endif return dat endfunction //=========================================================================== //Periodic Effects - creates an effect every t seconds //=========================================================================== private struct PeriodicEffectData extends EffectTimer unit target string model string where effect e = null real life real plife real rlife = 0 //remaining periodic time boolean point = false boolean instant method onDestroy takes nothing returns nothing if .e != null then call DestroyEffect(.e) endif if .point then call RecycleCaster(.target) endif endmethod method onExpire takes nothing returns nothing if .target==null or GetWidgetLife(.target)<=0.405 then call .destroy() return elseif .life<=0 and .life!=-1 then call .destroy() return else if .life!=-1 then set .life=.life-EffectTimerCycle endif set .rlife=.rlife-EffectTimerCycle endif if .rlife <= 0 then if .instant then call DestroyEffect(AddSpecialEffectTarget(.model,.target,.where)) else call DestroyEffect(.e) set .e = AddSpecialEffectTarget(.model,.target,.where) endif set .rlife=.plife endif endmethod endstruct function DestroyPeriodicEffect takes PeriodicEffectData dat returns nothing set dat.life=0 endfunction function CreatePeriodicEffectTarget takes string model, unit target, string where, real periodic, real timeout, boolean instant returns PeriodicEffectData local PeriodicEffectData dat = PeriodicEffectData.create() set dat.target = target set dat.model = model set dat.where = where set dat.plife = periodic set dat.instant = instant if timeout > 0 then set dat.life = timeout else set dat.life = -1 endif return dat endfunction function CreatePeriodicEffect takes string model, real x, real y, real periodic, real timeout, boolean instant returns PeriodicEffectData local PeriodicEffectData dat set bj_lastCreatedUnit = GetACaster() call CS_MoveUnit(bj_lastCreatedUnit,x,y) set dat = CreatePeriodicEffectTarget(model,bj_lastCreatedUnit,"origin",periodic,timeout,instant) set dat.point = true return dat endfunction //=========================================================================== //Circular Effects //=========================================================================== private struct CircData extends EffectTimer unit target = null real life = -1 boolean point = false real r integer n real a_spd //angular spd unit array u[MaxEffectNumber] real array a[MaxEffectNumber] effect array e[MaxEffectNumber] PeriodicEffectData array pe[MaxEffectNumber] boolean have_pe = false real l_spd //linear spd (spiral) real l //current radius (spiral only) real sp_r //spiral radius (spiral only) integer sp_life = -1 boolean have_sp = false lightning array c_lig[MaxEffectNumber] lightning array s_lig[MaxEffectNumber] real lig_h method onDestroy takes nothing returns nothing loop set .n=.n-1 exitwhen .n<0 if .e[0]!=null then call DestroyEffect(.e[.n]) endif if .c_lig[0]!=null then call DestroyLightning(.c_lig[.n]) endif if .s_lig[0]!=null then call DestroyLightning(.s_lig[.n]) endif if .have_pe then set .pe[.n].life =0 endif call RecycleCaster(.u[.n]) endloop endmethod method onExpire takes nothing returns nothing local integer n=.n local real x local real y if .target==null or GetWidgetLife(.target)<=0.405 then call .destroy() elseif .life<=0 and .life!=-1 then call .destroy() elseif .have_sp and .sp_life<=0 and .sp_life!=-1 then call .destroy() else loop set n=n-1 exitwhen n<0 set .a[n] = .a[n]+.a_spd if .a[n]>6.28318 then set .a[n]=.a[n]-6.28318 elseif .a[n]<0 then set .a[n]=.a[n]+6.28318 endif set x=GetUnitX(.target)+.l*Cos(.a[n]) set y=GetUnitY(.target)+.l*Sin(.a[n]) call CS_MoveUnit(.u[n],x,y) if .c_lig[0]!=null then call MoveLightningEx(.c_lig[n],true,GetUnitX(.target),GetUnitY(.target),.lig_h,x,y,ES_GetUnitZ(.u[n])) endif if .s_lig[0]!=null then if n==0 then call MoveLightningEx(.s_lig[n],true,GetUnitX(.u[.n-1]),GetUnitY(.u[.n-1]),ES_GetUnitZ(.u[.n-1]),x,y,ES_GetUnitZ(.u[n])) else call MoveLightningEx(.s_lig[n],true,GetUnitX(.u[n-1]),GetUnitY(.u[n-1]),ES_GetUnitZ(.u[n-1]),x,y,ES_GetUnitZ(.u[n])) endif if .a_spd > 0 then call SetUnitFacingTimed(.u[n],(.a[n]*57.2958)+90,EffectTimerCycle) else call SetUnitFacingTimed(.u[n],(.a[n]*57.2958)-90,EffectTimerCycle) endif endif endloop if .have_sp then if (.sp_r>.r and .l>.sp_r) or (.sp_r<.r and .l<.sp_r) then if .sp_life!=-1 then set .sp_life=.sp_life-1 endif set .l = .r else set .l = .l+.l_spd endif endif if .life!=-1 then set .life=.life-EffectTimerCycle endif endif endmethod endstruct function DestroyCircularEffect takes CircData dat returns nothing set dat.life=0 endfunction function AddCircularSpiralEffect takes CircData dat, real radius, real linearspd, integer repeats returns nothing if dat.r == radius then debug call BJDebugMsg("Effect System Error: Can't create spiral that having same radius with the circular effect") return else set dat.have_sp = true set dat.sp_r = radius if dat.r > radius then //closing set dat.l_spd = -linearspd*EffectTimerCycle else set dat.l_spd = linearspd*EffectTimerCycle endif endif if repeats <= 0 then set dat.sp_life = -1 else set dat.sp_life = repeats endif endfunction function AddCircularCenterLightning takes CircData dat, string model, real r, real g, real b, real height returns nothing local real x = GetUnitX(dat.target) local real y = GetUnitY(dat.target) local integer n = dat.n set dat.lig_h = height loop set n=n-1 exitwhen n<0 set dat.c_lig[n]=AddLightningEx(model,true,x,y,height,GetUnitX(dat.u[n]),GetUnitY(dat.u[n]),ES_GetUnitZ(dat.u[n])) call SetLightningColor(dat.c_lig[n],r,g,b,1) endloop endfunction function AddCircularSideLightning takes CircData dat, string model, real r, real g, real b returns nothing local integer n = dat.n if n==1 then debug call BJDebugMsg("Effect System Error: Can't create side lighting with only one circular effect member") return endif set dat.s_lig[0]=AddLightningEx(model,true,GetUnitX(dat.u[dat.n-1]),GetUnitY(dat.u[dat.n-1]),ES_GetUnitZ(dat.u[dat.n-1]),GetUnitX(dat.u[0]),GetUnitY(dat.u[0]), ES_GetUnitZ(dat.u[0])) call SetLightningColor(dat.s_lig[0],r,g,b,1) loop set n=n-1 exitwhen n<1 set dat.s_lig[n]=AddLightningEx(model,true,GetUnitX(dat.u[n-1]),GetUnitY(dat.u[n-1]),ES_GetUnitZ(dat.u[n-1]),GetUnitX(dat.u[n]),GetUnitY(dat.u[n]), ES_GetUnitZ(dat.u[n])) call SetLightningColor(dat.s_lig[n],r,g,b,1) endloop endfunction function AddCircularPeriodicEffect takes CircData dat, string model, real periodic, boolean instant returns nothing local integer n = dat.n set dat.have_pe = true loop set n=n-1 exitwhen n<0 set dat.pe[n] = CreatePeriodicEffectTarget(model,dat.u[n],"origin",periodic,0,instant) endloop endfunction function ModifyCircularEffect takes CircData dat, integer red, integer green, integer blue, real scale, real height returns nothing local integer n = dat.n loop set n=n-1 exitwhen n<0 call SetUnitVertexColor(dat.u[n],red,green,blue,255) call SetUnitScale(dat.u[n],scale,scale,scale) call SetUnitFlyHeight(dat.u[n],height,0) endloop endfunction function CreateCircularEffectTarget takes string model, unit target, integer number, real radius, real speed, real time returns CircData local CircData dat = CircData.create() local real x = GetUnitX(target) local real y = GetUnitY(target) local integer n = 0 local real a set dat.target = target set dat.n = number if radius<10 then set radius = 10 endif set dat.r = radius set dat.l = radius if number>0 then //Will really screw up the whole thing if I don't do this set a = 6.2832/number else debug call BJDebugMsg("Effect System Error: Circular effect member is <= 0") return 0 endif if speed != 0 then set dat.a_spd = Atan2(speed*EffectTimerCycle,radius) else set dat.a_spd = 0 endif if time > 0 then set dat.life = time endif set dat.e[0]=null set dat.s_lig[0]=null set dat.c_lig[0]=null loop set dat.u[n] = GetACaster() set dat.a[n] = a*n call CS_MoveUnit(dat.u[n],x+radius*Cos(dat.a[n]),y+radius*Sin(dat.a[n])) call SetUnitFacing(dat.u[n],dat.a[n]) if model!=null and model!="" then set dat.e[n] = AddSpecialEffectTarget(model,dat.u[n],"origin") endif set n=n+1 exitwhen n>=number endloop return dat endfunction //=========================================================================== //Lightning effects //=========================================================================== private struct DelayedLightningData extends EffectTimer lightning e boolean bind = false unit from = null unit to = null real life real anow = 1 real frate = 0 method onDestroy takes nothing returns nothing call DestroyLightning(.e) endmethod method onExpire takes nothing returns nothing if .life<=0 and .life!=-1 then call .destroy() else if .frate>0 then set .anow = .anow-.frate call SetLightningColor(.e,GetLightningColorR(.e),GetLightningColorG(.e),GetLightningColorB(.e),.anow) endif if .from!=null and GetWidgetLife(.from)>0.405 and .to!=null and GetWidgetLife(.to)>0.405 then call MoveLightningEx(.e,true,GetUnitX(.from),GetUnitY(.from),ES_GetUnitZ(.from),GetUnitX(.to),GetUnitY(.to),ES_GetUnitZ(.to)) if .life!=-1 then set .life=.life-EffectTimerCycle endif else call .destroy() endif endif endmethod endstruct function DestroyDelayedLightning takes DelayedLightningData dat returns nothing set dat.life=0 endfunction function ModifyLightning takes DelayedLightningData dat, real red, real green, real blue, unit a, unit b returns lightning if a!=null and b!=null then if a==b then debug call BJDebugMsg("Effect System Error: Can't create lightning effect on self.") return null else set dat.bind = true set dat.from = a set dat.to = b endif endif call MoveLightningEx(dat.e,true,GetUnitX(a),GetUnitY(a),ES_GetUnitZ(a),GetUnitX(b),GetUnitY(b),ES_GetUnitZ(b)) call SetLightningColor(dat.e,red,green,blue,1) return dat.e endfunction function FadeOutLightning takes DelayedLightningData dat, real timeout returns nothing set dat.life = timeout set dat.frate = timeout*EffectTimerCycle endfunction function CreateDelayedLightning takes string model, real x1, real y1, real z1, real x2, real y2, real z2, real timeout returns DelayedLightningData local DelayedLightningData dat = DelayedLightningData.create() set dat.e = AddLightningEx(model,true,x1,y1,z1,x2,y2,z2) if timeout>0 then set dat.life=timeout else set dat.life=-1 endif return dat endfunction endlibrary History: Version 1.0 - First version of the system with the basic effects. (Instant effects, periodic effect, circular effect) Version 1.1 - Bug fix, added delayed effect. Version 1.2 - Optimization and improvement, added lightning effect. Version 1.4 - More internal code optimization, some minor changes in lightning effect. Version 1.5 - Caster System independent now (with the mini CasterSystemLibrary), added fading lightning effect, sample update.
Bonus : - My JESP spell that created for Spell Making Session #8 : Hollow Void, it requires the effect system, have a look. - Hollow Illusion, some randomly made illusion spell, fully utilize the usage of the Effect System :) - Sky Bomber, another JESP spell created for Spell Making Session #10 Credits: Vexorian - for the caster system and JASSHelper. blu_da_noob - for the suggestions and the field for improvements. moyack - for the suggestion on CasterSystem-independent and other feedbacks. |
| 03-05-2008, 07:14 AM | #2 |
some advice, if you post code in your post you will probably get it reviewed faster, i've noticed mods are very lazy |
| 03-05-2008, 12:38 PM | #3 | |
Quote:
But yeah, code in the first post please. :) |
| 03-05-2008, 04:49 PM | #4 |
Okie, just added, but the code is quite long so... :) open at your own risk~ |
| 03-06-2008, 05:43 AM | #5 | |
Quote:
|
| 03-07-2008, 12:23 PM | #6 |
~___~ hmmmm any comments? Other than the mod being lazy or whatever... |
| 03-07-2008, 12:25 PM | #7 |
Chill, dude, it's not even the weekend yet. Your system has more than 100 lines in it, I can't just read it in passing. Christ. :/ |
| 03-07-2008, 12:30 PM | #8 |
Hey!! I have destined my weekend for a review, please be patient!!! |
| 03-07-2008, 12:45 PM | #9 |
eiks, sorry ><! cus posted the topic for few days and can't see some feedback around so thought the people were dreaming off lol! sorry yea |
| 03-10-2008, 03:01 AM | #10 |
I've been so busy with real life that I've been unable to give a full review. But in general, according with the things I just saw, there are some stuff that I feel it should be "shorter" to define (I'll explain this later). Can you help me by point me out where do you use Caster System??... in which parts of your system please?? I have the feeling that this system can be optimized much more. I'll give more reviews tomorrow. |
| 03-10-2008, 03:49 AM | #11 |
hmph mainly is in the GetACaster() and RecycleCaster() part where I don't want my map to create tons of dummy handle (well just imagine one from effect sys and one for caster sys) around and lagging the map, however i could release a sub-version that don't require the CasterSystem... |
| 03-10-2008, 07:49 PM | #12 |
If your system uses a few times caster system, then you should try to add your own dummy recycler (Which is now easy with a simple struct) I did this is 10 minutes: I'll do one just for fun... when I get home. |
| 03-11-2008, 01:41 PM | #13 |
well as i said up there i wanted to make the 2 system share the dummy recycler to save memory, anyway i'll make one caster system-independent version in the next version :) |
| 03-12-2008, 01:44 AM | #14 |
I did this, I haven't tested yet, but I'm pretty sure it works, can you do me the favor to test it?? JASS:library DummyRecycler // Dummy recycler made very quickly, no guarantee!!! by moyack globals private constant integer DummyID = 'u000' //Dummy ID rawcode endglobals struct Dummy unit d = CreateUnit(Player(15), DummyID, 0,0,0) integer abil integer order boolean instant // used to remove the unit the amov ability, allowing to cast any ability without facing the target. static method create takes integer Abil, string DummyOrder, real x, real y returns Dummy local Dummy D = Dummy.allocate() set D.abil = Abil set D.order = AbilityId(DummyOrder) set D.instant = GetUnitAbilityLevel(.d, 'Amov') > 0 call UnitAddAbility(D.d, Abil) call UnitAddAbility(D.d, 'Aloc') //Add locust call SetUnitX(D.d, x) call SetUnitY(D.d, y) returns D endmethod method move takes real x, real y returns nothing call SetUnitX(.d, x) call SetUnitY(.d, y) endmethod method movetocaster takes unit caster returns nothing call .move(GetUnitX(caster), GetUnitY(caster)) endmethod method instant takes boolean flag returns nothing // this function sets the instant feature... if flag and GetUnitAbilityLevel(.d, 'Amov') > 0 then call UnitRemoveAbility(.d, 'Amov') set .instant = true else call RemoveUnit(.d) set .d = CreateUnit(Player(15), DummyID, 0,0,0) set .instant = false endif endmethod method immediate takes nothing returns boolean return IssueImmediateOrderById(.d, order) endmethod method target takes widget w returns boolean return IssueTargetOrderById(.d, .order, w) endmethod method point takes real x, real y returns boolean return IssuePointOrderById(.d, .order, x, y) endmethod endstruct endlibrary More comments: - In the function ModifyLightning you return the lightning when in the input, you enter the struct data that contains the lightning variable, so it's unnecessary, please make this function returns nothing. - Please offer an alternate version that doesn't use the Caster system, because there are people who don't use this system. - One question: Can I create triggered lightning effects which target fly units?? if yes, can you add a triggered Finger of dead sample in your map?? I hope you can do this. In general very good stuff we have here. I'll await for the update. |
| 03-13-2008, 02:55 AM | #15 |
Alrite, just updated, with the alternate version that don't require Caster System, triggered Finger of Death. I returned the lightning in the modify lightning mainly is because the user can change the lightning position in their trigger for effect adjustment manually (or something like that) so as long as the user don't destroy the lightning it is harmless :) |
