Spell Sharl

Jesus4Lyf

Good Idea™
Reaction score
397
Welcome to Sharl.

sharlip9.jpg


The screenshot is good but it really doesn't do the spell a justice. You can't see the fire effect in the screenshots for some reason.

Made with vJASS.
Fully MUI, but due to trigger intensiveness and displaying masses of units at once per instance, I don't recommend multiple instances in general.
Requires Key Timers 2, and vJASS.

He sees the nether rip... Who can stop the fire? The claws?

Channeling spell. End effect is a delayed, chanelling DoT with a hook effect.

Fully interruptable. If the caster is paused, stunned, killed, issued an order or the target is killed, the spell stops, and the Sharl strands fall to the ground, ends first, as the magic wanes.

The caster summons 3 strands of twisting nether energies to grab it's target, and pull it to the caster. As the target is pulled back, the tips of the nether strands constantly explode and wear down, dealing damage over time to the target.

Sounds simple? Let me explain something about this spell... It takes everything into account. If the caster is stunned AT ANY POINT, the unit is instantly released and the strands fall to the ground and disappear. If the unit moves, the sharl strands will curve to catch it, and pull it back along the path the strands took to get there. Furthermore, it fully adjusts for all angles (I'd love to see a flying unit cast this), all units, even terrain heights. If interrupted while dealing damage, the full damage is not dealt, the unit is released, and the strands fall to the ground. Also, for each unit created as part of the nether things, sparks fly out on it's creation. I kinda went relatively all out on the detail. Doesn't lag much either. :cool:

Furthermore, it's JESP.

This spell took a hell of a lot of work to make. Once again, please credit me (Jesus4Lyf) if used.

Here's the code, but looking at it probably won't do you much good. The 3d handling engine I designed is probably unreadable to most, if not all.
JASS:
scope Sharl
	// Spell made by Jesus4Lyf.
	// Be sure to update the AbilCode and DummyType.
	// Feel free to play with the constant globals, if you know what you're doing kinda.
	// I believe this follows JESP. <img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" class="smilie smilie--sprite smilie--sprite8" alt=":D" title="Big Grin    :D" loading="lazy" data-shortname=":D" />
	private function Damage takes integer level returns real
		return level*150.+50.
	endfunction
	globals
		private constant integer AbilCode=&#039;A000&#039;
		private constant integer DummyType=&#039;u000&#039;
		private constant string VortexModel=&quot;Abilities\\Weapons\\SpiritOfVengeanceMissile\\SpiritOfVengeanceMissile.mdl&quot;
		private constant real VortexScale=0.9
		private constant string LiningModel=&quot;Abilities\\Weapons\\PhoenixMissile\\Phoenix_Missile.mdl&quot;
		private constant real LiningScale=0.7
		private constant string UnwrapModel=&quot;Abilities\\Weapons\\FireBallMissile\\FireBallMissile.mdl&quot;
		private constant real UnwrapScale=0.4
		private constant string SparkModel=&quot;Abilities\\Spells\\Human\\ManaFlare\\ManaFlareTarget.mdl&quot;
		private constant real SparkScale=0.55
		private constant integer SparkQuantity=3
		private constant real StepRate=18
		private constant real SparkMaxSpeed=10
		
		private location ZCheck=Location(0,0)
	endglobals
	
	scope Spark
		private struct spark
			unit u
			effect e
			real xv
			real yv
			real zv
		endstruct
		private function SparkGravity takes nothing returns boolean
			local spark d=GetTriggerExecCount(GetTriggeringTrigger())
			call SetUnitX(d.u,GetUnitX(d.u)+d.xv)
			call SetUnitY(d.u,GetUnitY(d.u)+d.yv)
			call SetUnitFlyHeight(d.u,GetUnitFlyHeight(d.u)+d.zv,0)
			set d.zv=d.zv-3
			if GetUnitFlyHeight(d.u)&lt;2 then
				call DestroyEffect(d.e)
				set d.e=null
				call KillUnit(d.u)
				call RemoveUnit(d.u)
				set d.u=null
				call d.destroy()
				return true
			endif
			return false
		endfunction
		public function At takes real x, real y, real z returns nothing
			local spark d
			local integer i=SparkQuantity
			loop
				exitwhen i==0
				set i=i-1
				set d=spark.create()
				set d.xv=GetRandomReal(-SparkMaxSpeed,SparkMaxSpeed)
				set d.yv=GetRandomReal(-SparkMaxSpeed,SparkMaxSpeed)
				set d.zv=GetRandomReal(-SparkMaxSpeed,SparkMaxSpeed)
				set d.u=CreateUnit(Player(15),DummyType,x,y,bj_DEGTORAD*Atan2(d.yv,d.xv))
				call SetUnitFlyHeight(d.u,z,0)
				set d.e=AddSpecialEffectTarget(SparkModel,d.u,&quot;origin&quot;)
				call SetUnitScale(d.u,SparkScale,SparkScale,SparkScale)
				call KT_Add(function SparkGravity, d, 0.04)
			endloop
		endfunction
	endscope
	
	scope Death
		globals
			private trigger remsfx=null
			private unit sfxu
			private real sfxt
		endglobals
		private function RemSFXActions takes nothing returns nothing
			local unit u=sfxu
			call TriggerSleepAction(.3)
			call RemoveUnit(u)
			set u=null
		endfunction
		public function Effect takes string model, real scale, real x, real y, real z returns nothing
			if remsfx==null then
				set remsfx=CreateTrigger()
				call TriggerAddAction(remsfx,function RemSFXActions)
			endif
			set sfxu=CreateUnit(Player(15),DummyType,x,y,GetRandomReal(0,360))
			call SetUnitFlyHeight(sfxu,z,0)
			call SetUnitScale(sfxu,scale,scale,scale)
			call DestroyEffect(AddSpecialEffectTarget(model,sfxu,&quot;origin&quot;))
			call KillUnit(sfxu)
			call TriggerExecute(remsfx)
		endfunction
	endscope
	
	private struct sharl
		unit target
		unit caster
		effect array partae[300]
		effect array partbe[300]
		effect array partce[300]
		unit array parta[300]
		unit array partb[300]
		unit array partc[300]
		real array partx[300]
		real array party[300]
		real array partz[300]
		effect array sfxe[50]
		unit array sfxu[50]
		integer speed=0
		real r
		integer tick=0
		integer order
		real dmg
	endstruct
	
	private function GetZ takes real x, real y returns real
		call MoveLocation(ZCheck,x,y)
		return GetLocationZ(ZCheck)
	endfunction
	
	//! textmacro SharlFailClear takes CHAR
		if d.part$CHAR$<i>!=null then
			call DestroyEffect(d.part$CHAR$e<i>)
			set d.part$CHAR$e<i>=null
			call KillUnit(d.part$CHAR$<i>)
			call RemoveUnit(d.part$CHAR$<i>)
			set d.part$CHAR$<i>=null
		endif
	//! endtextmacro
	//! textmacro SharlFailPos takes CHAR
		if d.part$CHAR$[d.tick-i]!=null then
			set r=GetUnitFlyHeight(d.part$CHAR$[d.tick-i])-s
			if r&lt;0 then
				call DestroyEffect(d.part$CHAR$e[d.tick-i])
				set d.part$CHAR$e[d.tick-i]=null
				call KillUnit(d.part$CHAR$[d.tick-i])
				call RemoveUnit(d.part$CHAR$[d.tick-i])
				set d.part$CHAR$[d.tick-i]=null
			else
				call SetUnitFlyHeight(d.part$CHAR$[d.tick-i],r,0)
			endif
		endif
	//! endtextmacro
	private function Fail takes nothing returns boolean
		local sharl d=GetTriggerExecCount(GetTriggeringTrigger())
		local integer i=d.speed+1
		local real s=0.
		local real r
		set d.speed=i
		if d.tick-i&lt;1 then
			set s=s-d.tick+i+1
			if d.parta[1]==d.partb[1] and d.partc[1]==null then
				set d.caster=null
				set d.target=null
				set i=d.tick
				loop
					//! runtextmacro SharlFailClear(&quot;a&quot;)
					//! runtextmacro SharlFailClear(&quot;b&quot;)
					//! runtextmacro SharlFailClear(&quot;c&quot;)
					set i=i-1
					exitwhen i==0
				endloop
				call d.destroy()
				return true
			endif
			set i=d.tick
		endif
		loop
			set i=i-1
			set s=s+1.
			//! runtextmacro SharlFailPos(&quot;a&quot;)
			//! runtextmacro SharlFailPos(&quot;b&quot;)
			//! runtextmacro SharlFailPos(&quot;c&quot;)
			exitwhen i==0
		endloop
		return false
	endfunction
	
	//! textmacro SharlPullUnwrap takes CHAR
		if d.part$CHAR$[d.tick]!=null then
			call Death_Effect(UnwrapModel,UnwrapScale,GetUnitX(d.part$CHAR$[d.tick]),GetUnitY(d.part$CHAR$[d.tick]),GetUnitFlyHeight(d.part$CHAR$[d.tick]))
			call DestroyEffect(d.part$CHAR$e[d.tick])
			set d.part$CHAR$e[d.tick]=null
			call KillUnit(d.part$CHAR$[d.tick])
			call RemoveUnit(d.part$CHAR$[d.tick])
			set d.part$CHAR$[d.tick]=null
		endif
	//! endtextmacro
	private function Pull takes nothing returns boolean
		local sharl d=GetTriggerExecCount(GetTriggeringTrigger())
		local integer i=1
		// This area is coded oddly because it used to use a speed variable.
		// I have left it this way in case I wish to use it again.
		// Shouldn&#039;t hurt. <img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" class="smilie smilie--sprite smilie--sprite1" alt=":)" title="Smile    :)" loading="lazy" data-shortname=":)" />
		set i=d.tick-i
		if GetUnitCurrentOrder(d.caster)!=d.order or IsUnitPaused(d.caster) or GetWidgetLife(d.caster)&lt;0.405 or GetWidgetLife(d.target)&lt;0.405 or GetUnitAbilityLevel(d.caster,&#039;BSTN&#039;)+GetUnitAbilityLevel(d.caster,&#039;BPSE&#039;)+GetUnitAbilityLevel(d.caster,&#039;BNsi&#039;)&gt;0 then
			if GetUnitCurrentOrder(d.caster)==d.order then
				call IssueImmediateOrder(d.caster,&quot;stop&quot;)
			endif
			call KT_Add(function Fail, d, 0.04)
			return true
		endif
		if i&lt;0 then
			set i=0
		endif
		loop
			exitwhen d.tick==i
			//! runtextmacro SharlPullUnwrap(&quot;a&quot;)
			//! runtextmacro SharlPullUnwrap(&quot;b&quot;)
			//! runtextmacro SharlPullUnwrap(&quot;c&quot;)
			call UnitDamageTarget(d.caster,d.target,d.dmg,true,false,ATTACK_TYPE_NORMAL,DAMAGE_TYPE_NORMAL,WEAPON_TYPE_WHOKNOWS)
			set d.tick=d.tick-1
		endloop
		call SetUnitX(d.target,d.partx<i>)
		call SetUnitY(d.target,d.party<i>)
		call SetUnitFlyHeight(d.target,d.partz<i>-GetZ(d.partx<i>,d.party<i>),0)
		if d.tick==0 then
			call SetUnitFlyHeight(d.target,GetUnitDefaultFlyHeight(d.target),70)
			call IssueImmediateOrder(d.caster,&quot;stop&quot;)
			set d.target=null
			set d.caster=null
			call d.destroy()
			return true
		endif
		return false
	endfunction
	
	//! textmacro SharlGrowPos takes CHAR
		set z=Sin(d.r)*40
		set y=Cos(d.r)*40
		set d.r=d.r+120*bj_DEGTORAD
		set z=Cos(v)*z
		set x=-Sin(v)*y
		set w=x
		set x=-Sin(f)*y+Cos(f)*x+d.partx[d.tick-1]
		set y=Sin(f)*w+Cos(f)*y+d.party[d.tick-1]
		set z=z+d.partz[d.tick-1]-GetZ(x,y)+45
		call Spark_At(x,y,z)
		if z&gt;-1 then
			set d.part$CHAR$[d.tick]=CreateUnit(Player(15),DummyType,x,y,f*bj_RADTODEG)
			call SetUnitFlyHeight(d.part$CHAR$[d.tick],z,0)
			set d.part$CHAR$e[d.tick]=AddSpecialEffectTarget(VortexModel,d.part$CHAR$[d.tick],&quot;origin&quot;)
			call SetUnitScale(d.part$CHAR$[d.tick],VortexScale,VortexScale,VortexScale)
		else
			set d.part$CHAR$[d.tick]=null
			set d.part$CHAR$e[d.tick]=null
		endif
	//! endtextmacro
	private function Grow takes nothing returns boolean
		local sharl d=GetTriggerExecCount(GetTriggeringTrigger())
		local real x=GetUnitX(d.target)-d.partx[d.tick]
		local real y=GetUnitY(d.target)-d.party[d.tick]
		local real z=GetUnitFlyHeight(d.target)+GetZ(GetUnitX(d.target),GetUnitY(d.target))-d.partz[d.tick]
		local real f=x*x+y*y
		local real m=SquareRoot(f)
		local real v=Atan2(z,m)
		local real w
		set m=StepRate/SquareRoot(f+z*z)
		set f=Atan2(y,x)
		if d.tick==0 then
			set d.r=82*bj_DEGTORAD
			set d.sfxu[1]=CreateUnit(Player(15),DummyType,d.partx[0],d.party[0],GetUnitFacing(d.caster))
			set d.sfxe[1]=AddSpecialEffectTarget(LiningModel,d.sfxu[1],&quot;origin&quot;)
			set d.sfxu[2]=CreateUnit(Player(15),DummyType,d.partx[0],d.party[0],GetUnitFacing(d.caster))
			set d.sfxe[2]=AddSpecialEffectTarget(LiningModel,d.sfxu[2],&quot;origin&quot;)
			set d.sfxu[3]=CreateUnit(Player(15),DummyType,d.partx[0],d.party[0],GetUnitFacing(d.caster))
			set d.sfxe[3]=AddSpecialEffectTarget(LiningModel,d.sfxu[3],&quot;origin&quot;)
		endif
		set d.tick=d.tick+1
		set d.r=d.r+8*bj_DEGTORAD
		set d.partx[d.tick]=d.partx[d.tick-1]+x*m
		set d.party[d.tick]=d.party[d.tick-1]+y*m
		set d.partz[d.tick]=d.partz[d.tick-1]+z*m
		
		//! runtextmacro SharlGrowPos(&quot;a&quot;)
		call SetUnitFacing(d.sfxu[1],f*bj_RADTODEG)
		call SetUnitX(d.sfxu[1],x)
		call SetUnitY(d.sfxu[1],y)
		call SetUnitFlyHeight(d.sfxu[1],z,0)
		//! runtextmacro SharlGrowPos(&quot;b&quot;)
		call SetUnitFacing(d.sfxu[2],f*bj_RADTODEG)
		call SetUnitX(d.sfxu[2],x)
		call SetUnitY(d.sfxu[2],y)
		call SetUnitFlyHeight(d.sfxu[2],z,0)
		//! runtextmacro SharlGrowPos(&quot;c&quot;)
		call SetUnitFacing(d.sfxu[3],f*bj_RADTODEG)
		call SetUnitX(d.sfxu[3],x)
		call SetUnitY(d.sfxu[3],y)
		call SetUnitFlyHeight(d.sfxu[3],z,0)
		
		if GetUnitCurrentOrder(d.caster)!=d.order or IsUnitPaused(d.caster) or GetWidgetLife(d.caster)&lt;0.405 or GetWidgetLife(d.target)&lt;0.405 or GetUnitAbilityLevel(d.caster,&#039;BSTN&#039;)+GetUnitAbilityLevel(d.caster,&#039;BPSE&#039;)+GetUnitAbilityLevel(d.caster,&#039;BNsi&#039;)&gt;0 then
			call DestroyEffect(d.sfxe[1])
			set d.sfxe[1]=null
			call DestroyEffect(d.sfxe[2])
			set d.sfxe[2]=null
			call DestroyEffect(d.sfxe[3])
			set d.sfxe[3]=null
			call KillUnit(d.sfxu[1])
			call RemoveUnit(d.sfxu[1])
			set d.sfxu[1]=null
			call KillUnit(d.sfxu[2])
			call RemoveUnit(d.sfxu[2])
			set d.sfxu[2]=null
			call KillUnit(d.sfxu[3])
			call RemoveUnit(d.sfxu[3])
			set d.sfxu[3]=null
			if GetUnitCurrentOrder(d.caster)==d.order then
				call IssueImmediateOrder(d.caster,&quot;stop&quot;)
			endif
			call KT_Add(function Fail, d, 0.04)
			return true
		endif
		
		if StepRate/m&lt;StepRate*3 then
			call UnitAddAbility(d.target,&#039;Amrf&#039;)
			call UnitRemoveAbility(d.target,&#039;Amrf&#039;)
			call DestroyEffect(d.sfxe[1])
			set d.sfxe[1]=null
			call DestroyEffect(d.sfxe[2])
			set d.sfxe[2]=null
			call DestroyEffect(d.sfxe[3])
			set d.sfxe[3]=null
			call KillUnit(d.sfxu[1])
			call RemoveUnit(d.sfxu[1])
			set d.sfxu[1]=null
			call KillUnit(d.sfxu[2])
			call RemoveUnit(d.sfxu[2])
			set d.sfxu[2]=null
			call KillUnit(d.sfxu[3])
			call RemoveUnit(d.sfxu[3])
			set d.sfxu[3]=null
			set d.dmg=Damage(GetUnitAbilityLevel(d.caster,AbilCode))/I2R(d.tick)
			call KT_Add(function Pull, d, 0.07)
			return true
		endif
		return false
	endfunction
	
	function Trig_Sharl_Conditions takes nothing returns boolean
		return GetSpellAbilityId()==AbilCode
	endfunction
	
	function Trig_Sharl_Actions takes nothing returns nothing
		local sharl d=sharl.create()
		set d.caster=GetSpellAbilityUnit()
		set d.target=GetSpellTargetUnit()
		set d.partx[0]=GetUnitX(d.caster)
		set d.party[0]=GetUnitY(d.caster)
		set d.partz[0]=GetZ(d.partx[0],d.party[0])+GetUnitFlyHeight(d.caster)
		set d.order=GetUnitCurrentOrder(d.caster)
		call KT_Add(function Grow, d, 0.1)
	endfunction
endscope

//===========================================================================
function InitTrig_Sharl takes nothing returns nothing
	set gg_trg_Sharl=CreateTrigger()
	call TriggerRegisterAnyUnitEventBJ(gg_trg_Sharl,EVENT_PLAYER_UNIT_SPELL_EFFECT)
	call TriggerAddCondition(gg_trg_Sharl,Condition(function Trig_Sharl_Conditions))
	call TriggerAddAction(gg_trg_Sharl,function Trig_Sharl_Actions)
endfunction</i></i></i></i></i></i></i></i></i></i></i>


Hope this gets as good a reaction as Sandman, if not better due to being JESP and hence easy to import. :D

Oh, and the dummy unit is the standard Jesus4Lyf dummy unit. If you use any of my other spells with it, you don't need to import it again (Sandman, future spells).

Edit: Updated it to use new KT2 versions (now 1.3). Why bother? Because it's a -lot- faster! It now multi-instances very nicely, and doesn't lag. Download was at 120 views.
 

Attachments

  • Spell - Sharl.w3x
    56.9 KB · Views: 694

Jesus4Lyf

Good Idea™
Reaction score
397
Yep, thanks for posting that vid. It gives a much better idea of the spell! :D

There, updated the tooltip.

Sure, the spell idea is relatively simple, but... The eye candy was HARD to make. It took a lot of effort and thought to make. Also, if the spell bends to hit a unit, the unit is pulled back along the path the spell took. So it isn't just eye candy. :D

In a real map, this is a tactical spell... The closer you get to the target, the faster the damage is dealt, and the less chance of a spell interrupt. You can cast it at range but chances are you'll get stunned or something, or not deal all the damage due to being interrupted. :)
 
O

OneEight7eve

Guest
your so good at making spells. there more than what you c with them.

Off topic : did u make a Real Life
 

Jesus4Lyf

Good Idea™
Reaction score
397
> your so good at making spells. there more than what you c with them.
Thanks. :D ^_^

>Off topic : did u make a Real Life
Why, yes I did! That was about 4 years ago when i started out. I made Jesus4Lyf's Real Life, helped in LoaP (original, not some ripoff) and was credited in Real Life for Moron's. I was famous as a mapper about 4 years ago for that, I'm suprised it's still remembered. Wasn't a good map by today's standards, but it was for it's time.
But that's off topic. So... ;) :D
 

vypur85

Hibernate
Reaction score
803
The spell is cool :).

Just a suggestion, when the unit is captured, it is not paused. So if it tries to escape, then the movement is quite jerky, which is weird. So, why not pause the captured unit? Not sure, maybe it's just me.

+R

Edit: Also, when the target reaches the hero, the hero jerks away slightly. Is this due to the collision or intentionally done? I cant read JASS so i really dont know :p.
 

Cohadar

master of fugue
Reaction score
209
Great spell.
I just lol'ed because one of the tentacles is starting to grow from heroes dick. :D
 

Cohadar

master of fugue
Reaction score
209
Btw you don't need 3 tentacles,
2 tentacles would actually look better (due to less confusion)

And if you could make them grow from heroes hands that would be totally wicked.
 

Jesus4Lyf

Good Idea™
Reaction score
397
Hm. Originally I was going to do 2... If anyone wants 2 instead, I'll mod it for them personally, but personally I like 3, and I'm not the keenest on redoing that code (not that it'd be hard because I used textmacros). :D

About making it grow from their hands... I believe theres no way to detect where a hero's hands are. But once again if someone wanted to use this in their map, and wanted it to grow from the hands of a specific model, I'd mod it for them probably...
 

Andrewgosu

The Silent Pandaren Helper
Reaction score
715
The spell itself is great, though, I would not use it in my maps, because it is quite lag-friendly.
 

Trollvottel

never aging title
Reaction score
262
i think you should pause the targeted unit for a while, the hippogryphs always tried to walk away and that looked weird.
the rest of the spell is very nice, except the caster sometimes changes his place when a pulled unit comes too near.
+rep
 
General chit-chat
Help Users
  • No one is chatting at the moment.

      The Helper Discord

      Members online

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top