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
608
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.
  • Varine Varine:
    How can you tell the difference between real traffic and indexing or AI generation bots?
  • The Helper The Helper:
    The bots will show up as users online in the forum software but they do not show up in my stats tracking. I am sure there are bots in the stats but the way alot of the bots treat the site do not show up on the stats
  • Varine Varine:
    I want to build a filtration system for my 3d printer, and that shit is so much more complicated than I thought it would be
  • Varine Varine:
    Apparently ABS emits styrene particulates which can be like .2 micrometers, which idk if the VOC detectors I have can even catch that
  • Varine Varine:
    Anyway I need to get some of those sensors and two air pressure sensors installed before an after the filters, which I need to figure out how to calculate the necessary pressure for and I have yet to find anything that tells me how to actually do that, just the cfm ratings
  • Varine Varine:
    And then I have to set up an arduino board to read those sensors, which I also don't know very much about but I have a whole bunch of crash course things for that
  • Varine Varine:
    These sensors are also a lot more than I thought they would be. Like 5 to 10 each, idk why but I assumed they would be like 2 dollars
  • Varine Varine:
    Another issue I'm learning is that a lot of the air quality sensors don't work at very high ambient temperatures. I'm planning on heating this enclosure to like 60C or so, and that's the upper limit of their functionality
  • Varine Varine:
    Although I don't know if I need to actually actively heat it or just let the plate and hotend bring the ambient temp to whatever it will, but even then I need to figure out an exfiltration for hot air. I think I kind of know what to do but it's still fucking confusing
  • The Helper The Helper:
    Maybe you could find some of that information from AC tech - like how they detect freon and such
  • Varine Varine:
    That's mostly what I've been looking at
  • Varine Varine:
    I don't think I'm dealing with quite the same pressures though, at the very least its a significantly smaller system. For the time being I'm just going to put together a quick scrubby box though and hope it works good enough to not make my house toxic
  • Varine Varine:
    I mean I don't use this enough to pose any significant danger I don't think, but I would still rather not be throwing styrene all over the air
  • The Helper The Helper:
    New dessert added to recipes Southern Pecan Praline Cake https://www.thehelper.net/threads/recipe-southern-pecan-praline-cake.193555/
  • The Helper The Helper:
    Another bot invasion 493 members online most of them bots that do not show up on stats
  • Varine Varine:
    I'm looking at a solid 378 guests, but 3 members. Of which two are me and VSNES. The third is unlisted, which makes me think its a ghost.
    +1
  • The Helper The Helper:
    Some members choose invisibility mode
    +1
  • The Helper The Helper:
    I bitch about Xenforo sometimes but it really is full featured you just have to really know what you are doing to get the most out of it.
  • The Helper The Helper:
    It is just not easy to fix styles and customize but it definitely can be done
  • The Helper The Helper:
    I do know this - xenforo dropped the ball by not keeping the vbulletin reputation comments as a feature. The loss of the Reputation comments data when we switched to Xenforo really was the death knell for the site when it came to all the users that left. I know I missed it so much and I got way less interested in the site when that feature was gone and I run the site.
  • Blackveiled Blackveiled:
    People love rep, lol
    +1
  • The Helper The Helper:
    The recipe today is Sloppy Joe Casserole - one of my faves LOL https://www.thehelper.net/threads/sloppy-joe-casserole-with-manwich.193585/
  • The Helper The Helper:
    Decided to put up a healthier type recipe to mix it up - Honey Garlic Shrimp Stir-Fry https://www.thehelper.net/threads/recipe-honey-garlic-shrimp-stir-fry.193595/

      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