• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

vJass - The start

Status
Not open for further replies.
Level 16
Joined
May 1, 2008
Messages
1,605
Moin moin =)

Yes I want to learn vJass now. I see there many people here, that understand it so I hope I get a little help with my start in vJass ^^
I will post here some question I have and try to learn from it.

NOTE: As you know all ( actually you should ) my english is bad. So please try to explain it step by step so I can understand it and learn from it. So I just start with my questions now and hope some can help me =)

1) How I start after setting the "spell configurations"?
For example, in a vJass spell you start with that:
JASS:
scope MyTrigger initializer Init
   globals
      private constant integer SPELL_ID = 'A001'
      private constant integer DUMMY_ID = 'h001'
      // and so on
   endglobals

   // Now you can continue the settings with stuff like
   private constant function Area takes integer lvl returns real
      return 350. + 50*lvl
   endfunction
   // and so on ( with AOE, damage and so on )
Ok this part is very easy, but after the configuration, HOW I continue? I never know what is the next part after these configurations.

2) The .
Yes, what is the meaning of this . in vJass?
JASS:
set .lvl = GetUnitAbilityLevel(.cast,SPELL_ID)
There you see a . in front of lvl and cast. I now the names "lvl" and "cast" are, I call it now: vJass variables. Behind the . the names are gray. So what is the meaning of the . and why is the word after the dot gray?

3) TimerUtils

What is this at all? A friend give me a link to it: http://www.wc3c.net/showthread.php?t=101322. I understand now that I can choose(?) between three types of timer or something like that ( blue - red - orange ) by setting the USE_HASH_TABLE and USE_FLEXIBLE_OFFSET. But HOW I use this TimerUtils in my vJass spell? Need I add a specified line in my spell then? Or is this use automatically?


Yes these are my three starting questions. I think I will have more after some time, but I start at 0 now, and I want learn it step by step.
For learning vJass I talked to watermelon already, but it's a bad feeling for me to ask him every time every day about vJass, so I make this Thread now for all who want start with vJass ^^

Greetings, Thanks and Peace
Dr. Boom
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,467
You can PM me for specific questions. In terms of the dot-syntax, that is reserved for structs. I advise reading a structs tutorial. there is a great one on TheHelper.net called "vJass: Uncomplicating the Complicated".

TimerUtils is for use with structs and for recycling your timers. Sometimes you should use TimerUtils and a lot of timers, but most of the time you can do it with a single timer and loop through your instances. Again, PM me and I can define any ungodly words.
 
Level 5
Joined
Oct 14, 2010
Messages
100
2) .member is a short writing for this.member. I suggest you always use the this keyword for readability.
this is a reserved keyword for the pointer to the current instance of a struct. A struct is essentially a data type such as unit, player that you create yourself. A popular example is
JASS:
struct Point
real x
real y
endstruct
for it defines a new datatype called "Point" that has an X and an Y coordinate.
Read more about structs at http://www.wc3c.net/vexorian/jasshelpermanual.html#stru

3) TimerUtils basically gives you an alternate way for using timers. It's a better way in the sense that it's faster, shouldn't leak and easier to use.

The library adds 4 functions.
local timer t = NewTimer() will create a new timer. The old way of doing this was by calling CreateTimer().
call SetTimerData(t, data) will attach an integer (data) to the timer.
local integer data = GetTimerData(t) will retrieve said data again from the timer. This is useful because you can attach structs in 1 function, and then retrieve that struct in the function that runs when the timer expires.
call ReleaseTimer(t) will recycle the timer so when you no longer need to use that timer, it can be used elsewhere. This is a counterpart to DestroyTimer(t)

1) It really depends on what you want the spell to do. First, you'll need a trigger that runs when the spell is cast. You'll need a function that contains all actions to be taken when the spell is cast.
 
Level 16
Joined
May 1, 2008
Messages
1,605
Moin moin =)

Ahh ok this sounds good, so I know a little more now. I wanted to make a very simple spell for training at the beginning but I fail a lot. I did first everything I know myself without any help but now I can't move on with the trigger. I looked at some tutorials but they didn't help at this point. Also I look to spells at hive but everyone do his own vJass as I notice.

The Spell idea at all was simple: The caster cast an ability on a friendly target. This target gets an armor bonus ( from the spell ) for 10 seconds. Now every second a light effect should be created at the target and heal it and every nearby friendly units. Simple isn't it but I don't know what comes next... I don't think my work up to now is correct anyway -_- so I post it and maybe someone can say something about it (say not laugh )

JASS:
scope SealOfLight initializer Init

    globals
        private constant integer SPELL_ID = 'A002'
        private constant real LOOP_TIME = 1.00
        private constant string AOE_EFFECT = "Abilities\\Spells\\Human\\HolyBolt\\HolyBoltSpecialArt.mdl"
        private constant boolean PRELOAD = true
    endglobals
    
    private constant function AOE_HEAL takes integer level returns real
        return 20.00 * level
    endfunction
    
    private constant function AOE_RANGE takes integer level returns real
        return 150.00 + 25 * level
    endfunction
    
    // End of Configuration
    
    globals
        private boolexpr b
        private group g
    endglobals
    
    private struct Data
        unit    caster //The caster
        unit    target // The target
        player  player = GetOwningPlayer(caster)
        real    x = GetUnitX(target)
        real    y = GetUnitY(target)
        timer   t
        private static thistype temp
        
        static method create takes unit caster,real x,real y returns thistype
            local thistype this = thistype.allocate()
            set .caster = c
            set .player = p
            set .x = x
            set .y = y
            set .t = NewTimer()
            return this
        endmethod
        
        static method filter takes nothing returns boolean
            local unit u = GetFilterUnit()
            
            return GetUnitState(u,UNIT_STATE_LIFE) > 0.405 and IsUnitAlly(u,temp.player)
            set u = null
        endmethod
        
        
        
        
        
    

    
////////////////////////////////////\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\    
//             This someother stuff at the end of the spell!!                      \\
////////////////////////////////////\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\

        static method SpellActions takes nothing returns nothing
        
            if GetSpellAbilityId() = SPELL_ID then
        
            else
            return false
        endmethod

        static method Init takes nothing returns nothing 
            local trigger t = CreateTrigger()
            local integer i = 0
            loop
                exitwhen i == bj_MAX_PLAYER_SLOTS
                call TriggerRegisterPlayerUnitEvent(t,Player(i),EVENT_PLAYER_UNIT_SPELL_EFFECT,null)
                set i = i + 1
            endloop
            call TriggerAddCondition(t,Condition(function thistype.SpellActions))
            set b = Condition(function thistype.filter)
            
             static if PRELOAD then
                call Preload(AOE_EFFECT)
            endif
            set t = null
        endmethod
    endstruct
endscoop

Greetings and Peace
Dr. Boom
 
Level 6
Joined
Nov 3, 2008
Messages
117
I recommend you read the vJass syntax manual in the Jasshelper folder.

About your code:

1. this endscoop must be this endscope
2. this scope SealOfLight initializer Init does not work for struct methods
You should make your Init function a private function instead of a static method. If you still want to keep it then you have to remove the initializer Init and rename your Init method to onInit.
3. this set b = Condition(function thistype.filter) won't do anything
4. You got a couple of mistakes in here:
JASS:
private struct Data
        unit    caster //The caster
        unit    target // The target
        player  player = GetOwningPlayer(caster)
        real    x = GetUnitX(target)
        real    y = GetUnitY(target)
        timer   t
        private static thistype temp
        
        static method create takes unit caster,real x,real y returns thistype
            local thistype this = thistype.allocate()
            set .caster = c
            set .player = p
            set .x = x
            set .y = y
            set .t = NewTimer()
            return this
        endmethod
instance members cannot be defined like you did. You have to define them when you create an instance. In your create method the variable p is not declared. The code posted above should look like this:
JASS:
private struct Data
        unit    caster = null
        unit    target = null
        player  owner
        real    x = 0.
        real    y = 0.
        timer   t = null
        private static thistype temp
        
        static method create takes unit caster, unit target returns thistype
            local thistype this = thistype.allocate()
            set this.caster = caster
            set this.target = target
            set this.player = GetOwningPlayer(caster)
            set this.x = x
            set this.y = y
            set this.t = NewTimer()
            return this
        endmethod
the dot syntax (set .caster = caster for example) cannot be used in static methods!

5.
JASS:
static method SpellActions takes nothing returns nothing
        
            if GetSpellAbilityId() = SPELL_ID then
        
            else
            return false
        endmethod
since you use this in a Condition(function thistype.SpellActions) the method above must return a boolean. And it is enough when you write it like this:
JASS:
static method SpellActions takes nothing returns boolean
    return GetSpellAbilityId()==Spell_ID
endmethod

That's all for now!
 
Level 16
Joined
May 1, 2008
Messages
1,605
Moin moin =O

WoW I see you understand the plan of vJass - very nice. Jeah as I thought many mistakes in my code, but ok I'm at the start point so this should be ok ^^

Ofc imba thanks to you and the other, who helped me up to now!!!

@ Inferior: But I have a question, you fixed me a lot of stuff in 4. I saw in your code you use:
JASS:
set this.player = GetOwningPlayer(caster)
Was this the plan? or must it like this:
JASS:
set this.owner = GetOwningPlayer(caster)
?

Greetings, imba Thanks and Peace
Dr. Boom
 
Level 16
Joined
May 1, 2008
Messages
1,605
Ok so far so good but I have 2 more points, when I try to save the map ( trigger is enable now ) he say the following:

"Undeclared variable SPELL_ID" in this line:
JASS:
return GetSpellAbilityId() == Spell_ID
But I set it above in the globals. Need I do something more there?

And the second ... I'm confused. You remember I have the part:
JASS:
        static method SpellActions takes nothing returns boolean
            return GetSpellAbilityId() == Spell_ID
        endmethod

But the jasshelper shows:
JASS:
        function s__SealOfLight___Data_SpellActions takes nothing returns boolean
            return GetSpellAbilityId() == Spell_ID
        endfunction

He mark "endfunction" and say: Comparing two variables of different primitive types (except Integer and Real ) are not allowed.

How can I fix this now?

Greetings and Peace
Dr. Boom
 
Level 6
Joined
Nov 3, 2008
Messages
117
Ok, my bad. Check your globals. There you wrote in ALL-CAP.
Change this: return GetSpellAbilityId()==Spell_ID to this: return GetSpellAbilityId()==SPELL_ID

and about the second one. Jasshelper compiles your writen vJass code into plain jass. that's why it looks weird
 
Level 16
Joined
May 1, 2008
Messages
1,605
Moin moin =)

Omg I don't understand this ... now this error is gone and I got another.

JASS:
        static method filter takes nothing returns boolean
            local unit u = GetFilterUnit()
            
            return GetUnitState(u,UNIT_STATE_LIFE) > 0.405 and IsUnitAlly(u,temp.owner)
            set u = null
        endmethod

He mark "set u = null" with the massage "missing return. Ok clear because there isn't a return in front but I can't type return u = null or?

I use this with the local variable, because my friend "Maker" said, it's better when I use a variable instead of always GetFilterUnit() in the return action.

Greetings and Peace
Dr. Boom
 
Level 6
Joined
Nov 3, 2008
Messages
117
well then it should look like this:

JASS:
static method filter takes nothing returns boolean
   local unit u=GetFilterUnit()
   local boolean b = GetUnitState(u,UNIT_STATE_LIFE)>0.405 and IsUnitAlly(u,temp.owner)
   set u=null
   return b
endmethod

you can do it like this, because integers,reals,strings and booleans don't cause memory leaks. (maybe i forgot 1 variable type)
 
Level 5
Joined
Oct 14, 2010
Messages
100
JASS:
static method filter takes nothing returns boolean
   return GetUnitState(GetFilterUnit(),UNIT_STATE_LIFE)>0.405 and IsUnitAlly(GetFilterUnit(),temp.owner)
endmethod

I know it's adviced to use local variables instead of calling functions such as GetFilterUnit() or GetTriggerUnit() multiple times, but in my opinion it's not worth doing in this case. I think the readability here outweighs the insignificant speedup you may get.

In fact, in this case it may even be faster than using 2 local variables and an assignment to null.
 
Level 6
Joined
Nov 3, 2008
Messages
117
JASS:
static method filter takes nothing returns boolean
   return GetUnitState(GetFilterUnit(),UNIT_STATE_LIFE)>0.405 and IsUnitAlly(GetFilterUnit(),temp.owner)
endmethod

I know it's adviced to use local variables instead of calling functions such as GetFilterUnit() or GetTriggerUnit() multiple times, but in my opinion it's not worth doing in this case. I think the readability here outweighs the insignificant speedup you may get.

In fact, in this case it may even be faster than using 2 local variables and an assignment to null.

It's only worth using the variables, when you use GetFilterUnit() for example more than trice. Otherwise you won't get any gains in speed (as far as i know, correct me if i'm wrong)
 
Level 16
Joined
May 1, 2008
Messages
1,605
Moin moin =)

For the next step I need to know the following: I use
JASS:
       private constant real LOOP_TIME          = 0.04
Now my question, how exaclty does this work?

Is it like 0.00 > 0.01 > 0.02 > 0.03 > 0.04 (do everything) > resett to 0.00 > and then again 0.01 > 0.02 > 0.03 > 0.04 ( do everything) > again resett 0.00 > ....?

Or is it like: 0.00 > 0.01 > 0.02 > 0.03 > 0.04 (do everything) > 0.05 > 0.06 > 0.07 > 0.08 ( do everything ) > 0.09 ..... ?

Greetings and Peace
Dr. Boom
 
Level 6
Joined
Nov 3, 2008
Messages
117
You just do this: TimerStart(anytimer,LOOP_TIME,true,function anyfunction)
the native looks like this : native TimerStart takes timer t, real time, boolean periodic, code callback returns boolean (i am not sure about the return at the moment). The boolean agrument "periodic" defines, whether the timer shall fire the callback code periodically (every "time" seconds) or once (will stop after "time" seconds). So i don't get what you need this for. We talk later about it, when i'm home again.
 
Level 16
Joined
May 1, 2008
Messages
1,605
Moin moin =)

Ok because I want make it with my new spell so ( was the idea I had first and I just try it )

A ball moves one line for some seconds. I want that the time continue like 0.00 > 0.01 > 0.02 > 0.03 > 0.04 (actions) > 0.05 and so on, because I create another value:
JASS:
private constant real       WAVE_RELEASE    = 3.00
and now I use this:
JASS:
private static method loop takes nothing returns nothing
   local real modulus = WAVE_RELEASE - ( WAVE_RELEASE / LOOP_TIME) * LOOP_TIME // hope this is correct (JassHelper said something like that)

   if modulus = 0. then
   // bla bla

That why I need that the LOOP_TIME continue and will "fire" at 0.04 0.08 0.12 ...

Hope you understand what I want say here and can give me a little help about this then.

Edit: In GUI it would be something like this:
  • Untitled Trigger 001
    • Events
      • Time - Every 0.04 seconds of game time
    • Conditions
    • Actions
      • Set Real = (Real + 0.04)
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (Real mod 2.00) equal to 0.00
        • Then - Actions
          • -------- do actions --------
        • Else - Actions
NOTE: I'm still try to learn vJass, so comments like "omg wtf you do -_-" are useless at this point =)

Greetings and Peace
Dr. Boom
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,467
This will work better:

JASS:
scope blank initializer init

globals
    private integer g_count = 0
endglobals

private function periodic takes nothing returns nothing
    set g_count = g_count + 1
    if (g_count == 50) then
        set g_count = 0
        // Do rare actions
    endif
    // Do common actions
endfunction

private function init takes nothing returns nothing
    call TimerStart(CreateTimer(), 0.04, true, function periodic)
endfunction

endscope
 
Level 16
Joined
May 1, 2008
Messages
1,605
Ahh ok I see this make sense I will try this =)

Thank you for helping me with vJass =D

Edit: I'm sorry, but I can't give you +rep now because I gave it to you at your post here on page 1. I will do it later if I can!

Edit 2: Ok I finish my code ( I think -_- ) and now I enable it and when I try to save I get the following JasHelper error:

Jasshelper mark "library Shockwaves initializer Init requires TimerUtils" (the first line) and say:

"Unable to find prototype: function init takes nothing returns *** inside the library"

What does they mean? I checked it but I don't understand what Jasshelper want from me^^

Edit 3. I fixed this, my mistake was to put "entstruct" at the bottom of the code before endlibrary

Greetings and Peace
Dr. Boom
 
Last edited:
Status
Not open for further replies.
Top