• 🏆 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!

[JASS] Arc Jump

Status
Not open for further replies.
Level 29
Joined
Jul 29, 2007
Messages
5,174
I just tried making a simple arc movement with timers but I got kinda stuck since im a total noob in JASS.

The code is this (yes I know it does nothing and it sucks, you can laugh at me if you want)

JASS:
function Trig_Untitled_Trigger_002_Actions takes nothing returns nothing
    local real maxpower = DistanceBetweenPoints(GetUnitLoc(GetTriggerUnit()), GetSpellTargetLoc())
    local location l = GetSpellTargetLoc()
    local real a = x.l
    local real b = y.l
    local timer time
    local integer start = 1
    local integer end = 30
    loop
        exitwhen start > end
        set start = start + 1
    call SetUnitPositionLoc( GetTriggerUnit(), PolarProjectionBJ(GetUnitLoc(GetTriggerUnit()), 10.00, GetUnitFacing(GetTriggerUnit())) )
    call StartTimerBJ( time, true, 0.02 )
    endloop
endfunction
//===========================================================================
function InitTrig_Untitled_Trigger_002 takes nothing returns nothing
    set gg_trg_Untitled_Trigger_002 = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( gg_trg_Untitled_Trigger_002, EVENT_PLAYER_UNIT_SPELL_EFFECT )
    call TriggerAddAction( gg_trg_Untitled_Trigger_002, function Trig_Untitled_Trigger_002_Actions )
endfunction


Basicly what I wanted to do was making the unit "jump" untill the height is worth the distance beetwin point 1 and point 2, and then come down the same way.

Now the problem is, I don't know how to use timers for this, can I call functions from other triggers, so I can use a normal timer event ?

I don't really want you guys to make me the code since im doing this to learn how to use JASS, but hints and bits of code would be nice and helpfull :p
 
If you want to make an ARC jump, I think you should know something about mathematic equations for it, so it's not so simple.

To begin your JASSer career you should try to move a unit with timers - such as a missile does, but with units. It's a very useful knowledge.

EDIT: Ah by the way, functions should work like this:

JASS:
function TimerActions takes nothing returns nothing
    // Do Timer actions - whatever you want to do when the timer expires
endfunction
function TriggerActions takes nothing returns nothing
    // Initialize all locals and create the timer:
    local unit Whoever = GetTriggerUnit()
    local location Wherever = GetSpellTargetLoc()
    local timer T = CreateTimer()
    // Start the timer (don't use StartTimerBJ, it's designed to use in GUI.
    // This one is much more useful:
    call TimerStart( T, 0.02, true, function TimerActions )
    // The 'true' above makes the timer repeat every time it reaches 0
endfunction

Good luck \o/
 
Last edited:
Level 29
Joined
Jul 29, 2007
Messages
5,174
Hooah thanks !
I wonderd why would I need to use BJ (dunno what it means besides that it has something to do with GUI, maybe for Globals ?).

And thats exacly what I needed to call another function, thanks :)

Now, a second question :p

How would I refer to the local I set in the first function, in the second (timer) function ?
 
I wonderd why would I need to use BJ (dunno what it means besides that it has something to do with GUI, maybe for Globals ?).

BJ stands for Blizzard Jass. This was meant to be easier for Jass users to understand and write codes, but at the cost of several useful functionalities.
(PS: I think xD)

How would I refer to the local I set in the first function, in the second (timer) function ?

That's the trick... If you don't care about many units using the same ability at the same time, so you can use a global for each local.

But this way, if a second unit use the ability BEFORE the first one has finished casting it, it will be all messed up...

So people use Handle Local Vars (get it here: http://www.wc3jass.com/viewtopic.php?t=224). This way you can attach the locals in the timer and get them back after.
 
Oh I almost finished typing, and then I closed the tab by accident >.<
Ok, there I go again xD

A "handle" is everything except reals, integers, strings, booleans (maybe more, don't remember).
These handles you create, and they will exist until you destroy them. So, if you have a way to refer to them, you can do so whenever you want.

Create a glocal gamecache variable. Copy the huge code in the Custom Script section (the first thing in the triggers list) and, in the first function, replace InitGameCache(...) with udg_NameOfYourVariable.

Usage:

JASS:
function TimerActions takes nothing returns nothing
    local timer T = GetExpiredTimer() // The expired timer!
    local unit U = GetHandleUnit( T, "unit" )
    // Whatever...
    set T = null
    set U = null
endfunction

function TriggerActions takes nothing returns nothing
    local timer T = CreateTimer() // Timer is created
    local unit U = GetTriggerUnit()
    call SetHandleHandle( T, "unit", U ) // storing the unit U (a handle) in the timer T
    call TimerStart( T, 0.02, true, function TimerActions )
    set T = null
    set U = null
endfunction

What did I do above?
In the TriggerActions, I created the timer and , using SetHandleHandle, stored the unit inside the timer. Let's say I created a place called "unit" inside the timer T, and put the unit U there.
Then, to get U back, I used GetHandleUnit.

Got it?
Remember -- since you created a handle (timer), you'll need to destroy it when it's job is done. So if you want to move a unit until this unit die, check in the TimerActions if it's dead. If so, use call DestroyTimer to destroy it. Once destroyed, it will never fire anymore (as it no longer exists).

Note destroying the timer will not stop the execution of TimerActions.

Thank you for preference. Come back on Mondays, Tuesdays, Wednesdays... Err, come back xD
 
Last edited:
Level 29
Joined
Jul 29, 2007
Messages
5,174
Ok, I basicly made the "bullets" move to 1000 range and then die (with a expiration timer), the problem is... well it says "Expected a name" on my bullet local (called Summon), heres the code

Code:
        function Trig_MyTrigger_Conditions takes nothing returns boolean
    if ( not ( GetSpellAbilityId() == 'AUan' ) ) then
        return false
    endif
    return true
endfunction
function Trig_TimerActions takes nothing returns nothing
    local timer t = GetExpiredTimer()
    local unit summon = GetHandleHandle( t, "unit", summon )
    call SetUnitPositionLoc( summon, PolarProjectionBJ(GetUnitLoc(summon), 10.00, GetUnitFacing(summon)) )
    set t = null
    set summon = null
endfunction
function Trig_MyTrigger_Actions takes nothing returns nothing
    local timer t = CreateTimer()
    local unit u = GetTriggerUnit()
    local unit summon
    call CreateNUnitsAtLoc( 1, 'hfoo', GetOwningPlayer(u), GetUnitLoc(u), GetUnitFacing(u) )
    set summon = GetLastCreatedUnit()
    call UnitApplyTimedLifeBJ( 2.00, 'BTLF', summon )
    call SetHandleHandle( t, "unit", summon )
    call TimerStart( t, 0.02, true, function TimerActions )
    call TriggerSleepAction( 2 )
    call DestroyTimer(t)
    set t = null
    set u = null
    set summon = null
endfunction

//===========================================================================
function InitTrig_MyTrigger takes nothing returns nothing
    set gg_trg_MyTrigger = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( gg_trg_MyTrigger, EVENT_PLAYER_UNIT_SPELL_EFFECT )
    call TriggerAddCondition( gg_trg_MyTrigger, Condition( function Trig_MyTrigger_Conditions ) )
    call TriggerAddAction( gg_trg_MyTrigger, function Trig_MyTrigger_Actions )
endfunction


[Edit] Ok I changed the actions trigger name to its name (lol didn't notice its MyTrigger_Actions without the Trig_) and now the error moved to the handles

"local unit summon = GetHandleHandle( t, "unit", summon )" - expected a name

From this I can guess I did some mistake with implanting the handles ?
I just copied them into my header, created a game cache variable and change the name there to my variable.
Should I set my variable to "last created game cache" (only option) ?

[Edit2] Hmmm didn't work.
Only made more compile errors lol.

[Edit3] w00t my code is gone in the post ?

Put it in code tags since jass tags stopped working lol.
 
Last edited:
Level 13
Joined
Nov 22, 2006
Messages
1,260
Here's where I hop in with a couple of linkies:
Well, that's all for now, once you go through those, things will be a lot clearer :)

BJ stands for Blizzard Jass. This was meant to be easier for Jass users to understand and write codes, but at the cost of several useful functionalities.
(PS: I think xD)

Well, some of them are actually made because some direct uses of natives didn't work, so wrappers had to be created. For example, this retarded function:

JASS:
function GetIssuedOrderIdBJ takes nothing returns integer
    return GetIssuedOrderId()
endfunction


They could've just put GetIssuedOrderId() directly, but that didn't work (God knows why).

A "handle" is everything except reals, integers, strings, booleans (maybe more, don't remember).

.....and code (people often forget that since it doesn't exist as a variable type in GUI).

These handles you create, and they will exist until you destroy them. So, if you have a way to refer to them, you can do so whenever you want.

Not all handles have to be destroyed since not all handles are actual handles, they are just integers. Examples of not-really-handles: attacktype, damagetype, weapontype, eventid..........and many more.

Err.....

local unit summon = GetHandleHandle( t, "unit", summon )

Should be GetHandleUnit and remove that last parameter. It's not your fault, Hossomi made a mistake (happens to the best of us Hossomi). So the correct version of this would be:

local unit summon = GetHandleUnit( t, "unit" )

If you look closer to the handle vars GetHandle functions, you would notice they only take two parameters.

Your trigger's leaking a whole lot, GhostWolf, and you have unncecessary BJs. CreateNUnitsAtLoc can be replaced with CreateUnit when creating a single unit, if there are more, you can use loops. You can also use coordinates instead of locations, they makes things simpler, more efficient and prettier.

The main point about timers is that you don't use TriggerSleepAction. There is a cool integer system that's good for avoiding TriggerSleepAction, you'll see later. It's not hard to understand it, with a little thinking, you'll figure it out. Just note that if there are no attached stuff, GetHandleSomething returns null for handles, 0 for integers, 0.00 for reals, "" for strings and false for booleans.

Pay attention what GetLastCreatedUnit() returns, things may become clearer what last created really is.

You have to flush the timer when attaching stuff to it, you have to do that before destroying it.The function for that is FlushHandleLocals.

For the unit movement (in the Trig_TimerActions function) you can use coordinates, maybe looks complicated at the start, but that's just trigonometry. You can look at this function if it's easier to understand:

JASS:
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


Trig_MyTrigger_Conditions function is very inefficient because it uses a very impractical use of if/then/else. I made it more efficient, you can check it out.

I practically just replaced this function with natives.

The improved version of your code would be:

JASS:
function Trig_MyTrigger_Conditions takes nothing returns boolean
    return GetSpellAbilityId() == 'AUan'
endfunction
function Trig_TimerActions takes nothing returns nothing
    local timer t = GetExpiredTimer()
    local unit summon = GetHandleUnit( t, "unit" )
    local integer i = GetHandleInt( t, "i" )
    local real a = GetUnitFacing(summon) * bj_DEGTORAD
    local real x = GetUnitX(summon) + 10 * Cos(a)
    local real y = GetUnitY(summon) + 10 * Sin(a)
    call SetUnitPosition( summon, x, y )
    if i >= 100 then
        call FlushHandleLocals(t)
        call DestroyTimer(t)
    else
        call SetHandleInt(t, "i", i + 1)
    endif
    set t = null
    set summon = null
endfunction
function Trig_MyTrigger_Actions takes nothing returns nothing
    local timer t = CreateTimer()
    local unit u = GetTriggerUnit()
    local unit summon
    local real x = GetUnitX(u)
    local real y = GetUnitY(u)
    set summon = CreateUnit(GetOwningPlayer(u), 'hfoo', x, y, GetUnitFacing(u))
    call UnitApplyTimedLife( summon, 'BTLF', 2.00 )
    call SetHandleHandle( t, "unit", summon )
    call TimerStart( t, 0.02, true, function TimerActions )
    set t = null
    set u = null
    set summon = null
endfunction

//===========================================================================
function InitTrig_MyTrigger takes nothing returns nothing
    set gg_trg_MyTrigger = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( gg_trg_MyTrigger, EVENT_PLAYER_UNIT_SPELL_EFFECT )
    call TriggerAddCondition( gg_trg_MyTrigger, Condition( function Trig_MyTrigger_Conditions ) )
    call TriggerAddAction( gg_trg_MyTrigger, function Trig_MyTrigger_Actions )
endfunction



I hope that helped a bit ;)
 
Level 29
Joined
Jul 29, 2007
Messages
5,174
Those tut's really helped me (and helping... still reading lol), thanks.

Another problem is that I don't know much about sin's/cos's and those kind of math stuff.
I also don't really know any math equations... sadly im stupid lol.

Anyways, I tried adding a code that checks if the terrain changes from the position of "summon" to the next position it will move to.
If the terrain gets lower, make summon fly (so he actualy stays at the same height from the eyes of the player), if the terrain is higher - kill him and end the trigger.
It goes like this

Code:
    local real x = GetUnitX(summon) + 10 * Cos(a)
    local real y = GetUnitY(summon) + 10 * Sin(a)
    local real b = GetUnitX(summon)
    local real c = GetUnitY(summon)
    local integer d = GetTerrainCliffLevel( x,y)
    local integer e = GetTerrainCliffLevel( b,c)
    if e-d>=1 then
        call SetUnitFlyHeight(summon,(e-d)*128,10000) 
    else if e-d<=-1 
        call KillUnit(summon) 
        call DestroyTimer(t)
        set t = null
        set summon = null
        return
    endif


Now as you can guess, the editor didn't like my "else if"s, how am I supposed to write them ?

[Edit] BLARG ! again the JASS tags didn't want to be big ...

[Edit2] Wow im stupid, declaring a local unit which tries to work on local x,y which weren't create yet... this took my compile errors from about 22 to 3 (still my "else ifs").

Remove yet another stupid mistake, up to 2 compile errors that concern my "else if"

else if e-d <= -1 - expected end of line (err?).
endif- expected 'endif' - hmmm... I wonder why "endif" expects "endif" ?
 
Last edited:
the "else" and the "if" is written together, like this: [/icode]elseif[/icode] ^^

About the sin and cos, it's a geometrical relation. Imagine a triangle with one 90º angle (don't know the name in English xD)

|\
|..\
|....\
|____\a

(Imagine we want to move from the point where the angle 'a' is to the top vertex of the triangle. So the green line is the distance you'd use in the GUI function)

First, we have to convert the angle 'a' to radians. To do so, we multiply it by bj_DEGTORAD (the real value is pi/180)

Then, the Cos of the result multiplied by the distance equals to the X Distance, and the Sin of the result multiplied by the distance equals to the Y Distance.

Got it? xD
 
Level 29
Joined
Jul 29, 2007
Messages
5,174
Im so stupid, I asked this then went to bed, then after about 5 seconds I was like "what the hell, if endif is endif then else if is probably elseif", guess I was right :p

*reading your explenation*

[Edit] actually it didn't like my elseif, it made me to make it like this (WTF no compile errors !?!?!?)

Code:
    if e-d>=1 then
        call SetUnitFlyHeight(summon,(e-d)*128,10000.00)
    else
        if e-d <= -1 then
            call KillUnit(summon) 
            call DestroyTimer(t)
            set t = null
            set summon = null
            return
        endif
    endif


Can someone tell me why my JASS tags never show my code and only show one line of it ?

By the way, Vexorian suggested on making my own 2 functions for polar projection (one for getting X and one for Y) and then calling both of them.
Is it more efficient then Silvenon's code ?

Hmm, on a second though I guess not because its calling 2 other functions for no reason.
Why did you make that "local a" though ? could just put it in the x,y without making it a local - didn't work, another compile error lol.

[Edit] ok, it doesn't move the unit, only creates it and kills it after 2 seconds.
This is the full code

Code:
function Trig_MyTrigger_Conditions takes nothing returns boolean
    return GetSpellAbilityId() == 'A000'
endfunction
function TimerActions takes nothing returns nothing
    local timer t = GetExpiredTimer()
    local unit summon = GetHandleUnit( t, "unit" )
    local integer i = GetHandleInt( t, "i" )
    local real a = GetUnitFacing(summon) * bj_DEGTORAD
    local real x = GetUnitX(summon) + 10 * Cos(a)
    local real y = GetUnitY(summon) + 10 * Sin(a)
    local real b = GetUnitX(summon) // start of terrain height part
    local real c = GetUnitY(summon)
    local integer d = GetTerrainCliffLevel( x,y)
    local integer e = GetTerrainCliffLevel( b,c)
    local real f = GetUnitDefaultFlyHeight(summon)
    if e-d>=1 then
        call SetUnitFlyHeight(summon,f+(e-d)*128,10000.00)
    else
    if e-d <= -1 then
        call KillUnit(summon) 
        call DestroyTimer(t)
        set t = null
        set summon = null
        return
    endif
    endif  // end of terrain height part
    call SetUnitPosition( summon, x, y )
    if i >= 100 then
        call FlushHandleLocals(t)
        call DestroyTimer(t)
    else
        call SetHandleInt(t, "i", i + 1)
    endif
    set t = null
    set summon = null
endfunction
function Trig_MyTrigger_Actions takes nothing returns nothing
    local timer t = CreateTimer()
    local unit u = GetTriggerUnit()
    local real a = GetUnitFacing(u) * bj_DEGTORAD
    local real x = GetUnitX(u) + 50 * Cos(a)
    local real y = GetUnitY(u) + 50 * Sin(a)
    local unit summon = CreateUnit(GetOwningPlayer(u), 'h000', x, y, GetUnitFacing(u))
    call UnitApplyTimedLife( summon, 'BTLF', 2.00 )
    call SetHandleHandle( t, "unit", summon )
    call TimerStart( t, 0.02, true, function TimerActions )
    set t = null
    set u = null
    set summon = null
endfunction

//===========================================================================
function InitTrig_MyTrigger takes nothing returns nothing
    set gg_trg_MyTrigger = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( gg_trg_MyTrigger, EVENT_PLAYER_UNIT_SPELL_EFFECT )
    call TriggerAddCondition( gg_trg_MyTrigger, Condition( function Trig_MyTrigger_Conditions ) )
    call TriggerAddAction( gg_trg_MyTrigger, function Trig_MyTrigger_Actions )
endfunction


Man, im so happy I got JassCraft for the all this natives and functions list ! even though they don't work for me... but thats my problem not JassCraft's :p

Why do we need to change from degree's to radians ? what ARE radians ?

[Edit] I saw this thread with a guy asking about his item-stacking system so I took on myself (not for him, just to try ^^) to make one.

As you can already guess, it doesn't work.
Beside the problem I wrote inside, it didn't work also when it should have worked.
Heres the code

Code:
function Trig_Untitled_Trigger_003_Conditions takes nothing returns boolean
    return GetItemType(GetManipulatedItem()) == ITEM_TYPE_CHARGED
endfunction
function Trig_Untitled_Trigger_003_Actions takes nothing returns nothing
    local unit u = GetTriggerUnit()
    local item i = GetManipulatedItem()
    local item i2
    local integer int = GetItemCharges(i)
    local integer int2
    local integer a = 0 // if I won't set it to 0, will it automaticly be 0 ?
    loop
       exitwhen a==6
       set a = a+1
       if GetItemTypeId(GetManipulatedItem()) == GetItemTypeId(UnitItemInSlot(u, a)) then
       set i2 = UnitItemInSlot(u,a)
       set int2 = GetItemCharges(i2)
       endif
       if int2 == 6 then
         return
       else
         loop
           exitwhen int==0 // problem, what if for example its int=5 and int2=3 - int will never be worth 0
             set int = int-1
             set int2 = int2+1
             call SetItemCharges(i, int)
             call SetItemCharges(i2, int2)
         endloop
       endif
    endloop
    set u = null
    set i = null
    set i2 = null
endfunction
//===========================================================================
function InitTrig_Untitled_Trigger_003 takes nothing returns nothing
    set gg_trg_Untitled_Trigger_003 = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( gg_trg_Untitled_Trigger_003, EVENT_PLAYER_UNIT_PICKUP_ITEM )
    call TriggerAddCondition( gg_trg_Untitled_Trigger_003, Condition( function Trig_Untitled_Trigger_003_Conditions ) )
    call TriggerAddAction( gg_trg_Untitled_Trigger_003, function Trig_Untitled_Trigger_003_Actions )
endfunction


Im telling you, this freaking JASS tags hate me -.-
 
Last edited:
Level 13
Joined
Nov 22, 2006
Messages
1,260
By the way, Vexorian suggested on making my own 2 functions for polar projection (one for getting X and one for Y) and then calling both of them.
Is it more efficient then Silvenon's code ?

You can do that, but using natives directly is more efficient. You can use those if you really can't do that directly:

JASS:
function PolarProjectionX takes real x, real d, real a returns real
    return x + d * Cos(a * bj_DEGTORAD)
endfunction

JASS:
function PolarProjectionY takes real y, real d, real a returns real
    return y + d * Sin(a * bj_DEGTORAD)
endfunction


I made it so you can put degrees as parameter for a.

You don't HAVE to understand that sin and cos, you just memorize it the way it is. That's what I did in the start.

I don't know why your code doesn't work, try with simpler things.

Why do we need to change from degree's to radians ? what ARE radians ?

Just memorize it like this:

Degrees: Radians * bj_RADTODEG
Radians: Degrees * bj_DEGTORAD

That's how you convert them.

Now, a tip how to use those PolarProjectionX/PolarProjectionY functions:

JASS:
function DoSomething takes nothing returns nothing
    local unit u = CreateUnit(....)
    local real x = GetUnitX(u)
    local real y = GetUnitY(u)
    local real d = 100
    local real a = GetUnitFacing(u) // note that this is in DEGREES
    local real px = PolarProjectionX(x, 100, a)
    local real py = PolarProjectionY(y, 100, a)
    call SetUnitPosition(u, px, py)
    set u = null
endfunction


EDIT: You would need to have those two functions in your map header......
 
Level 29
Joined
Jul 29, 2007
Messages
5,174
Lol, tried to change a lot of things, even tried using the Handle vars to attach all my locals (unit,facing degrees,new x,new y) and using them, still didn't work.

No idea why it doesn't want to work ? lol.

(By the way, you've got any comment on my item thingy ? :p)
 
Level 21
Joined
Aug 21, 2005
Messages
3,699
local integer a = 0 // if I won't set it to 0, will it automaticly be 0 ?
Nope. If you use an uninitialised variable, it'll give an error.

if GetItemTypeId(GetManipulatedItem()) == GetItemTypeId(UnitItemInSlot(u, a)) then
you declared a variable that contains the manipulated item... Use it..

--> if GetItemTypeId(i) == GetItemTypeId(UnitItemInSlot(u, a)) then
if int2 == 6 then
return

return? return what?

loop
exitwhen int==0 // problem, what if for example its int=5 and int2=3 - int will never be worth 0
set int = int-1
set int2 = int2+1
call SetItemCharges(i, int)
call SetItemCharges(i2, int2)
endloop
so... what's this supposed to do?
 
Level 29
Joined
Jul 29, 2007
Messages
5,174
Nope. If you use an uninitialised variable, it'll give an error.

Weird, didn't give me any compile errors.


--> if GetItemTypeId(i) == GetItemTypeId(UnitItemInSlot(u, a)) then
return? return what?

This is just to stop the function from continuing to work.
Now that I look at it again it would stop me from nulling at the end, is there any way to jump there ?

so... what's this supposed to do?

It removes one charge from the item acquired and adds one to the item that already was in the inventory.
 
Level 21
Joined
Aug 21, 2005
Messages
3,699
Weird, didn't give me any compile errors.
In-game it'll give an error. Just try to do this:
local integer a
local integer b = 1 + a

then call the function, it'll say something like "uninitialised integer a"

This is just to stop the function from continuing to work.
Now that I look at it again it would stop me from nulling at the end, is there any way to jump there ?

There's always a way to do something like this. The easiest one is:
local boolean b = false
// blabla
if GetItemTypeId(i) == GetItemTypeId(UnitItemInSlot(u, a)) then
set b = true
endif
if b = false
// do the rest
endif
null your variables.


In this case it's even better to say:
if int2 <6 do
// your loop
endif


exitwhen int==0 // problem, what if for example its int=5 and int2=3 - int will never be worth 0
what's the problem?

Finally, why don't you just remove the (Item being manipulated) and add 1 charge (or the amount of charges on item being manipulated) to the item you "discovered"?
 
Level 21
Joined
Aug 21, 2005
Messages
3,699
You made a few mistakes..

1) Inventory space ranges from 0 to 5.
If you do
JASS:
loop      
    exitwhen a==6      
    set a = a+1     
    if GetItemTypeId(manipulated) == GetItemTypeId(UnitItemInSlot(u, a)) then
a will be ranging from 1 to 5, since you already set a = 1 before you check anything else. Always try to put
set a = a + 1
1 line before
endloop

JASS:
     call CreateItem(S2I(s),x,y)      
set first = GetLastCreatedItem()
This one is not really a mistake, but it's faster (and easier) to do
JASS:
 set first = CreateItem(S2I(s), x, y)
The CreateItem function returns an item, which means you can assign an itemvariable to the CreateItem function.
^^ that works for any function with a return value other than "nothing".

I don't have enough experience with jass myself (heh, I started 1 week before you or something :p), but I don't think I2S works for items... mainly because
GetItemName(manipulated) probably returns the actual item NAME (e.g. "Boots of Speed").
CreateItem requires the item ID, which is an integer. To find this integer in the object editor, select an item and press cntrl + D. In the case of boots of speed you'll see 'bspd'. It might look like a string, but it's actually a number with I don't know, 64 different digits instead of 10 (like in the decimal numbers). If you want to create an item using this raw data, you must put the integer in single quotation marks.
e.g.
JASS:
set first = CreateItem('bspd', x, y).

Ofcourse, you want to make a dynamic system, so you should be able to find the item ID of (item being manipulated). To do so, use the GetItemTypeId(item) function.

Next mistake (I think - again, I'm a newby too) is that you null all variables after looping. You should null them at the end of an iteration.
For example:

JASS:
loop
    exitwhen a > 5
    // do your stuff
    set manipulated = null
    set blabla = null
endloop
set u = null // notice that you don't actually CHANGE 'u' inside the loop, so you need to null it after "endloop".
Almost done: I fail to understand why you're creating new items...
You have 1 item: the item being manipulated.
You find a second item: the item of the same type in the inventory.
Rather than removing both and creating 1 or 2 new items (depending on the situation), just set the charges of (Item being manipulated) = totalcharges and remove the second item (in case you're below the max. charges) OR set the charges of (item being manipulated) = maxcharges and second item charges to (totalcharges - maxcharges)

Finally: you have made a very important mistake: you don't check whether the item you found in the inventory is the SAME item as the item being manipulated.
Let's say your inventory is empty;
you pick up an item with 4 charges.
The trigger runs, knows item being manipulated has 4 charges) and detects a SECOND item in inventoryslot 1... Only... it's actually the same item.
Total charges: 8.
Congratulations, you've doubled your amount of charges. In fact, you created a second item with 2 charges (assuming the max. amount of charges is 6), and the loop hasn't ended yet.
The loop continues. Oh, a THIRD item with 2 charges is detected. Only, this third item is the one you just created with 2 charges, so it suddenly has 6 charges :p

You can fix this by checking whether the slot in which item being manipulated is is NOT the same as integer a.
 
Level 29
Joined
Jul 29, 2007
Messages
5,174
Hmmm, nice corrections didn't notice most of it.
About the creating items, I know its stupid, I just wanted to make the code as simple and stupid as possible untill it actually works.

About the item ID, I was really confused what actions I should put there, now I know :D

Oh well, since I must go untill tommarows night ill check it then.

(nontopic - funny we both talk like in a chat in both GUI and JASS forums ^^)
 
Level 29
Joined
Jul 29, 2007
Messages
5,174
Started to work now, still buggy but ill try to sort it out.

Now I was really curious as to why we need all this hard ways to move locals from one function to another when we can do something like this (this is the moving trigger that sadly doesn't work):

Code:
function Trig_MyTrigger_Conditions takes nothing returns boolean
    return GetSpellAbilityId() == 'A000'
endfunction
function TimerActions takes [COLOR="Red"]summon [/COLOR]returns nothing
    local timer t = GetExpiredTimer()
    local real a = GetUnitFacing(summon) * bj_DEGTORAD
    local real x = GetUnitX(summon) + 10 * Cos(a)
    local real y = GetUnitY(summon) + 10 * Sin(a)
    call SetUnitPosition( summon, x, y )
    call DestroyTimer(t)
    set t = null
    set summon = null
endfunction
function Trig_MyTrigger_Actions takes nothing returns nothing
    local timer t = CreateTimer()
    local unit u = GetTriggerUnit()
    local real x = GetUnitX(u)
    local real y = GetUnitY(u)
    local unit summon = CreateUnit(GetOwningPlayer(u), 'h000', x, y, GetUnitFacing(u))
    call UnitApplyTimedLife( summon, 'BTLF', 2.00 )
    call TimerStart( t, 0.02, true, function TimerActions )
    set t = null
    set u = null
    set summon = null
endfunction

//===========================================================================
function InitTrig_MyTrigger takes nothing returns nothing
    set gg_trg_MyTrigger = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( gg_trg_MyTrigger, EVENT_PLAYER_UNIT_SPELL_EFFECT )
    call TriggerAddCondition( gg_trg_MyTrigger, Condition( function Trig_MyTrigger_Conditions ) )
    call TriggerAddAction( gg_trg_MyTrigger, function Trig_MyTrigger_Actions )
endfunction


After all, isn't this the propose of "Takes" ?

[Edit]

Works ! :D

Here's the code and I attached map (not that you really care about it :p)

Code:
function Trig_Untitled_Trigger_004_Conditions takes nothing returns boolean
    return GetItemType(GetManipulatedItem()) == ITEM_TYPE_CHARGED
endfunction
function Trig_Untitled_Trigger_004_Actions takes nothing returns nothing
    local unit u = GetTriggerUnit()
    local item manipulated = GetManipulatedItem()
    local item inventory
    local integer manipulatedcharges = GetItemCharges(manipulated)
    local integer inventorycharges
    local integer totalcharges
    local integer a = 0
    loop
     exitwhen a==6
    if GetItemTypeId(manipulated) == GetItemTypeId(UnitItemInSlot(u, a)) then
     set inventory = UnitItemInSlot(u, a)
     set inventorycharges = GetItemCharges(inventory)
     set totalcharges = inventorycharges + manipulatedcharges
    endif
    if inventorycharges != 6 then
    if UnitItemInSlot(u,a) == manipulated then
     set u = null
     set manipulated = null
     set inventory = null
     return
    endif
    if totalcharges > udg_maxcharges then // declared a global in another trigger
     call SetItemCharges(inventory,udg_maxcharges)
     call SetItemCharges(manipulated,(totalcharges-udg_maxcharges))
    else
     if totalcharges <= udg_maxcharges then
      call SetItemCharges(inventory,totalcharges)
      call RemoveItem(manipulated)
     endif
    endif  
    endif
    set inventory = null
    set a = a+1
    endloop
    set manipulated = null
    set u = null
endfunction

//===========================================================================
function InitTrig_Untitled_Trigger_004 takes nothing returns nothing
    set gg_trg_Untitled_Trigger_004 = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( gg_trg_Untitled_Trigger_004, EVENT_PLAYER_UNIT_PICKUP_ITEM )
    call TriggerAddCondition( gg_trg_Untitled_Trigger_004, Condition( function Trig_Untitled_Trigger_004_Conditions ) )
    call TriggerAddAction( gg_trg_Untitled_Trigger_004, function Trig_Untitled_Trigger_004_Actions )
endfunction
 

Attachments

  • Whatever.w3x
    23.9 KB · Views: 35
Level 21
Joined
Aug 21, 2005
Messages
3,699
function TimerActions takes summon returns nothing

You must take a variable TYPE and have an identifier 'linked' to it.
For instance:
JASS:
function TimerActions takes unit summon returns nothing
Inside the function, everytime you use 'summon', it'll refer to the unit you 'took'.

So you can do something like this:
call TimerActions(mycoolunit)

inside the timeractions function, everywhere you use "summon", it'll refer to mycoolunit
 
Yes. BTW, that's why your moving function does not work. I think it'll not pass syntax check, once you can't pass the parameters to the second function inside TimerStart.

If you want to see if it works, without being MUI, create a unit global variable and, in TriggerActions, set the global = summon.

In TimerActions, use the global instead of summon (and remove the "takes summon")
 
Level 29
Joined
Jul 29, 2007
Messages
5,174
I didn't put it in the real code, just put it now as an example for the question.

Anyway I did what you told me to check really whats the problem.
I came up with only one answer - I didn't implant the Local Vars correctly.

I still can't understand how to do it, what I have now is this

JASS:
// ===========================
function H2I takes handle h returns integer
    return h
    return 0
endfunction

// ===========================
function LocalVars takes nothing returns gamecache
    // Replace InitGameCache("jasslocalvars.w3v") with a global variable!!
    return udg_Game_Catche
endfunction

function SetHandleHandle takes handle subject, string name, handle value returns nothing
    if value==null then
        call FlushStoredInteger(LocalVars(),I2S(H2I(subject)),name)
    else
        call StoreInteger(LocalVars(), I2S(H2I(subject)), name, H2I(value))
    endif
endfunction

........


Is that global there right ? it seemed the right thing by reading the comment.
 
Ah I think I forgot to tell you something
At map initialization (any trigger with that event), you must do:

  • Actions
    • Game Cache - Create a game cache from (whatever)
    • Set Game_Cache = Last Created Game Cache
    • Game Cache - Clear Game_Cache
I mean, create a game cache and store it in the global variable =P
Or you may change the function LocalVars to:

JASS:
function LocalVars takes nothing returns gamecache
    if udg_Game_Catche == null then
        call FlushGameCache( InitGameCache("Whatever") )
        set udg_Game_Catche = InitGameCache("Whatever")
    endif
 return udg_Game_Catche
endfunction

I think that making a trigger that initializes the game cache, since you'd be avoiding an IF statement everytime you use handle locals =P
 
Level 29
Joined
Jul 29, 2007
Messages
5,174
What the hell ?!

I didn't get what map I should put in the game cache so I finaly used my mind (yea thats special with me) and looked at another map that I used the Hande Vars with (didn't even know what they do then lol).

Now there, I didn't change ANYTHING, didn't make any game cache variable or nothing, and it works ... err ????
 
Level 13
Joined
Nov 22, 2006
Messages
1,260
Maybe somebody made a vJass global game cache, like this:

JASS:
globals
    gamecache gc
endglobals


That's possible, you know....

Or it's some other kind of Handle Vars........something is not right if you didn't have to create a gamecache global.
 
Level 29
Joined
Jul 29, 2007
Messages
5,174
I just copied Kattana's code.

Now I made my "bullet system" set the bullet's height according to the target of ability.

If for example you targeted a place with a Z that is 100 more then yours, it will set the units height to +1 (since you/I made it move 100 times).
This works great, expect when it gets to cliffs.
My unit has 0 collision and is a flying unit but he is still flying over the cliff and he can't collid into the cliff (which is what I want, I basicly want the bullets to be able to collid with terrain and die when they do).

[Edit] for some reason it does't raise the bullet's height.

Thecode goes like this

Code:
// this part is when the unit casts
local location loc = GetSpellTargetLoc() // couldn't find any command for using x,y , is there one ? 
local real raiseheight = GetLocationZ(loc) / 100
call SetHandleReal( t, "raiseheight", raiseheight )
Code:
// this part is in the timer actions
local real raiseheight = GetHandleReal(t, "raiseheight" )
local real currentheight = GetUnitFlyHeight(summon)
call SetUnitFlyHeight( summon, raiseheight+currentheight, 100)
 
Last edited:
Level 13
Joined
Nov 22, 2006
Messages
1,260
// couldn't find any command for using x,y , is there one ?

Nope, we usually do it like this:

JASS:
local location l = GetSpellTargetLoc()
local real x = GetLocationX(l)
local real y = GetLocationY(l)


Er.....your raiseheight will be very low, I think, even unnoticeable. You have that in mind, do you?

I think (SOMEBODY CORRECT ME IF I'M WRONG!) that GetUnitFlyHeight returns the flying height of the unit plus the GetLocationZ of that unit's position. So you would probably have to subtract GetLocationZ to get the real height of the unit (because SetUnitFlyHeight sets the flying height plus GetLocationZ of that position).
 
I made a bullet system a short time ago (with arrows), and it took me really a long time to get it to work (-_-)

I think GetUnitFlyHeight does not return the Flying Height plus the location Z, since I had to subtract the location Z from the previous flying height of the projectile when it came over a cliff.

You need to check the difference between the LocationZ of the current position and the one of the next position, and subtract this difference from the current Fly Height. Then add the increment.

It's not so easy like that xD
Good luck, just some tips now because I'm in a hurry here, sorry
 
Status
Not open for further replies.
Top