| 01-31-2009, 12:16 AM | #1 |
Disintegrate spellmap (With bonus spells) Included: Disintegrate (FocusMagic) Like a lightning effect with collision Swap (SwapArrow) FireOrb (ArcaneArrow) These last two are basically just xecollider samples. Yeah these are just the hero contest spells, but packed in their own spell map without Mc!'s art, so I can update them with bug fixes. Disintegrate and FireOrb actually got updated and got more features than the ones in the hero contest submission... These things don't really look that well without Mc!'s art though. Disintegrate was a fun spell to code, and yes it was inspired by a d3 video... Edit: updated to fix bug with FireOrb FocusMagic:library FocusMagic initializer init requires xebasic, xedamage, xefx, Table //************************************************************************************** //* FocusMagic //* ------------ //* Author: Vexorian. //* Requirements: //* - xebasic, xedamage, xefx //* - The Table library //* - A triggerer ability, with a point target. An example would be //* the FocusMagic ability you can find in this map's object editor. //* //* Notes: - The base ability's lightning effect field determines the lightning to use. //* - The base ability's area effect field determines the effect to use at the //* end of the laser. //* - The base ability's target effect field determines the target effect. //* //************************************************************************************* //================================================================================== // Config: // // globals private constant integer SPELL_ID ='A00B' //The triggerer spell id. private constant integer MAX_SPELL_LEVELS = 3 private constant real LASER_HEIGHT = 80.0 private constant real END_FX_HEIGHT = 80.0 private constant real END_FX_SCALE = 2.0 private constant real LASER_START_OFFSET = 20.0 private constant string ATTACH_POINT_TARGET = "chest" private constant boolean PSEUDO_EXPLODE = true //This adds a cute FX on unit death endglobals //// // Some config functions: // - // radius: the collision size of the beam (See bellow for an explanation:) // damagePerSecond: dps? // manaDrainPerSecond: Every second, the casting unit will lose a total of manaDrainPerSecond // requiredMana: The spell is stopped once the unit reaches less than requiredMana. // private function radius takes real level returns real return level*0.0 + 35.0 endfunction private function damagePerSecond takes real level returns real return 45.0 + level*22.5 endfunction private function manaDrainPerSecond takes real level returns real return 3.0 + level*0.0 endfunction private function requiredMana takes real level returns real return 25.0 + level*0.0 endfunction private function configDamage takes integer level, xedamage d returns nothing //Read xedamage's documentation to know how to configure this. //does not support damagetrees // set d.damageAllies = true //True if you want it to hurt allies. set d.damageSelf = false set d.atype = ATTACK_TYPE_NORMAL // NORMAL (spell) attacktype set d.exception = UNIT_TYPE_FLYING // Don't hit fliers set d.dtype = DAMAGE_TYPE_LIGHTNING // LIGHTNING (magical) damage, call d.factor(UNIT_TYPE_STRUCTURE, 0.33) // does 1/3 damage to buildings. endfunction //Some tweaks that are more advanced: globals private real TIMER_PERIOD = 0.1 //The timer's period of time, seems 0.1 is fine private real TARGET_FX_PERIOD = 0.25 //Every TARGET_FX_PERIOD a special effect is played on currently affected targets. private real BEGINNING_DURATION = 1.0 //This is an initial time in which requiredMana is ignored. endglobals // // The spell is based on a shape that's like the integral of a circle: // ,---------------------. , // ( ) | radius // `---------------------' ` // |<->| Units which collision circles intersect with this figure are affected by the spell. // ^radius // //=============================================================================== // The code. // // // In my opinion, this is the best spell I made, well, just because I am a geometry fan (when it works correctly) // Anyway, as you can see, I added collision to a lightning effect, this laser beam will consider unit collision // sizes and all. Not to mention the custom art... // // I consider the lightning effect to be a line segment, for each unit in the vecinity, I get the closest point // inside this segment, for that I did a derivative to find a formula that you can see in unitInRectEnum, // once we have this point... just check if the unit is in range to that point, and done! The rest are just // smoke and mirrors, that's right, eye candy got complicated to make in this one, it is silly I needed GetLocationZ // to make the lightning effect look well. Notice that since the return value of GetLocationZ is not used for things // that affect the gameplay, it shouldn't desync if there are local terrain deformations. // // And yes, I am using a HandleTable for the end spell effect, just remember, that this is one of those cases in // which this is perfectly safe, yes, IT IS. Kidnapping custom values was not necessary. No, it wasn't. // (The stop event will never fire for a unit if the start event has not fired for it yet) and stop fires // when you remove the unit) // // globals private group enumgroup private rect enumrect private xedamage array damageconf private HandleTable unitsInstance private location zloc endglobals private function GetZ takes real x, real y returns real call MoveLocation(zloc,x,y) return GetLocationZ(zloc) endfunction private struct instance unit u integer level real x2 real y2 lightning li boolean end = false real acum = 0.0 real elapsed=0.0 xefx fx static instance current static method unitInRectEnum takes nothing returns boolean local instance this=.current local unit u=this.u local unit t=GetFilterUnit() local real x1=GetUnitX(u) local real y1=GetUnitY(u) local real x2=this.x2 local real y2=this.y2 local real a=x2-x1 local real b=y2-y1 local real cx local real cy local real s=(a*( GetUnitX(t) -x1)+b*( GetUnitY(t)-y1))/(a*a+b*b) local real fc if(s<0) then set s=0.0 elseif(s>1) then set s=1.0 endif set cx=x1+s*a set cy=y1+s*b if IsUnitInRangeXY(t, cx, cy, radius(this.level) ) then if damageconf[this.level].damageTarget(u,t, damagePerSecond(this.level)*TIMER_PERIOD ) then if(PSEUDO_EXPLODE and (GetWidgetLife(t)<=0.405) ) then //call ShowUnit(t,false) call DestroyEffect( AddSpellEffectTargetById(GetUnitTypeId(t), EFFECT_TYPE_SPECIAL, t, "origin" ) ) endif if(this.acum == 0.0) then call DestroyEffect( AddSpellEffectTargetById(SPELL_ID,EFFECT_TYPE_TARGET, t, "origin" ) ) endif endif endif set u=null set t=null return false endmethod method process takes nothing returns boolean local real a local real x1 local real y1 local real x2 local real y2 if(.end) then return false endif set a=GetUnitState(this.u, UNIT_STATE_MANA) if (a < requiredMana(this.level) ) and (this.elapsed>=BEGINNING_DURATION) then call PauseUnit(this.u, true) call IssueImmediateOrder(this.u, "stop") call PauseUnit(this.u, false) endif call SetUnitState(this.u, UNIT_STATE_MANA, a- this.level * manaDrainPerSecond(this.level)* TIMER_PERIOD ) set x1=GetUnitX(this.u) set y1=GetUnitY(this.u) set x2=this.x2 set y2=this.y2 set a=Atan2(y2-y1,x2-x1) set x1=x1+LASER_START_OFFSET*Cos(a) set y1=y1+LASER_START_OFFSET*Sin(a) set a=XE_MAX_COLLISION_SIZE + radius(this.level) call MoveLightningEx(this.li, false, x1,y1,GetZ(x1,y1)+LASER_HEIGHT, x2,y2,GetZ(x2,y2)+LASER_HEIGHT) //set the rect: (painful stuff, yes) if(x1 < x2) then if( y1 < y2) then call SetRect(enumrect, x1-a,y1-a,x2+a,y2+a) else call SetRect(enumrect, x1-a,y2-a,x2+a,y1+a) endif else if( y1 < y2) then call SetRect(enumrect, x2-a,y1-a,x1+a,y2+a) else call SetRect(enumrect, x2-a,y2-a,x1+a,y1+a) endif endif set .current = this call GroupEnumUnitsInRect(enumgroup, enumrect, Condition(function instance.unitInRectEnum) ) set .acum=.acum+TIMER_PERIOD set .elapsed=.elapsed + TIMER_PERIOD if(.acum>= TARGET_FX_PERIOD) then set .acum=0.0 endif return true endmethod method onDestroy takes nothing returns nothing call DestroyLightning(this.li) call unitsInstance.flush(this.u) call this.fx.destroy() endmethod endstruct globals private instance array V private integer N=0 private timer T endglobals private function control takes nothing returns nothing local integer i=N-1 loop exitwhen (i<0) if ( not V[i].process()) then call V[i].destroy() set N=N-1 set V[i]=V[N] endif set i=i-1 endloop if(N==0) then call PauseTimer(T) endif endfunction private function onSpellEffect takes nothing returns nothing local location loc =GetSpellTargetLoc() local unit u=GetTriggerUnit() local instance ins = instance.create() if (N==0) then call TimerStart(T, TIMER_PERIOD, true, function control ) endif set u:unitsInstance = integer(ins) set V[N]=ins set N=N+1 set ins.u=u set ins.x2=GetLocationX(loc) set ins.y2=GetLocationY(loc) set ins.level = GetUnitAbilityLevel(u, SPELL_ID) set ins.fx=xefx.create(ins.x2, ins.y2, 0) set ins.fx.z=END_FX_HEIGHT set ins.fx.scale = END_FX_SCALE set ins.fx.fxpath=GetAbilityEffectById(SPELL_ID, EFFECT_TYPE_AREA_EFFECT, 0) set ins.li = AddLightningEx( GetAbilityEffectById(SPELL_ID, EFFECT_TYPE_LIGHTNING, 0) ,false, GetUnitX(u), GetUnitY(u), GetZ(GetUnitX(u),GetUnitY(u))+LASER_HEIGHT, ins.x2, ins.y2, GetZ(ins.x2,ins.y2)+LASER_HEIGHT ) call RemoveLocation(loc) set u=null set loc=null endfunction private function onSpellEnd takes nothing returns nothing //I love this: set instance(GetTriggerUnit():unitsInstance).end= true endfunction private function spellIdMatch takes nothing returns boolean return (SPELL_ID==GetSpellAbilityId()) endfunction //===================================================================================================== // Init stuff: // private function init takes nothing returns nothing local trigger t=CreateTrigger() local integer i local integer j set zloc=Location(0,0) set enumrect = Rect(0,0,0,0) set unitsInstance = HandleTable.create() set enumgroup=CreateGroup() set T=CreateTimer() call TriggerRegisterAnyUnitEventBJ(t,EVENT_PLAYER_UNIT_SPELL_EFFECT) call TriggerAddCondition(t, Condition(function spellIdMatch)) call TriggerAddAction(t, function onSpellEffect) set t=CreateTrigger() call TriggerRegisterAnyUnitEventBJ(t,EVENT_PLAYER_UNIT_SPELL_ENDCAST) call TriggerAddCondition(t, Condition(function spellIdMatch)) call TriggerAddAction(t, function onSpellEnd) set i=1 loop exitwhen (i>MAX_SPELL_LEVELS) set damageconf[i]=xedamage.create() call configDamage(i, damageconf[i] ) set i=i+1 endloop set t=null endfunction endlibrary |
| 01-31-2009, 12:22 AM | #2 |
Source Code? |
| 01-31-2009, 12:25 AM | #3 |
There's a program called world editor which comes with warcraft 3 that can allow you to see the code. |
| 01-31-2009, 12:38 AM | #4 |
Where can I download this program at? Disintegrate is really cool. |
| 01-31-2009, 01:31 AM | #5 |
ima take a look at this and compare it to what i did when i made it for our D3 map - see if i can get any pointers (MC!s are does make it looks distinctly better, I only wish he could have made the lightning effect less lightningy and more lasery/lavay/more like a dense,viscous liquid) |
| 01-31-2009, 01:39 AM | #6 |
But wasn't the video's one more laser like? I don't have enough memory to remember correctly. |
| 01-31-2009, 02:20 AM | #7 |
it was, the only thing i can think to compare it to would be the wand beams from the HP movies - like i said, as opposed to lightning the beam looks more like a dense, viscous liquid MC!s looks much better then the WC3 FoD lightning, but i think there was still room for improvement (mind you this is just from screenys ive seen, i have yet to test it in game **what exactly does this: JASS:AddSpellEffectTargetById(GetUnitTypeId(t), EFFECT_TYPE_SPECIAL, t, "origin" ) do??? and how does it create a "cute FX on unit death" |
| 01-31-2009, 03:00 AM | #8 |
It references the effect field within " Art - Special " in the object editor page of the base ability. |
| 01-31-2009, 03:13 AM | #9 | |
Quote:
well, when you explode units the special art field of the unit is played. This does that. |
| 01-31-2009, 07:29 AM | #10 |
I must say I'd prefer emjlr3's version. Here you can't swing it around like in the gameplay trailer, you have to channel a new spell in order to hit other units. You should consider such feature, it would be an improvement. Cool fire orb, though. |
| 01-31-2009, 10:38 AM | #11 |
Nice spells.. but i got thousands of double frees when fire orb missiles hit any enemies ... JASS:
method onUnitHit takes unit hitunit returns nothing
if damageconf[.level].damageTarget(.source, hitunit, secondMissileDamage(.level) ) then
call .destroy() // call .terminate() ...
endif
endmethod
|
| 01-31-2009, 11:31 AM | #12 | |
That's so lame, I should really make my build scripts use --debug by default unless it is the release... It is inspired by the trailer but I do not intend to reproduce it 100% , I actually like the red lightning stuff and I already made swinging before when making lightning inferno and the other freezing spell, it is cool for demonstrations but it doesn't have a huge gameplay value due to wc3's controls, besides of overcomplicating the code... Quote:
|
| 01-31-2009, 12:22 PM | #13 | |
Quote:
Yeah, you should, really. That would protect you from those cheap errors for real. |
| 01-31-2009, 02:54 PM | #14 |
That thing was updated anyway. |
| 02-01-2009, 06:03 PM | #15 |
Anyways, this looks good by me. Approvizzled. |
