HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

Create a new object type [vJass]

06-30-2007, 11:13 AM#1
SlyRabbit
Before you continue:
First of all please forgive me for anything unclear in this article because English is not my native language.

Purpose of this tutorials:
1. Is to provide a useful code to other “Ability makers”, which has been tested in a map that works;
2. To show some advantage of vJass.

Preparation:
Tools:
All codes are written in vJass, kindly prepare the relative tools. I recommend Jass New Gen Pack.
Knowledge:
At least you have to know how vJass & Jass works, otherwise don’t waste time on this tutorials.
Please ignore all sentences start with debug, it’s only for debugging.

Other statement:
I will provide:
Answering of any questions followed;
Code problems fixing.
But will not provide:
Code migrating;
Take responsibility for maps destruction by code misuse or map tools.

Have you been tired of creating a set of units then remove them one by one after that, or repeat loop/ endloop million times?

Here is an example: When a unit cast “Flame Strike”, create a “Flame line” on the ground from <TriggerUnit>’s location to <SpellTarget> location. What do we do in a typical way?

1, Calculate the distance between <TriggerUnit>’s location & <SpellTarget> location;
2, Create a set of dummy units attached special effects(or directly special effects without units) along the path between this two locations, by loop/ endloop;
3, Wait a little bit time;
4, Delete these sets of units, by an other loop/ endloop of course.
Yes you may think of a custom function to perform it, but how do you reach each of the elements? Again you may say global variables, and if this is in a melee game, you have to use array for different players.
This is “millions of works.”

Now try to imagine that we have “unitsline” type object in the game which we can declare and use at any time, what happen if we can do this?

Read the trigger below:
Trigger:
Draw
Collapse Events
Unit - A unit Begins casting an ability
Collapse Conditions
(Ability being cast) Equal to Flame Strike
Collapse Actions
Custom script: local unitsline line = DrawUnitsline( GetOwningPlayer( GetTriggerUnit()), GetUnitLoc( GetTriggerUnit()), GetSpellTargetLoc())
Custom script: local real length = GetUnitslineLength( line )
Wait 3.00 seconds
Custom script: call DestroyUnitsline( line )
Unit - Set mana of (Triggering unit) to 100.00%
Unit - Reset ability cooldowns for (Triggering unit)

DrawUnitsline() is a custom function that returns “unitsline”, so we can easily use a local var to save it, then “Get” its length or “Destroy” it, such as what we normally do to a “lightning”, or “effect”, or “unit”.
This can be completely accomplished with our new friend, vJass.
I have to say that even now I am not so clear about how vJass works, anyway here is what we need to do:
Build a “struct” named unitsline, inclusive a real “length”, group “members”. "length” is a sub-var that save the length of line, “members” is actually a group that save all units we created.
Code:
Collapse JASS:
    struct unitsline
        real length
        group members
    endstruct

Then we start our work, create a custom function. You may see that it’s just as normal as creating a custom function, but please pay attention to that how we save data in “unitsline” var:
Code:
Collapse JASS:
// You may skip this part it’s just a private struct used in function.
    struct linedata
        real ox
        real oy
        real tx
        real ty
        real dx
        real dy
        real face
    endstruct
// You may skip this part it’s just a private struct used in function.
//--------------------------------------------------------------------------
    function DrawUnitsline takes player who, location startPoint, location endPoint returns unitsline
        local unit u
        local linedata line = linedata.create()
        local unitsline units_line = unitsline.create()
        local integer num
        local integer f = 1
        //! textmacro generaldebug
        debug local string message
        debug local string head
        debug local string mid
        debug local string end
        //! endtextmacro
        //! runtextmacro generaldebug()
        set line.ox = GetLocationX( startPoint )
        set line.oy = GetLocationY( startPoint )
        set line.tx = GetLocationX( endPoint )
        set line.ty = GetLocationY( endPoint )
        set line.face = Atan2( line.ty - line.oy, line.tx - line.ox )
        set units_line.members = CreateGroup()

// Here we save the length to lin.length, it’s not must. It’s particular and only for //GetUnitslineLength(), that a function will introduce below.

        set units_line.length = SquareRoot(( line.tx - line.ox ) * ( line.tx - line.ox ) + ( line.ty - line.oy ) * ( line.ty - line.oy ))
        set num = R2I( units_line.length ) / R2I( line_step )
        debug set head = "function call: " + SetTextColor( "Drawline()", "Yellow" ) + " "
        debug set mid = "by " + SetTextColor( "Player " +I2S( GetPlayerId( who ) + 1 ), "Red" ) + ", "
        debug set end = SetTextColor( I2S( num ), "Yellow" ) + " units been placed."
        debug set message = head + mid + end
        loop
            exitwhen f > num
            set line.dx = line.ox + I2R(f) * line_step * Cos( line.face )
            set line.dy = line.oy + I2R(f) * line_step * Sin( line.face )
            set u = CreateUnit( who, Dummysetting_DummyU, line.dx, line.dy, 0.0 )
            call SetUnitPathing( u, false )
            call SetUnitFlyHeight( u, 0.00, 0.00 )
            call AddSpecialEffectTarget( Dummysetting_FireModel, u, "origin" )

            // We save all units into line.members group, so we can reach them later.
            call GroupAddUnit( units_line.members, u )
            set u = null
            set f = f + 1
        endloop
        debug call BJDebugMsg( message )
        call linedata.destroy( line )
        return units_line
    endfunction

Now we already have a function that can create and return a “unitsline”, we still need more functions to reach the data that contain in this type of object. Of course the most important 1 is Destroy, we can’t just create something and then let it run forever without anyway to destroy. Another function I can think of is to get a unitsline’s length, actually it’s not necessary because you may use whichLine.length to get it simply, I create this function for an example purpose that how it works only.

Code:
Collapse JASS:
    function DestroyUnitsline takes unitsline whichLine returns nothing
        local unit u
        debug local integer num = 0
        //! runtextmacro generaldebug()

// Yes this is the same, we have to use a loop/ endloop to get each element in the group,    // then destroy 1 by 1.

        loop
            set u = FirstOfGroup( whichLine.members )
            exitwhen u == null
            call RemoveUnit( u )
            debug set num = num + 1
            call GroupRemoveUnit( whichLine.members, u )
        endloop
        debug set head = "function call: " + SetTextColor( "DestroyUnitsline()", "Yellow" ) + " "
        debug set mid = SetTextColor( I2S(num), "Yellow" ) + " units been destroyed."
        debug set message = head + mid
        debug call BJDebugMsg( message )
        // Destroy the struct
        call whichLine.destroy()
    endfunction
//--------------------------------------------------------------------------
    function GetUnitslineLength takes unitsline whichLine returns real
        //! runtextmacro generaldebug()
        debug local integer num = CountUnitsInGroup( whichLine.members )
        debug set head = "function call: " + SetTextColor( "GetUnitslineLength()", "Yellow" ) + " "
        debug set mid = "= " + SetTextColor( R2S( whichLine.length ), "Yellow" ) + "; "
        debug set end = SetTextColor( I2S(num), "Yellow" ) + " x " + SetTextColor( R2S(line_step), "Yellow" ) + " = " + SetTextColor( R2S( I2R(num) * line_step ), "Yellow" )
        debug set message = head + mid + end
        debug call BJDebugMsg( message )
        if ( whichLine.members == null ) then
            return 0.0
        endif
        // This is simple, just get the length from it’s sub var.
        return whichLine.length
    endfunction

And here is the complete code, in case you don't have interest with researching it you can just paste it to your map and use:

Code:
Collapse JASS:
//==========================================================================
//--------------------------------------------------------------------------
//-                                                                        -
//--------------------------------------------------------------------------
//==========================================================================
library Dummysetting

globals
    public constant integer DummyU = 'u000'
    public constant string FireModel = "Abilities\\Spells\\Human\\FlameStrike\\FlameStrikeDamageTarget.mdl"
    //public constant string FireModel = "Abilities\\Spells\\Other\\Doom\\DoomDeath.mdl"
    //public constant string FireModel = "Doodads\\Cinematic\\FrostTrapUp\\FrostTrapUp.mdl"
endglobals

    struct unitsline
        real length
        group members
    endstruct

scope Debugfunctions
//==========================================================================
//--------------------------------------------------------------------------
    function SetTextColor takes string txt, string color returns string
        //! textmacro settextcolorfunction takes color, colorcode
        if ( color == "$color$" ) then
            set color = "$colorcode$"
        endif
        //! endtextmacro
        //! runtextmacro settextcolorfunction ( "White", "|cFFFFFFFF" )
        //! runtextmacro settextcolorfunction ( "Red", "|c00ff0000" )
        //! runtextmacro settextcolorfunction ( "Blue", "|c000000ff" )
        //! runtextmacro settextcolorfunction ( "Teal", "|c0000ffff" )
        //! runtextmacro settextcolorfunction ( "Purple", "|c00800080" )
        //! runtextmacro settextcolorfunction ( "Yellow", "|c00ffff00" )
        //! runtextmacro settextcolorfunction ( "Green", "|c0000ff00" )
        //! runtextmacro settextcolorfunction ( "Pink", "|c00ff00ff" )
        //! runtextmacro settextcolorfunction ( "Gray", "|cFF808080" )
        //! runtextmacro settextcolorfunction ( "LightBlue", "|cFFC0FFFF" )
        //! runtextmacro settextcolorfunction ( "DarkGreen", "|cFF004000" )
        //! runtextmacro settextcolorfunction ( "Brown", "|cFF400000" )
        //! runtextmacro settextcolorfunction ( "Black", "|cFF000000" )
        return color + txt + "|r"
    endfunction
//--------------------------------------------------------------------------
//==========================================================================
endscope

endlibrary
//==========================================================================
//--------------------------------------------------------------------------
//-                                                                        -
//--------------------------------------------------------------------------
//==========================================================================
library Drawfunctions requires Dummysetting

globals
    private constant real line_step = 30.0
    private constant real letter_verticle = 400.0
    private constant real letter_horizon = letter_verticle * 2.0
    private constant real effect_lifetime = 5.00
    private constant real angle_step = 3.00
endglobals

scope UnitslineFunctions
//==========================================================================
//--------------------------------------------------------------------------
    struct linedata
        real ox
        real oy
        real tx
        real ty
        real dx
        real dy
        real face
    endstruct
//--------------------------------------------------------------------------
    function DrawUnitsline takes player who, location startPoint, location endPoint returns unitsline
        local unit u
        local linedata line = linedata.create()
        local unitsline units_line = unitsline.create()
        local integer num
        local integer f = 1
        //! textmacro generaldebug
        debug local string message
        debug local string head
        debug local string mid
        debug local string end
        //! endtextmacro
        //! runtextmacro generaldebug()
        set line.ox = GetLocationX( startPoint )
        set line.oy = GetLocationY( startPoint )
        set line.tx = GetLocationX( endPoint )
        set line.ty = GetLocationY( endPoint )
        set line.face = Atan2( line.ty - line.oy, line.tx - line.ox )
        set units_line.members = CreateGroup()
        set units_line.length = SquareRoot(( line.tx - line.ox ) * ( line.tx - line.ox ) + ( line.ty - line.oy ) * ( line.ty - line.oy ))
        set num = R2I( units_line.length ) / R2I( line_step )
        debug set head = "function call: " + SetTextColor( "Drawline()", "Yellow" ) + " "
        debug set mid = "by " + SetTextColor( "Player " +I2S( GetPlayerId( who ) + 1 ), "Red" ) + ", "
        debug set end = SetTextColor( I2S( num ), "Yellow" ) + " units been placed."
        debug set message = head + mid + end
        loop
            exitwhen f > num
            set line.dx = line.ox + I2R(f) * line_step * Cos( line.face )
            set line.dy = line.oy + I2R(f) * line_step * Sin( line.face )
            set u = CreateUnit( who, Dummysetting_DummyU, line.dx, line.dy, 0.0 )
            call SetUnitPathing( u, false )
            call SetUnitFlyHeight( u, 0.00, 0.00 )
            call AddSpecialEffectTarget( Dummysetting_FireModel, u, "origin" )
            call GroupAddUnit( units_line.members, u )
            set u = null
            set f = f + 1
        endloop
        debug call BJDebugMsg( message )
        call linedata.destroy( line )
        return units_line
    endfunction
//--------------------------------------------------------------------------
    function DestroyUnitsline takes unitsline whichLine returns nothing
        local unit u
        debug local integer num = 0
        //! runtextmacro generaldebug()
        loop
            set u = FirstOfGroup( whichLine.members )
            exitwhen u == null
            call RemoveUnit( u )
            debug set num = num + 1
            call GroupRemoveUnit( whichLine.members, u )
        endloop
        debug set head = "function call: " + SetTextColor( "DestroyUnitsline()", "Yellow" ) + " "
        debug set mid = SetTextColor( I2S(num), "Yellow" ) + " units been destroyed."
        debug set message = head + mid
        debug call BJDebugMsg( message )
        call whichLine.destroy()
    endfunction
//--------------------------------------------------------------------------
    function GetUnitslineLength takes unitsline whichLine returns real
        //! runtextmacro generaldebug()
        debug local integer num = CountUnitsInGroup( whichLine.members )
        debug set head = "function call: " + SetTextColor( "GetUnitslineLength()", "Yellow" ) + " "
        debug set mid = "= " + SetTextColor( R2S( whichLine.length ), "Yellow" ) + "; "
        debug set end = SetTextColor( I2S(num), "Yellow" ) + " x " + SetTextColor( R2S(line_step), "Yellow" ) + " = " + SetTextColor( R2S( I2R(num) * line_step ), "Yellow" )
        debug set message = head + mid + end
        debug call BJDebugMsg( message )
        if ( whichLine.members == null ) then
            return 0.0
        endif
        return whichLine.length
    endfunction
//==========================================================================
endscope

endlibrary
07-01-2007, 10:35 PM#2
PitzerMike
Quite for good for a first post.
Your indentation and naming conventions are really weird, but the content of the tutorial is alright.
I approve.
07-30-2007, 11:17 PM#3
TheSecretArts
couldnt u just use type unitsline extends handle
07-30-2007, 11:56 PM#4
Ignitedstar
So this is one way of making one of those spells that uses a line in front of the caster... Man, have I needed one of these. But, I need to understand how vJass works...
08-24-2007, 06:49 PM#5
Silvenon
Quote:
But, I need to understand how vJass works...

Reeeeeally simple, don't worry ;)

SlyRabbit, you keep adding _ in unitsline name for no reason, units_line.members for example. The struct name is wrong, and it won't work.

Omg, locations! It surprises me a person that uses vJass uses locations. But then again, you use coordinates inside the function so I would say that you made it for GUI users.

Collapse JASS:
//! textmacro generaldebug
debug local string message
debug local string head
debug local string mid
debug local string end
//! endtextmacro

Wtf is this??? I totally don't understand those debugs.

Anways a fine tut, but I think everybody can make one of those functions for himself if he needs it. Not that my Knockback function is any better :P.

Quote:
Originally Posted by SlyRabbit
Have you been tired of creating a set of units then remove them one by one after that, or repeat loop/ endloop million times?

Million times is not necessary, just make one function (like you did) and call it every time.

+REP!!!