• Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
  • Read Evilhog's interview with Gregory Alper, the original composer of the music for WarCraft: Orcs & Humans 🔗Click here to read the full interview.

[JASS] Please help me check whats wrong

Status
Not open for further replies.
Level 4
Joined
Jul 20, 2005
Messages
107
Hello everyone.. I just started to learn jass and i've try to make a skill out of it.. However it didn't went well.. The JASS don't seem to work on the loop part and just skip everything else after the loop action..

Here is the script

JASS:
function RB_Conditions takes nothing returns boolean
    return GetSpellAbilityId() == 'A000'
endfunction

function RB_Actions takes nothing returns nothing
    local unit c = GetSpellAbilityUnit()
    local unit t = GetSpellTargetUnit()
    local lightning l
    local integer i
    call AddLightningLoc( "FORK", GetUnitLoc(c), GetSpellTargetLoc() )
    set l = GetLastCreatedLightningBJ()
    loop
        exitwhen IsUnitAliveBJ(c) == false or IsUnitAliveBJ(t) == false or i == 46 or R2I(DistanceBetweenPoints(GetUnitLoc(c), GetUnitLoc(t))) >= 800
        call MoveLightningLoc( l, GetUnitLoc(c), GetUnitLoc(t) )
        call SetLightningColorBJ( l, GetRandomReal(0, 1), GetRandomReal(0, 1), 1, 1 )
        call UnitDamageTargetBJ( c, t, 50.00, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_NORMAL )
        set i = i + 1
    endloop
    set i = 0
    call DestroyLightningBJ(l)
endfunction

//======================
function InitTrig_RB takes nothing returns nothing
    local trigger RB = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ(RB, EVENT_PLAYER_UNIT_SPELL_EFFECT)
    call TriggerAddCondition(RB, Condition(function RB_Conditions))
    call TriggerAddAction(RB, function RB_Actions)
    set RB = null
endfunction



You may notices that i didn't null the variable.. well i will after i find out how to complete the jass.. So do help me.. Thank you very much =)
 
Level 40
Joined
Dec 14, 2005
Messages
10,532
AddLightningLoc does not give a Last Created Lightning, and the integer var must be initialized at 0. Also, there is no spell target location when the spell is unit-targeted.

Fixed script (Also fixes other stuff)

You may want to note that this all happens instantly since there are no waits.

JASS:
function RB_Conditions takes nothing returns boolean
    return GetSpellAbilityId() == 'A000'
endfunction

function RB_Actions takes nothing returns nothing
    local unit c = GetTriggerUnit()
    local unit t = GetSpellTargetUnit()
    local real x = GetUnitX(c)
    local real y = GetUnitY(c)
    local real x2 = GetUnitX(t)
    local real y2 = GetUnitY(t)
    local lightning l = AddLightning("FORK",true,x,y,x2,y2)
    local integer i = 0
    loop
        exitwhen GetWidgetLife(c) <= 0 or GetWidgetLife(t) <= 0 or i > 45 or (x-x2)*(x-x2)+(y-y2)*(y-y2) >= 640000
        call MoveLightning(l,true,x,y,x2,y2)
        call SetLightningColor(l,GetRandomReal(0,1),GetRandomReal(0,1),1,1)
        call UnitDamageTarget(c,t,50,true,false,ATTACK_TYPE_NORMAL,DAMAGE_TYPE_NORMAL,null)
        set i = i + 1
    endloop
    call DestroyLightning(l)
    set l = null
    set c = null
    set t = null
endfunction

//======================
function InitTrig_RB takes nothing returns nothing
    local trigger RB = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ(RB, EVENT_PLAYER_UNIT_SPELL_EFFECT)
    call TriggerAddCondition(RB, Condition(function RB_Conditions))
    call TriggerAddAction(RB, function RB_Actions)
    set RB = null
endfunction
 
Level 4
Joined
Jul 20, 2005
Messages
107
Okie thanks but can you explain the lightning action to me a bit? I wanna know whats inside the bracket
And also the Unit damage why got a null at the end of it?
And also the range for the exitwhen..
 
Level 40
Joined
Dec 14, 2005
Messages
10,532
Okie thanks but can you explain the lightning action to me a bit? I wanna know whats inside the bracket
Please specify.

And also the Unit damage why got a null at the end of it?
Weapon Type, which is just for sounds (like Metal Medium Slice and all those things).

And also the range for the exitwhen..
Since range is the Square Root of the change in x squared plus the change in y squared, but Square Root is slow, it is more efficient to square both sides of the equation.
 
Level 4
Joined
Jul 20, 2005
Messages
107
Don't really understand why do we need to use square root..

About the bracket i think i understand already.. Thanks a lot.. And what other actions are unable to use last created?
I'd try what you did and there is a bit problem.. The lightning does not follow the unit.. But i fixed it
 
Level 40
Joined
Dec 14, 2005
Messages
10,532
About the bracket i think i understand already.. Thanks a lot.. And what other actions are unable to use last created?
Any natives can't use last created, BJ functions manually set the variable.

Don't really understand why do we need to use square root..
By pythagoras' theorem, in a right-angled triangle

x*x + y*y = h*h (h=length of hypotenuse)

Thus,

d (length of hypotenuse, same as h) = Sqrt(x*x+y*y)

For reference:

JASS:
function DistanceBetweenPoints takes location locA, location locB returns real
    local real dx = GetLocationX(locB) - GetLocationX(locA)
    local real dy = GetLocationY(locB) - GetLocationY(locA)
    return SquareRoot(dx * dx + dy * dy)
endfunction
 
Level 4
Joined
Jul 20, 2005
Messages
107
Now that you mention it i remember thanks a lot.. How stupid of me to forget that formula after i graduate from high school haha..

I also find out that instead of you using IsUnitAliveBJ you use GetwidgetLife.. it is the same concept as the lightning right?

Anyway I added wait in the trigger and i put 0.10 waiting time and it is not as smooth as i use 2 trigger.. And if i am not wrong wait action can't be less than 0.1 right? So any suggestion? This is the trigger i made

  • Testing
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
      • (Ability being cast) Equal to Rainbow Lightning
    • Actions
      • Lightning - Create a Forked Lightning lightning effect from source (Position of (Casting unit)) to target (Target point of ability being cast)
      • Set lightning[1] = (Last created lightning effect)
      • Set Temp_Unit[1] = (Casting unit)
      • Set Temp_Unit[2] = (Target unit of ability being cast)
      • Trigger - Turn on Testing Copy <gen>
  • Testing Copy
    • Events
      • Time - Every 0.10 seconds of game time
    • Conditions
    • Actions
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (Temp_Unit[1] is alive) Equal to True
          • (Temp_Unit[2] is alive) Equal to True
          • TempInteger[1] Less than or equal to 45
          • (Integer((Distance between (Position of Temp_Unit[1]) and (Position of Temp_Unit[2])))) Less than or equal to 800
        • Then - Actions
          • Special Effect - Create a special effect attached to the origin of Temp_Unit[2] using Abilities\Weapons\Bolt\BoltImpact.mdl
          • Lightning - Move lightning[1] to source (Position of Temp_Unit[1]) and target (Position of Temp_Unit[2])
          • Lightning - Change color of (Last created lightning effect) to ((Random real number between 0.00 and 1.00) (Random real number between 0.00 and 1.00) 1.00) with 1.00 alpha
          • Unit - Cause Temp_Unit[1] to damage Temp_Unit[2], dealing 50.00 damage of attack type Spells and damage type Normal
          • Set TempInteger[1] = (TempInteger[1] + 1)
          • Special Effect - Destroy (Last created special effect)
        • Else - Actions
          • Lightning - Destroy lightning[1]
          • Set TempInteger[1] = 0
          • Trigger - Turn off (This trigger)
 
Last edited:
Level 4
Joined
Jul 20, 2005
Messages
107
Ok so the lightning works.. But there is another problem.. If the unit is flying.. The lightning won't target on that unit but will only target on the position he is in.. Is there a solution for this?

And also another problem is how do you set to timer? you need to use global variable already?

Actually what is the meaning of BJ?
 
Last edited:
Level 6
Joined
Mar 20, 2008
Messages
208
GetUnitFlyHeight() might be of use

Ground units should have their flyheight return as 0, I gues you could create the spell with an offset.

a UNIT_TYPE_FLYING check might also be useful.



BJ means its a blizzard junction. Which means its a helper function that calls a native function for you, which makes it easier for you and the map editor, at the cost of efficiency and speed.

Normally, you can strip out the BJ and go straight to the native to save your code a jump or two, especially if its a BJ that has a bunch of if-then checks that you know will never be needed.
 
Level 4
Joined
Jul 20, 2005
Messages
107
I've rewrite the jass using timer and it works however it does not work as MUI.. It will be buggy if more than 2 units are use the skill.. Please help me correct it.. Also help me do the flying is possible.. Thanks a lot

JASS:
function RB_Conditions takes nothing returns boolean
    return GetSpellAbilityId() == 'A000'
endfunction

function RB_Func002A takes nothing returns nothing
    local real x = GetUnitX(udg_caster)
    local real y = GetUnitY(udg_caster)
    local real x2 = GetUnitX(udg_targ)
    local real y2 = GetUnitY(udg_targ)
    if IsUnitAliveBJ(udg_caster) == true and IsUnitAliveBJ(udg_targ) == true and udg_integer <= 50 and (x-x2)*(x-x2)+(y-y2)*(y-y2) <= 640000 then
        call MoveLightning(udg_lightning,true,x,y,x2,y2)
        call SetLightningColor(udg_lightning,GetRandomReal(0,1),GetRandomReal(0,1),1,1)
        call UnitDamageTarget(udg_caster,udg_targ,10,true,false,ATTACK_TYPE_NORMAL,DAMAGE_TYPE_NORMAL,null)
        set udg_integer = udg_integer + 1
    else
        call DestroyLightning(udg_lightning)
        call DestroyTimer(udg_timer)
        set udg_timer = null
        set udg_caster = null
        set udg_targ = null
    endif
endfunction

function RB_Actions takes nothing returns nothing
    local real x
    local real y
    local real x2
    local real y2
    set udg_caster = GetTriggerUnit()
    set udg_targ = GetSpellTargetUnit()
    set x = GetUnitX(udg_caster)
    set y = GetUnitY(udg_caster)
    set x2 = GetUnitX(udg_targ)
    set y2 = GetUnitY(udg_targ)
    set udg_integer = 0
    set udg_lightning = AddLightning("FORK",true,x,y,x2,y2)
    set udg_timer = CreateTimer()
    call TimerStart(udg_timer,0.10,true,function RB_Func002A)
endfunction

//=======================
function InitTrig_RB takes nothing returns nothing
    local trigger RB = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ(RB, EVENT_PLAYER_UNIT_SPELL_EFFECT)
    call TriggerAddCondition(RB, Condition(function RB_Conditions))
    call TriggerAddAction(RB, function RB_Actions)
    set RB = null
endfunction
 
Level 17
Joined
Apr 27, 2008
Messages
2,455
JASS:
call TimerStart(udg_timer,0.10,true,function RB_Func002A)
you start the timer as periodic, use false instead.
and you should pause the timer before destroying it, or recycle timers (i dunno if the bugs with timers are actually true with the new patch or not)
 
Level 4
Joined
Jul 20, 2005
Messages
107
Sorry but i don't really understand what you mean o_O sorry for costing you so much trouble though..
 
Level 40
Joined
Dec 14, 2005
Messages
10,532
Troll-Brain, true is periodic, false is non-periodic.

Shyhalu, no idea where you got 'blizzard junction' from (seeing as it makes little sense), but it is generally speculated it stands for Blizzard.j or Blizzard Jass (Blizzard.j being the file all the BJ functions are found in)

You Win, AddLightningEx allows for Z coordinates too.

Also, you may still use locals, since

  • GetExpiredTimer() returns the calling timer in a timer callback function
  • You can use something like structs to "globally" pass your locals and retain MUI
 
Level 4
Joined
Jul 20, 2005
Messages
107
Troll-Brain, true is periodic, false is non-periodic.

Shyhalu, no idea where you got 'blizzard junction' from (seeing as it makes little sense), but it is generally speculated it stands for Blizzard.j or Blizzard Jass (Blizzard.j being the file all the BJ functions are found in)

You Win, AddLightningEx allows for Z coordinates too.

Also, you may still use locals, since

  • GetExpiredTimer() returns the calling timer in a timer callback function
  • You can use something like structs to "globally" pass your locals and retain MUI

How to make local to globally? o_O can show example?
And what is Z coordinates?

Thank you people very much for teaching =)
 
Level 17
Joined
Apr 27, 2008
Messages
2,455
well i'm to lazy to explain all the things, search for that (tutorials and the search tool) and read the jasshelper documetation in the pack, but i can post a solution.
first you need the jassnewgenpack.

create a trigger called CS Safety or whatever, convert it in jass and remplace the lines with that :

JASS:
library CSSafety // by Vexorian

globals
    private timer array T
    private integer N = 0
endglobals
//==========================================================================================
function NewTimer takes nothing returns timer
    if (N==0) then
        return CreateTimer()
    endif
 set N=N-1
 return T[N]
endfunction
//==========================================================================================
function ReleaseTimer takes timer t returns nothing
    call PauseTimer(t)
    if (N==8191) then
        debug call BJDebugMsg("Warning: Timer stack is full, destroying timer!!")
        call DestroyTimer(t)
    else
        set T[N]=t
        set N=N+1
    endif   
endfunction
endlibrary

create an other trigger, for example ReturnBug and do the same with that :
JASS:
library ReturnBug

    function H2I takes handle h returns integer
        return h
        return 0
    endfunction

endlibrary

  • init
    • Evénements
      • Map initialization
    • Conditions
    • Actions
      • Set MyCache = (Create a game cache from likeYouWant)
and finally your trigger :

JASS:
struct Rb
    unit caster
    unit target
    lightning l
    integer i
endstruct

function RB_Conditions takes nothing returns boolean
    return GetSpellAbilityId() == 'A000'
endfunction

function RB_Func002A takes nothing returns nothing
    local timer t = GetExpiredTimer()
    local string str = I2S(H2I(t))
    local Rb s = GetStoredInteger(udg_MyCache,str,"timer") // read the index of the strut
    local real x = GetUnitX(s.caster)
    local real y = GetUnitY(s.caster)
    local real x2 = GetUnitX(s.target)
    local real y2 = GetUnitY(s.target)
    if GetUnitState(s.caster, UNIT_STATE_LIFE) <= 0 and GetUnitState(s.target, UNIT_STATE_LIFE) <= 0 and s.i <= 50 and (x-x2)*(x-x2)+(y-y2)*(y-y2) <= 640000 then
        call MoveLightning(s.l,true,x,y,x2,y2)
        call SetLightningColor(s.l,GetRandomReal(0,1),GetRandomReal(0,1),1,1)
        call UnitDamageTarget(s.caster,s.target,10,true,false,ATTACK_TYPE_NORMAL,DAMAGE_TYPE_NORMAL,null)
        set s.i = s.i + 1
    else
        call DestroyLightning(s.l)
        call ReleaseTimer(t) // recycle timer
        call s.destroy() // destroy the struct
        call FlushStoredMission(udg_MyCache,str) //clean the cache
    endif
endfunction

function RB_Actions takes nothing returns nothing
    local Rb s = Rb.create() // create a struct
    local timer tim = NewTimer() // use a timer in pause or create a new timer
    
    set s.i = 0
    set s.caster = GetTriggerUnit()
    set s.target = GetSpellTargetUnit()
    set s.l = AddLightning("FORK",true,GetUnitX(s.caster),GetUnitY(s.caster),GetUnitX(s.target),GetUnitY(s.target))
    call StoreInteger(udg_MyCache,I2S(H2I(tim)),"timer",s) // link the timer and the struct
    
    call TimerStart(tim,0.10,true,function RB_Func002A)
endfunction

//=======================
function InitTrig_RB takes nothing returns nothing
    local trigger t = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
    call TriggerAddCondition(t, Condition(function RB_Conditions))
    call TriggerAddAction(t, function RB_Actions)
endfunction

The z is the height

@PurplePoot : my bad too, i thought it was an other thread

off-topic : the submission forum for the jass functions is dead or what ?!
 
Last edited:
Level 40
Joined
Dec 14, 2005
Messages
10,532
off-topic : the submission forum for the jass functions is dead or what ?!
I'm the only one who moderates it, currently, and my computer needs reformatting (just got a windows disk last night), so I only have access to a computer at school right now.

I should be able to mass-moderate this stuff starting somewhere between Tuesday and Thursday, if all goes well (Can't get on later today for other reasons).
 
Level 4
Joined
Jul 20, 2005
Messages
107
well i'm to lazy to explain all the things, search for that (tutorials and the search tool) and read the jasshelper documetation in the pack, but i can post a solution.
first you need the jassnewgenpack.

create a trigger called CS Safety or whatever, convert it in jass and remplace the lines with that :

JASS:
library CSSafety // by Vexorian

globals
    private timer array T
    private integer N = 0
endglobals
//==========================================================================================
function NewTimer takes nothing returns timer
    if (N==0) then
        return CreateTimer()
    endif
 set N=N-1
 return T[N]
endfunction
//==========================================================================================
function ReleaseTimer takes timer t returns nothing
    call PauseTimer(t)
    if (N==8191) then
        debug call BJDebugMsg("Warning: Timer stack is full, destroying timer!!")
        call DestroyTimer(t)
    else
        set T[N]=t
        set N=N+1
    endif   
endfunction
endlibrary

create an other trigger, for example ReturnBug and do the same with that :
JASS:
library ReturnBug

    function H2I takes handle h returns integer
        return h
        return 0
    endfunction

endlibrary

  • init
    • Evénements
      • Map initialization
    • Conditions
    • Actions
      • Set MyCache = (Create a game cache from likeYouWant)
and finally your trigger :

JASS:
struct Rb
    unit caster
    unit target
    lightning l
    integer i
endstruct

function RB_Conditions takes nothing returns boolean
    return GetSpellAbilityId() == 'A000'
endfunction

function RB_Func002A takes nothing returns nothing
    local timer t = GetExpiredTimer()
    local string str = I2S(H2I(t))
    local Rb s = GetStoredInteger(udg_MyCache,str,"timer") // read the index of the strut
    local real x = GetUnitX(s.caster)
    local real y = GetUnitY(s.caster)
    local real x2 = GetUnitX(s.target)
    local real y2 = GetUnitY(s.target)
    if GetUnitState(s.caster, UNIT_STATE_LIFE) <= 0 and GetUnitState(s.target, UNIT_STATE_LIFE) <= 0 and s.i <= 50 and (x-x2)*(x-x2)+(y-y2)*(y-y2) <= 640000 then
        call MoveLightning(s.l,true,x,y,x2,y2)
        call SetLightningColor(s.l,GetRandomReal(0,1),GetRandomReal(0,1),1,1)
        call UnitDamageTarget(s.caster,s.target,10,true,false,ATTACK_TYPE_NORMAL,DAMAGE_TYPE_NORMAL,null)
        set s.i = s.i + 1
    else
        call DestroyLightning(s.l)
        call ReleaseTimer(t) // recycle timer
        call s.destroy() // destroy the struct
        call FlushStoredMission(udg_MyCache,str) //clean the cache
    endif
endfunction

function RB_Actions takes nothing returns nothing
    local Rb s = Rb.create() // create a struct
    local timer tim = NewTimer() // use a timer in pause or create a new timer
    
    set s.i = 0
    set s.caster = GetTriggerUnit()
    set s.target = GetSpellTargetUnit()
    set s.l = AddLightning("FORK",true,GetUnitX(s.caster),GetUnitY(s.caster),GetUnitX(s.target),GetUnitY(s.target))
    call StoreInteger(udg_MyCache,I2S(H2I(tim)),"timer",s) // link the timer and the struct
    
    call TimerStart(tim,0.10,true,function RB_Func002A)
endfunction

//=======================
function InitTrig_RB takes nothing returns nothing
    local trigger t = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
    call TriggerAddCondition(t, Condition(function RB_Conditions))
    call TriggerAddAction(t, function RB_Actions)
endfunction

The z is the height

@PurplePoot : my bad too, i thought it was an other thread

off-topic : the submission forum for the jass functions is dead or what ?!

This JASS i don't really understand o_O the tutorial i read didn't teached this...
 
Level 4
Joined
Jul 20, 2005
Messages
107
So if i use jass global in script A, can i use it in script B?
Why do we use the jass global and not the normal udg_variable?
 
Level 17
Joined
Apr 27, 2008
Messages
2,455
So if i use jass global in script A, can i use it in script B?
Why do we use the jass global and not the normal udg_variable?
a private global can be used only in his library/scope.
It's better than a "normal" udg_variable cause it's really faster to declare and you don't need to change the name if it is private or public.
and you can declare any type of variable not as gui

JASS:
scope MyScope

   globals
      integer I // can be used everywhere
      private real R // can be used only in this scope
      public boolean B // can be used everywhere but that will be B inside MyScope and MyScope_B outside this scope
   endglobals

endscope
 
Status
Not open for further replies.
Top