Spell Spells - Simple Dash Spell

emjlr3

Change can be a good thing
Reaction score
395
Spell Making School: A Simple Dash Spell


Introduction:

The purpose of this tutorial is to teach people how to make a simple dash spell in JASS. This not only enables it to be very efficient, but also MUI, where in GUI this could be neither of the above.

That is, however, not the only thing you will learn. The dash spell is mainly used as an example, the tutorial should teach you some general things about JASS and spell making, which is more important.

This tutorial is NOT an introduction or starting course to JASS. It is highly recommended (more accurately, required) that you know the basics of JASS before you start on this. There are plenty of them around here, just take a look, and come back when you feel you are ready.

This is the first part of a series of tutorials covering different areas in spell-making that I plan to make - A so-called spell making school I am starting, per say.

All you need to follow this tutorial, is the WE some basic JASS knowledge, JASS Craft and the CScache system found and easily implemented from Vexorian’s caster system, found here . I use this, and recommend that you do the same. We could go through and make our own here, but why bother? When there is one available for us to work from.

Even though code can be restored, I don't recommend coding spells in the WE, because a small error is enough to make the program crash on saving, and nobody enjoys that.
{Parts taken and edited from Blade.dk’s tutorial here .}

Creating Our Spell:

Let us start by first creating a trigger in the GUI. This is a trick I often do to save myself time, as it takes me about 10 seconds to click a few buttons and convert to custom script, where as it would take me a few minutes to look up my rawcodes, and type it all up from scratch:

Code:
Dash
    Events
        Unit - A unit Starts the effect of an ability
    Conditions
        (Ability being cast) Equal to Dash
    Actions

Here we use starts the effect of an ability because it is more accurate. This event makes the trigger fire when the spell is cast, cool down starts and mana is taken. Therefore it is the ideal event in this case. A suggest not using “Begins Casting An Ability” because that runs before these things happens, and can be exploited. It can however be used to check for a special condition for an ability, and only let the ability cast if that condition is met, but that is neither here nor there. Ok now convert your GUI trigger to JASS:

Code:
function Trig_Dash_Conditions takes nothing returns boolean
    if ( not ( GetSpellAbilityId() == 'AUan' ) ) then
        return false
    endif
    return true
endfunction

function Trig_Dash_Actions takes nothing returns nothing
endfunction

//===========================================================================
function InitTrig_Dash takes nothing returns nothing
    set gg_trg_Dash = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( gg_trg_Dash, EVENT_PLAYER_UNIT_SPELL_EFFECT )
    call TriggerAddCondition( gg_trg_Dash, Condition( function Trig_Dash_Conditions ) )
    call TriggerAddAction( gg_trg_Dash, function Trig_Dash_Actions )
endfunction

Lets start by noting a few things about this. The ‘Auan’ denotes the ability being cast. Each ability in each map has a unique rawcode for it. The simplest way to find a spell's rawcode, is to select it in the object editor and press CTRL+D. The first four letters of the spell's name is the rawcode (case sensitive, must be put within single quotes) the next four letters (only appears on custom spells) is the rawcode of the spell it was based on.

The first thing you want to do with all your ability triggers is to simplify the initial condition. It seems a bit goofy does it not? If you read is carefully, basically what it is doing is checking if the ability is not equal to the one we want, and returning false, else returning true. Honestly, what is the point? So we change it:

Code:
function Trig_Dash_Conditions takes nothing returns boolean
    return GetSpellAbilityId() == 'AUan' 
endfunction

Now, all we are doing is returning the Boolean of our equation, whether the spell cast, GetSpellAbilityId(), is equal to the ability we want, ‘Auan’. If it returns true, our actions are ran, if it returns false, nothing happens.

We only plan to use one special effect model for the spell for now: The Blood Elf Spell Thief blood model.
The path of that model is: Objects\Spawnmodels\Human\HumanBlood\BloodElfSpellThiefBlood.mdl

When you want to use a path in JASS, you must first put it between quotes, as it is a string. You'll also have to replace every single backslash (\) with two backslashes instead (\\). Another trick to reduce first cast lag is to preload the effects that are going to be used in the spell. So in our init trig we add PreLoad native for the effect we are going to use, which is ran during the map init. It adds to load time, but reduces lag in game:

Code:
//===========================================================================
function InitTrig_Dash takes nothing returns nothing
    set gg_trg_Dash = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( gg_trg_Dash, EVENT_PLAYER_UNIT_SPELL_EFFECT )
    call TriggerAddCondition( gg_trg_Dash, Condition( function Trig_Dash_Conditions ) )
    call TriggerAddAction( gg_trg_Dash, function Trig_Dash_Actions )
    call Preload("Objects\\Spawnmodels\\Human\\HumanBlood\\BloodElfSpellThiefBlood.mdl")
endfunction

Alright now lets us beging the actual coding ! We first go to the actions function and store the basic locals we will be needing for the ability:

Code:
function Trig_Dash_Actions takes nothing returns nothing
    local unit u = GetTriggerUnit()
    local location l = GetSpellTargetLoc()
    local real x = GetUnitX(u)
    local real y = GetUnitY(u)
    local real xtarg = GetLocationX(l)
    local real ytarg = GetLocationY(l)
    local real ang = bj_RADTODEG * Atan2(ytarg – y, xtarg – x)
    local real dx = xtarg - x
    local real dy = ytarg - y
    local real dist = SquareRoot(dx * dx + dy * dy)    
    local trigger trig = CreateTrigger()    
    local string strig = GetAttachmentTable(trig)
    local timer t = CreateTimer()
    local string s = GetAttachmentTable(t)

We store the caster and the location of the target of the ability cast. I then like to get the x and y for that location, as well as that for the caster, since they will used used often in a bit, and use those, because I personally like using reals better then locations, as they are easier for use in natives and do not require any clean up. Next is the angle. In order to move a unit from its position to another position in a straight line, the angle between this points is required. This we use take a look at the function AngleBetweenPoints(). We take what this returns, which uses reals, and use that instead of a bj function, so we eliminate a function, and optimize our trigger.

The next step is to store the distance between the caster and the target. I like to do this because I like the unit to move to where he cast, instead of a fixed distance. This is better for in game strategy as well as realness. What we are going to do with this is to compare the casters position from where he started after every periodic dash movement to that of the total distance. Once they are within a range, then the movement is over. So just like with the angle, we take a look at the DistanceBetweenPoints() function and use what is in that by plugging in our stored reals for the caster position and target position.

We then create a trigger to do the damage with. Why another trigger you ask? Can’t we just damage units around the caster as he moves? Yes you can, however that is far less efficient, and can lead to targets being damaged many times on a single pass.

We next need to create a local for the string to get the attachment of our trigger, since we will be storing locals onto it, and use GetAttTable() to get it. If you are unfamiliar with this process, please refer to Daelin’s Advanaced JASS tutorial.

A timer is then created, and the same process used to set a string equal to the attachment table of the timer.

Now that our local are set, we can continue. The next step is to set up our trigger that will damage the units who come close to the caster as he dashes.

Code:
function Trig_ Dash_Actions takes nothing returns nothing
    local unit u = GetTriggerUnit()
    local location l = GetSpellTargetLoc()
    local real x = GetUnitX(u)
    local real y = GetUnitY(u)
    local real xtarg = GetLocationX(l)
    local real ytarg = GetLocationY(l)
    local real ang = bj_RADTODEG * Atan2(ytarg - y, xtarg - x)
    local real dx = xtarg - x
    local real dy = ytarg - y
    local real dist = SquareRoot(dx * dx + dy * dy) 
    local trigger trig = CreateTrigger()    
    local string strig = GetAttachmentTable(trig)
    local timer t = CreateTimer()
    local string s = GetAttachmentTable(t)
    
    call TriggerRegisterUnitInRange(trig,u,150,null)
    call TriggerAddCondition( trig, Condition( function Dash_Dam_Cond ) )
    call SetTableObject(strig,”ta”, TriggerAddAction( trig, function Dash_Dam ))
    call SetTableObject(strig,"u",u)

There are three parts to a basic trigger, the event, the conditions, and the actions. We will set them up in order. First the event, that of a unit coming within a range of our caster, so any units who come within 150 of the caster during the duration of the spell will have the conditions ran for them. The next is the condition function, which adds our condition function to the trigger. The next part is adding the triggeraction. I use this method to remove the triggeraction leak, by storing the trigger action to the strig string and creating it in 1 line, we can remove it at a later date, and save and extra line of code. The last part is that of storing the caster in the trigger, since there is no way to get the unit which the triggering unit came in range of ( that I know of).

Our next step will be that of creating our condition and actions function for the local damage trigger we created. A rule of thumb is that any function that is referred to in another function must be above the function it was referred to in. Therefore our condition and actions functions we added to our local trigger must be above the Trig_Bloody_Dash_Actions function in our trigger or we will get errors. So let is create them:

Code:
function Dash_Dam_Cond takes nothing returns boolean
    local string s = GetAttachmentTable(GetTriggeringTrigger())
    return IsUnitEnemy(GetFilterUnit(),GetOwningPlayer(GetTableUnit(s,"u")))==true and GetUnitState(GetFilterUnit(),UNIT_STATE_LIFE)>0 
endfunction

This is why we need the stored caster to this trigger, to find out if the triggering unit(the one that came in range) is an enemy of our caster. We get the attached table of our trigger, and return whether the filter unit is an enemy of the owner of our stored caster, u. I also check if the filter unit is alive with GetUnitState, since we do not want this to fire for dead units. Next is the actions:

Code:
function Dash_Dam takes nothing returns nothing
    local string s = GetAttachmentTable(GetTriggeringTrigger())
    local unit u = GetTableUnit(s,"u")
    local unit v = GetTriggerUnit()    
    local real dam = 5*GetHeroAgi(u,true)
    
    call UnitDamageTarget(u,v,dam,false,false,ATTACK_TYPE_NORMAL,DAMAGE_TYPE_NORMAL,null)
    call SetUnitState(u,UNIT_STATE_LIFE,GetUnitState(u,UNIT_STATE_LIFE)+(.25*dam))
    call DestroyEffect(AddSpecialEffectTarget("Objects\\Spawnmodels\\Human\\HumanBlood\\BloodElfSpellThiefBlood.mdl",v,"overhead"))
    
    set u = null
    set v = null    
endfunction

Again we start here by declaring our locals as any information we need. I also set the heroes agility*5 to a local real variable since that is the damage I will be doing. My function then proceeds to damage the target based on the dam real I stored, and add 25% of it back to our casters hp, as well as creating our preloaded effect on the target. Again I use all native functions to keep the code as optimized as possible. I set my local units u and v to null at the end to remove the unit leak.

Now our damage trigger is complete, so any enemy unit that is alive who comes in 150 range of our caster will take 5*the agility of the caster in damage and get an effect on them. The caster will also regain 25% of the damage done back to him.

Now we go back to our actions function, Trig_ Dash_Actions, to set up our periodic timer for the casters movement.

Code:
function Trig_ Dash_Actions takes nothing returns nothing
    local unit u = GetTriggerUnit()
    local location l = GetSpellTargetLoc()
    local real x = GetUnitX(u)
    local real y = GetUnitY(u)
    local real xtarg = GetLocationX(l)
    local real ytarg = GetLocationY(l)
    local real ang = bj_RADTODEG * Atan2(ytarg - y, xtarg - x)
    local real dx = xtarg - x
    local real dy = ytarg - y
    local real dist = SquareRoot(dx * dx + dy * dy) 
    local trigger trig = CreateTrigger()    
    local string strig = GetAttachmentTable(trig)
    local timer t = CreateTimer()
    local string s = GetAttachmentTable(t)
    
    call TriggerRegisterUnitInRange(trig,u,150,null)
    call TriggerAddCondition( trig, Condition( function Dash_Dam_Cond ) )
    call SetTableObject(strig,”ta”, TriggerAddAction( trig, function Dash_Dam ))
    call SetTableObject(strig,"u",u)     
    
    call SetTableReal(s,"ang",ang)
    call SetTableReal(s,"dist",dist)
    call SetTableReal(s,"moved",0)
    call SetTableObject(s,"u",u)
    call SetTableObject(s,"trig",trig)    
    call TimerStart(t,.03,true,function Dash_Effects)

As we did with the trigger earlier, we must store all needed values to our timer as well. We will need the target location reals, our angle, distance, and the caster. Two extra ones we store are the trigger we created, so we can remove its leaks when the movement is done, as well as a real named “moved”, which we will use as the total distance moved for the caster. This is what we will compare to the distance we found earlier to decide when our dash will be complete. I usually use .03 as my periodic timer speed, since it is still fast and will look smooth in game, but to slow to cause any lag problems.

Before we go onto our timer function, let us finish this one first:

Code:
function Trig_ Dash_Actions takes nothing returns nothing
    local unit u = GetTriggerUnit()
    local location l = GetSpellTargetLoc()
    local real x = GetUnitX(u)
    local real y = GetUnitY(u)
    local real xtarg = GetLocationX(l)
    local real ytarg = GetLocationY(l)
    local real ang = bj_RADTODEG * Atan2(ytarg - y, xtarg - x)
    local real dx = xtarg - x
    local real dy = ytarg - y
    local real dist = SquareRoot(dx * dx + dy * dy) 
    local trigger trig = CreateTrigger()    
    local string strig = GetAttachmentTable(trig)
    local timer t = CreateTimer()
    local string s = GetAttachmentTable(t)
    
    call TriggerRegisterUnitInRange(trig,u,150,null)
    call TriggerAddCondition( trig, Condition( function Dash_Dam_Cond ) )
    call SetTableObject(strig,”ta”, TriggerAddAction( trig, function Dash_Dam ))
    call SetTableObject(strig,"u",u)    
    
    call SetTableReal(s,"ang",ang)
    call SetTableReal(s,"dist",dist)
    call SetTableReal(s,"moved",0)
    call SetTableObject(s,"u",u)
    call SetTableObject(s,"trig",trig)    
    call TimerStart(t,.03,true,function Dash_Effects)
    
    call SetUnitTimeScalePercent(u, 400) 
    call SetUnitPathing(u,false)
    call SetUnitAnimationByIndex(u,1)
    
    set u = null
    call RemoveLocation(l)
    set l = null
    set trig = null    
endfunction

Three extra things I do before wrapping this function up is setting its timescapepercent, which is how fast the unit’s animations are. We want it to look like it is dashing, so why not make it look like it is running, by using a faster animation speed. I then set the caster to have no collision, and lastly so it’s animation index to that of its walk animation. This is a trick used to force units to play an animation even when they are being moved around. To check a units animation indexs, play them in game the same way, and use BJDebugMsg() to display what integer is being played, and you can then use the integer for the walk animation, or whatever other animation you need.

The last part of any function is to remove leaks. You should know enough about leaks and basic JASS functions to know what leaks are and how to remove them. I do that here, and so should you in all of your functions.

The last part we need to do is set up our periodic timer function to move our caster:

Code:
function Dash_Effects takes nothing returns nothing
    local timer t = GetExpiredTimer()
    local string s = GetAttachmentTable(t)
    local trigger trig
    local string strig
    local unit u = GetTableUnit(s,"u")
    local real ang = GetTableReal(s,"ang")
    local real dist = GetTableReal(s,"dist")
    local real moved = GetTableReal(s,"moved")

This is pretty self explanatory. If you do not understand what is going on here, either re-re-read a handle vars tutorial or the readme that came with the CScache system for a brush up. Two of the locals I created I did not set so anything. These will eventually refer to our local trigger created earlier, however there is no use setting them unless we are actually going to use them, as you will see it a bit.

The next part is probably the trickiest of the entire trigger, which is that of the actual movement. Many people are not really sure how to move units in a straight line, this is how:

Code:
function Dash_Effects takes nothing returns nothing
    local timer t = GetExpiredTimer()
    local string s = GetAttachmentTable(t)
    local trigger trig
    local string strig
    local unit u = GetTableUnit(s,"u")
    local real ang = GetTableReal(s,"ang")
    local real dist = GetTableReal(s,"dist")
    local real moved = GetTableReal(s,"moved")    
    
    call SetUnitPosition(u,GetUnitX(u) + 30 * Cos(ang * bj_DEGTORAD),GetUnitY(u) + 30 * Sin(ang * bj_DEGTORAD))
    call SetUnitAnimationByIndex(u,1)    
    set moved = moved+30

We are setting our units position to a polar projection of where it originally was. Take a look at the polar projection bj in JASS Craft:

Code:
function PolarProjectionBJ takes location source, real dist, real angle returns location
    local real x = GetLocationX(source) + dist * Cos(angle * bj_DEGTORAD)
    local real y = GetLocationY(source) + dist * Sin(angle * bj_DEGTORAD)
    return Location(x, y)
endfunction

If you take your units location, and set it to a positive distance at the angle we found earlier, it will move along a straight line from where it started towards the target, at the distance increment you choose.

We also set our units animation again to keep it going, and set our real moved to itself plus the distance we moved our caster, so that we keep track of however it has moved. The next step is a fork in the road, on way, the timer will keep going and the caster moved again, the other, everything will stop since the caster will be close to the destination:

Code:
function Dash_Effects takes nothing returns nothing
    local timer t = GetExpiredTimer()
    local string s = GetAttachmentTable(t)
    local trigger trig
    local string strig
    local unit u = GetTableUnit(s,"u")
    local real ang = GetTableReal(s,"ang")
    local real dist = GetTableReal(s,"dist")
    local real moved = GetTableReal(s,"moved")    
    
    call SetUnitPosition(u,GetUnitX(u) + 30 * Cos(ang * bj_DEGTORAD),GetUnitY(u) + 30 * Sin(ang * bj_DEGTORAD))
    call SetUnitAnimationByIndex(u,1)    
    set moved = moved+30
    
    if moved>=dist or GetUnitState(u,UNIT_STATE_LIFE)<=0 then
        set trig = GetTableTrigger(s,"trig")
        set strig = GetAttTable(trig)
        call TriggerRemoveAction(trig,GetTableTriggerAction(strig,"ta"))
        call ClearTable(strig)
        call DestroyTrigger(trig)
        set trig = null
        call SetUnitTimeScalePercent(u, 100)
        call SetUnitPathing(u,true) 
        call SetUnitAnimationByIndex(u,0)
        call ClearTable(s)
        call PauseTimer(t)
        call DestroyTimer(t)
    else
        call SetTableReal(s,"moved",moved)
    endif    
    
    set u = null
endfunction

Our local real moved, which has stored how far we have moved the caster, is then compared to the total distance we found earlier, if it is still less then it, we store our new move distance, and the timer continues, however is the total move distance is more then our distance found, we must stop the timer, set everything back to normal, and remove our leaks. I also check to make sure our caster is alive, because it would look silly to dash a dead unit, no?

So if we are at our destination, it is time to shut everything down. Now we set our trigger and strig string locals to the trigger we created and its attached table. Remove the action to take care of that leak, clear the table to take care of that one, and destroy our trigger to save some memory and take care of that leak. Here we also set trig=null, since it only needs to be set to null if it was set to something in the first place.

We then reset our unit to normal animation speed, give it back its pathing, and set its animation to stand, so it doesn’t keep running but just stand there (  ). The last part is removing our leaks with the timer, by clearing its table, pausing it and destroying it. It is important to pause the timer before you destroy it because it can sometimes bug if you do. Again we clean up our leaks at the end by setting our local unit variable to null, and this function is complete.

Another little thing to note, I never set timers I attach things to to null, it can cause bugs. Yes it leaks, but its better to have it always work, and have that small leak, then sometimes bug on you in a game.

Let us take a look at our final trigger:

Code:
function Trig_Dash_Conditions takes nothing returns boolean
    return GetSpellAbilityId() == 'A05M' 
endfunction

function Dash_Dam_Cond takes nothing returns boolean
    local string s = GetAttachmentTable(GetTriggeringTrigger())
    return IsUnitEnemy(GetFilterUnit(),GetOwningPlayer(GetTableUnit(s,"u")))==true and GetUnitState(GetFilterUnit(),UNIT_STATE_LIFE)>0 
endfunction

function Dash_Dam takes nothing returns nothing
    local string s = GetAttachmentTable(GetTriggeringTrigger())
    local unit u = GetTableUnit(s,"u")
    local unit v = GetTriggerUnit()
    local real agil = GetHeroAgi(u,true)
    local real dam = 5*agil
    
    call UnitDamageTarget(u,v,dam,false,false,ATTACK_TYPE_NORMAL,DAMAGE_TYPE_NORMAL,null)
    call SetUnitState(u,UNIT_STATE_LIFE,GetUnitState(u,UNIT_STATE_LIFE)+(.25*dam))
    call DestroyEffect(AddSpecialEffectTarget("Objects\\Spawnmodels\\Human\\HumanBlood\\BloodElfSpellThiefBlood.mdl",v,"overhead"))
    
    set u = null
    set v = null    
endfunction

function Dash_Effects takes nothing returns nothing
    local timer t = GetExpiredTimer()
    local string s = GetAttachmentTable(t)
    local trigger trig
    local string strig
    local unit u = GetTableUnit(s,"u")
    local real ang = GetTableReal(s,"ang")
    local real dist = GetTableReal(s,"dist")
    local real moved = GetTableReal(s,"moved")    
    
    call SetUnitPosition(u,GetUnitX(u) + 30 * Cos(ang * bj_DEGTORAD),GetUnitY(u) + 30 * Sin(ang * bj_DEGTORAD))
    call SetUnitAnimationByIndex(u,1)    
    set moved = moved+30
    
    if moved>=dist or GetUnitState(u,UNIT_STATE_LIFE)<=0 then
        set trig = GetTableTrigger(s,"trig")
        set strig = GetAttTable(trig)
        call TriggerRemoveAction(trig,GetTableTriggerAction(strig,"ta"))
        call ClearTable(strig)
        call DestroyTrigger(trig)
        set trig = null
        call SetUnitTimeScalePercent(u, 100)
        call SetUnitPathing(u,true) 
        call SetUnitAnimationByIndex(u,0)
        call ClearTable(s)
        call PauseTimer(t)
        call DestroyTimer(t)
    else
        call SetTableReal(s,"moved",moved)
    endif    
    
    set u = null
endfunction

function Trig_Dash_Actions takes nothing returns nothing
    local unit u = GetTriggerUnit()
    local location l = GetSpellTargetLoc()
    local real x = GetUnitX(u)
    local real y = GetUnitY(u)
    local real xtarg = GetLocationX(l)
    local real ytarg = GetLocationY(l)
    local real ang = bj_RADTODEG * Atan2(ytarg - y, xtarg - x)
    local real dx = xtarg - x
    local real dy = ytarg - y
    local real dist = SquareRoot(dx * dx + dy * dy) 
    local trigger trig = CreateTrigger()    
    local string strig = GetAttachmentTable(trig)
    local timer t = CreateTimer()
    local string s = GetAttachmentTable(t)
    
    call TriggerRegisterUnitInRange(trig,u,150,null)
    call TriggerAddCondition( trig, Condition( function Dash_Dam_Cond ) )
    call SetTableObject(strig,"ta", TriggerAddAction( trig, function Dash_Dam ))
    call SetTableObject(strig,"u",u)    
    
    call SetTableReal(s,"ang",ang)
    call SetTableReal(s,"dist",dist)
    call SetTableReal(s,"moved",0)
    call SetTableObject(s,"u",u)
    call SetTableObject(s,"trig",trig)    
    call TimerStart(t,.03,true,function Dash_Effects)
    
    call SetUnitTimeScalePercent(u, 400) 
    call SetUnitPathing(u,false)
    call SetUnitAnimationByIndex(u,1)
    
    set u = null
    call RemoveLocation(l)
    set l = null
    set trig = null    
endfunction

//===========================================================================
function InitTrig_Dash takes nothing returns nothing
    set gg_trg_Dash = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( gg_trg_Dash, EVENT_PLAYER_UNIT_SPELL_EFFECT )
    call TriggerAddCondition( gg_trg_Dash, Condition( function Trig_Dash_Conditions ) )
    call TriggerAddAction( gg_trg_Dash, function Trig_Dash_Actions )
    Preload("Objects\\Spawnmodels\\Human\\HumanBlood\\BloodElfSpellThiefBlood.mdl")
endfunction




V 1.02(Fixed up a good bit recently)
That is all for now folks. The spell you have created is MUI and leak free. Congratulations on finishing the tutorial, and good luck JASSing.
 

ReVolver

Mega Super Ultra Cool Member
Reaction score
609
Wow :eek: Keep up the good job!

[Moved] Temporary
 

lh2705

Just another Helper
Reaction score
111
if u dont mind could you put a ready made map for this?

"IF YOU DONT MIND" :D :D
 

emjlr3

Change can be a good thing
Reaction score
395
lh2705 said:
if u dont mind could you put a ready made map for this?

"IF YOU DONT MIND" :D :D

I'll think about it, but then that kinda defeats hte purpose of you following thsi and making it on ur own
 

Sim

Forum Administrator
Staff member
Reaction score
534
Well why put a finished map ? JASS triggers can simply be copy-pasted into the trigger editor and chaning the Id of the spells. :D
 

emjlr3

Change can be a good thing
Reaction score
395
Daxtreme said:
Well why put a finished map ? JASS triggers can simply be copy-pasted into the trigger editor and chaning the Id of the spells. :D

that too, it would jsut require u making a base ability, and changing the rawcode
 

phyrex1an

Staff Member and irregular helper
Reaction score
447
Code:
function Trig_Dash_Conditions takes nothing returns boolean
    Return GetSpellAbilityId() == 'AUan' 
endfunction
hmm... return, with capital r?

>GetAttTable()
This is a home made function, change that to GetAttachmentTable().

In the finished code:
Code:
    return IsUnitEnemy(GetFilterUnit(),GetOwningPlayer(GetTableUnit(s,"u")))==true and GetUnitState(GetFilterUnit(),UNIT_STATE_LIFE)>0
The ==true ins't needed.

Code:
    call TriggerAddCondition( trig, Condition( function Dash_Dam_Cond ) )
This leaks a triggercondition and a boolexpr.

And, for straigh line movments you doesn't need to use Cos and Sine as much as you do, and its suggested to avoid them when possible.
Code:
30 * Cos(ang * bj_DEGTORAD)
This is static through the whole trigger so insteed of storing the angle in the gamecache you can store the
Code:
30 * Cos(ang * bj_DEGTORAD)
and
Code:
30 * Sin(ang * bj_DEGTORAD)
vaule in the gamecache.

If you not want to do that change then you can think about this insteed:
Code:
    local real ang = bj_RADTODEG * Atan2(ytarg - y, xtarg - x)
just to convert it back to a rad angle again in the function Dash_Effects
Code:
    call SetUnitPosition(u,GetUnitX(u) + 30 * Cos(ang * bj_DEGTORAD),GetUnitY(u) + 30 * Sin(ang * bj_DEGTORAD))

Code:
    call SetTableReal(s,"moved",0)
In the function Trig_Dash_Actions isn't needed, it's 0 by defoult.

In the function Dash_Dam you have some wierd spaces in the middle of variable names, makes it hard to copy 'n paste ^^

Good tutorial, I had to dig realy deep to find those small things ^^
 

emjlr3

Change can be a good thing
Reaction score
395
fixed the return error, and AttTable error

==true may not be needed, but it can't hurt either

how to remove trigger condition leaks?

the spaces seems fine in my post, but screws up when shown, duno y

the rest I'll fix when I get the chance
 

phyrex1an

Staff Member and irregular helper
Reaction score
447
emjlr3 said:
==true may not be needed, but it can't hurt either
Its the same thing as call DoNothing(), waste of execution time ^^
But in the end it's up to the coder wich way to code...

Code:
    call TriggerAddCondition( trig, Condition( function Dash_Dam_Cond ))
The boolexpr must be destroyed later togheter with the triggercondition.
The triggercondition can be destroyed with TriggerRemoveCondition.

I suggest that you doesn't use TriggerAddCondition at all, you can use the boolexpr parameter for the TriggerRegisterUnitInRange insteed, that way you only have one boolexpr to clean up.

The best solution is ofc to try to make so you doesn't need a filter at all but, as in this trigger, that isn't always possible.
 

lh2705

Just another Helper
Reaction score
111
i get 88 compiled errors mostly consisting of

Expecting a variable name
Expecting a code statement
Expecting a name
Expecting a function name

how to fix it??

sry for dbl posting
 

emjlr3

Change can be a good thing
Reaction score
395
well one step might be to use JASS Craft...just a thought, i only mentioned that a million times
 
B

BigNailCow

Guest
It's probably due to not using CScache. That happened to me until I figured out what CScache was, which your tutorial doesn't really mention.
 

emjlr3

Change can be a good thing
Reaction score
395
All you need to follow this tutorial, is the WE some basic JASS knowledge, JASS Craft and the CScache system found and easily implemented from Vexorian’s caster system,

u sure?

** recently fixed a good bit of the code I hade screwed up, may want to check it again, only prob still left is the condition leak, ill mess with that later
 

emjlr3

Change can be a good thing
Reaction score
395
y is this?, the caster deals the damage, and is right next to the unit who dies
 
Reaction score
456
...and emjlr3 is talking about simple dash spell :) Example map would be cool.
 

emjlr3

Change can be a good thing
Reaction score
395
rofl the code is there, copy and paste teh code, create an ability, give it to a unit, and uve got an demo map, i dont see what teh big deal is
 

Defi4nc3

Developer of DORPG
Reaction score
20
One itsy bitsy little thing, im not sure if it was mentioned already but you put "PreLoad" with a Capital L, shouldn't it be "Preload"?

Love the Example though, Very Good Job.
 
General chit-chat
Help Users
  • No one is chatting at the moment.
  • Ghan Ghan:
    Still lurking
    +3
  • The Helper The Helper:
    I am great and it is fantastic to see you my friend!
    +1
  • The Helper The Helper:
    If you are new to the site please check out the Recipe and Food Forum https://www.thehelper.net/forums/recipes-and-food.220/
  • Monovertex Monovertex:
    How come you're so into recipes lately? Never saw this much interest in this topic in the old days of TH.net
  • Monovertex Monovertex:
    Hmm, how do I change my signature?
  • tom_mai78101 tom_mai78101:
    Signatures can be edit in your account profile. As for the old stuffs, I'm thinking it's because Blizzard is now under Microsoft, and because of Microsoft Xbox going the way it is, it's dreadful.
  • The Helper The Helper:
    I am not big on the recipes I am just promoting them - I use the site as a practice place promoting stuff
    +2
  • Monovertex Monovertex:
    @tom_mai78101 I must be blind. If I go on my profile I don't see any area to edit the signature; If I go to account details (settings) I don't see any signature area either.
  • The Helper The Helper:
    You can get there if you click the bell icon (alerts) and choose preferences from the bottom, signature will be in the menu on the left there https://www.thehelper.net/account/preferences
  • The Helper The Helper:
    I think I need to split the Sci/Tech news forum into 2 one for Science and one for Tech but I am hating all the moving of posts I would have to do
  • The Helper The Helper:
    What is up Old Mountain Shadow?
  • The Helper The Helper:
    Happy Thursday!
    +1
  • Varine Varine:
    Crazy how much 3d printing has come in the last few years. Sad that it's not as easily modifiable though
  • Varine Varine:
    I bought an Ender 3 during the pandemic and tinkered with it all the time. Just bought a Sovol, not as easy. I'm trying to make it use a different nozzle because I have a fuck ton of Volcanos, and they use what is basically a modified volcano that is just a smidge longer, and almost every part on this thing needs to be redone to make it work
  • Varine Varine:
    Luckily I have a 3d printer for that, I guess. But it's ridiculous. The regular volcanos are 21mm, these Sovol versions are about 23.5mm
  • Varine Varine:
    So, 2.5mm longer. But the thing that measures the bed is about 1.5mm above the nozzle, so if I swap it with a volcano then I'm 1mm behind it. So cool, new bracket to swap that, but THEN the fan shroud to direct air at the part is ALSO going to be .5mm to low, and so I need to redo that, but by doing that it is a little bit off where it should be blowing and it's throwing it at the heating block instead of the part, and fuck man
  • Varine Varine:
    I didn't realize they designed this entire thing to NOT be modded. I would have just got a fucking Bambu if I knew that, the whole point was I could fuck with this. And no one else makes shit for Sovol so I have to go through them, and they have... interesting pricing models. So I have a new extruder altogether that I'm taking apart and going to just design a whole new one to use my nozzles. Dumb design.
  • Varine Varine:
    Can't just buy a new heatblock, you need to get a whole hotend - so block, heater cartridge, thermistor, heatbreak, and nozzle. And they put this fucking paste in there so I can't take the thermistor or cartridge out with any ease, that's 30 dollars. Or you can get the whole extrudor with the direct driver AND that heatblock for like 50, but you still can't get any of it to come apart
  • Varine Varine:
    Partsbuilt has individual parts I found but they're expensive. I think I can get bits swapped around and make this work with generic shit though
  • Ghan Ghan:
    Heard Houston got hit pretty bad by storms last night. Hope all is well with TH.
  • The Helper The Helper:
    Power back on finally - all is good here no damage
    +2
  • V-SNES V-SNES:
    Happy Friday!
    +1
  • The Helper The Helper:
    New recipe is another summer dessert Berry and Peach Cheesecake - https://www.thehelper.net/threads/recipe-berry-and-peach-cheesecake.194169/

      The Helper Discord

      Members online

      No members online now.

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top