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!
Oh, I think I've seen it in some tutorial, by the way, when trying to trigger something with:
JASS:
function Example takes unit returns nothing
endfunction
Is this:
JASS:
function Example takes unit('A000') returns nothing
endfunction
Different from this?
JASS:
function Example takes unit returns nothing
call CreateUnit('A000')
endfunction
I'm really sorry... But I'm quite confused. Also, if any of you know of anymore programming languages for Warcraft III besides the ones stated, please inform me, thank you
you cannot do that I think... unit is an object, 'A000' is an integer...
plus the takes part, takes a parameter to be used by the function
JASS:
function Example takes unit a returns nothing
call KillUnit(a)
//This would kill the unit passed onto this function
endfunction
function Init takes nothing returns nothing
call Example(MyHero)
//Doing this would pass the unit MyHero to the function Example, so MyHero would be killed
endfunction
function Init2 takes nothing returns nothing
call Example(MyHero2)
//now this would kill MyHero2
endfunction
IDK why, but this seems to be getting nowhere...
maybe you should start by doing triggers in GUI and then convert it into JASS, then study the resulting function...
Because you seem a bit lost on functions, I shall post up chapter 7 from my secret tut : |
Chapter 7- Functions
What is a Function?
A function is like a task in programming. When a function is called (run), the function performs that task. Functions may have any amount of lines of code, including 0 lines, (as complicated a task as you want) and may even perform multiple tasks.
Functions are the only way to run maps. Looking back at the GUI layout:
Events:
Conditions:
Actions:
Functions would be what's put into the actions category.
Functions can take parameters (like the numbers plugged into a calculator) and return a single value.
Because functions take values and return a value, some extra stuff is required in the first part of the function block. The function block layout reads: function (name) takes (something) returns (something)
The (name) portion is the label of the function, which is placed after the function keyword. The label is what is used when calling the function.
JASS:
function Label
endfunction
The takes keyword shows what values must be plugged into a function when running it. Takes uses a comma separated list of declared variables (these variables cannot be initialized since their values are plugged into the function): takes real x, integer y, boolean b
JASS:
function Label takes real x, integer y, boolean b
endfunction
Each variable declared in takes is associated to the value that is plugged into the function when it is run. For example, the first value put into a function would be the first variable declared in takes.
Whenever the Label function is run, it creates whatever variables are declared in takes for itself. When it ends, it destroys those variables. In this case, 3 variables would be declared every time Label is run
JASS:
Label
real x
integer y
boolean b
Those variables would be initialized to whatever values are passed into Label when it is run (order matters). Whenever calling Label, 3 values would have to be passed in, the first one being a real, the second one being an integer, and the third one being a boolean (values**). This means that if 3.3, 5, and true were passed into the Label function, it'd be akin to
JASS:
Label
real x = 3.3
integer y = 5
boolean b = true
Functions are run using the call keyword.
call MyFunction
Values are passed in by grouping them into () with a comma separated list. Even if a function doesn't take anything, the () must be used.
call MyFunction()
To run the Label function from before (remember Label tales a real, integer, and boolean): call Label(3.3, 5, true)
Three values must always be passed in because Label takes 3 arguments. This wouldn't be legal call Label(3.3, 5)
If Label didn't take anything call Label()
Calls can only be done within functions.
The returns keyword shows the type of variable a function returns: returns real
JASS:
function Label takes real x, integer y, boolean b returns real
endfunction
The nothing keyword is used whenever a function takes nothing or returns nothing.
JASS:
function Label takes nothing returns nothing
endfunction
When a function is called, that function will always return a value, even if that value is nothing. No variable type can be set to nothing, so setting a variable to a function that returns nothing isn't possible.
Variables can be set to functions as if the functions were values (because a function always returns a value). Functions can also be plugged into functions as if they were values. Keep in mind that the type a function returns is the type of value a function is treated as.
When a function is used as a value, the call keyword is not used.
JASS:
real x
real y
set x = Label(5, 6, true) //the above example of Label is used
set y = Label(Label(7, 8, true), 16, true) //Label is passed into Label as a parameter.
//this wouldn't be legal as Label returns a real
//set y = Label(6.6, Label(7, 8, true), true)
//Remember the function is: function Label takes real x, integer y, boolean b returns real
//This means that the y in the function is being set to Label(7, 8, true).
//The y var in the function is an integer, and integer variables cannot store real values.
Function blocks cannot go into function blocks or global blocks (global blocks only store global variables) (functions only store lines of code)
Code can be written normally in a function block and the parameters can be used as regular variables within the function. A function can only call a function that is declared above it.
JASS:
function Label takes integer x returns nothing
endfunction
function Label2 takes integer y returns nothing
call Label(y)
endfunction
function Label3 takes nothing returns nothing
call Label2(3)
call Label4() //syntax error, Label4 is declared after Label3
endfunction
function Label4 takes nothing returns nothing
endfunction
The return keyword is used to return values. Return will immediately exit out of a function.
Using the Add example from before:
JASS:
//this function can only return values of type integer
function Add takes integer number1, number2 returns integer
return number1+number2
endfunction
//this function can only return values of type integer
function Add5And7 takes nothing returns integer
return Add(5, 7) //returns 5+7, which is 12
endfunction
If a function returns something, it must always return that something at the last line.
JASS:
function Add takes integer x, integer y returns integer
//syntax error because this function has to return an integer value
endfunction
function Add2 takes nothing returns notihng
call Add(5, 7)
endfunction
JASS:
function Add takes integer x, integer y returns integer
return 5.5 //syntax error because this function has to return an integer value. 5.5 is a real.
endfunction
function Add2 takes nothing returns notihng
call Add(5, 7)
endfunction
JASS:
function Bleh takes nothing returns nothing
endfunction
//Bleh is never called because there is a return above it. This will still cause a syntax error even though the function always returns a value. The last line of code for a function must always be a return
function Add takes integer x, integer y returns integer
return x+y
call Bleh() //line is never reached because of the return above
endfunction
function Add2 takes nothing returns notihng
call Add(5, 7)
endfunction
JASS:
function Bleh takes nothing returns nothing
endfunction
//this example does the exact same thing as the above, but it works.
function Add takes integer x, integer y returns integer
return x+y
call Bleh() //line is never reached because of the return above
return 0
endfunction
function Add2 takes nothing returns notihng
call Add(5, 7)
endfunction
A function that returns nothing may still have a return statement in it, but it doesn't need one. Returning nothing is just the return keyword by itself.
JASS:
function Bleh takes nothing returns nothing
return
endfunction
//this works too
function Bleh2 takes nothing returns nothing
return
call Bleh() //line never reached
endfunction
A function that takes only a single argument does not need a comma separated list.
JASS:
function Bleh takes integer x returns nothing
endfunction
Create a function called Add that takes an integer z and an integer z5 and returns a value. Make a function called Set that doesn't take anything and doesn't return anything.
Make it so that when Add is called, it returns the sum of z and z5 and two global integers whose values are 7 and 9. Make it so when Set is called, it sets the value of a third global integer value to Add and passes in the values of a global integer goo whose value is 16 and the value 4.
Make a function called Do that takes a real z. Set the z value to whatever it is times 5 and then return it divided by a global integer q that has a value of 8. Make it return z.
Make a function called DoDo that passes 4 into Do and passes the result of Do into Print
JASS:
function Print takes real value returns nothing
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 90000, R2S(value))
endfunction
After creating the code, run the map and see what number it displays.
Check the solution to see if you did it right.
Output: 10
JASS:
globals
real q = 8
endglobals
function Do takes real z returns real
set z = z*5/q
return z
endfunction
function Print takes real value returns nothing
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 90000, R2S(value))
endfunction
function DoDo takes nothing returns nothing
call Print(Do(4))
endfunction
scope Display initializer init
private function init takes nothing returns nothing
call DoDo()
endfunction
endscope
I'm really really sorry... I just seem really confused at programming. But I won't mind, I'll just keep trying until I get it
Uhm... Are there other programming languages in Warcraft III too?
Well, you guys could do a little research so that you can better learn this stuff. I know some of the answers are in my old vjass guide on TH, like the order of operations in boolean expressions. Other answers can be found in common.j.
If you look at Event scripts as well as the TriggerRegister stuff, you can figure out how events run in JASS as well as the answers on conditions and actions.
If you read up on ExecuteFunc, especially concerning benchmarks, you'll learn why it is typically avoided.
If you look at SC2, you'll learn why strings are slow in wc3 ; P.
Etc etc
Yes, I know all the answers, but it's best to learn them on your own and discuss your findings so that they stick with you and so that you fully understand them ; D.
1. What are two methods for achieving recursive event data when creating custom events?
When events are run, data is normally associated with that event. GetTriggerUnit GetAttacker GetTriggerPlayer
When creating custom events, it is easy enough to do this
JASS:
globals
private trigger myEvent = CreateTrigger()
private integer data = 0
endglobals
function OnMyEvent takes boolexpr c returns nothing
call TriggerAddCondition(myEvent, c)
endfunction
function FireMyEvent takes integer d returns nothing
set data = d
call TriggerEvaluate(myEvent)
endfunction
function GetEventData takes nothing returns nothing
return data
endfunction
But this can result in a problem.
JASS:
function Test takes nothing returns boolean
local integer d = GetEventData() //d is now 1
if (d == 1) then
call FireMyEvent(2) //set d to 2
endif
if (d != GetEventData()) then
call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, "RECURSION ERROR!")
endif
return false //to prevent trigger actions from being run for no reason
endfunction
function Init takes nothing returns nothing
call OnMyEvent(Condition(function test))
call FireMyEvent(1) //data is now 1
endfunction
In events, event data should always be the same data as it was when the event first fired. In the above scenario, the data was first 1 but then becomes corrupted at 2. While this doesn't seem to be an issue, it can be a serious issue.
JASS:
//this will fire second
function Test2 takes nothing returns boolean
//remember that the event data become corrupt on the first fire?
local integer d = GetEventData() //2 on first and second fires
return false
endfunction
//this will fire first
function Test takes nothing returns boolean
local integer d = GetEventData() //d is now 1
if (d == 1) then
call FireMyEvent(2) //set d to 2
endif
if (d != GetEventData()) then
call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, "RECURSION ERROR!")
endif
return false //to prevent trigger actions from being run for no reason
endfunction
function Init takes nothing returns nothing
call OnMyEvent(Condition(function Test))
call OnMyEvent(Condition(function Test2))
call FireMyEvent(1) //data is now 1
endfunction
There are two methods for solving this recursion error. The first poor way is to create an array type stack.
JASS:
globals
private trigger myEvent = CreateTrigger()
private integer stack = 0
private integer array data
endglobals
function OnMyEvent takes boolexpr c returns nothing
call TriggerAddCondition(myEvent, c)
endfunction
function FireMyEvent takes integer d returns nothing
set stack = stack + 1 //increase the stack, thus making a new spot for event data
set data[stack] = d //event the new spot to our current data
call TriggerEvaluate(myEvent) //fire
set stack = stack - 1 //revert to previous data
endfunction
function GetEventData takes nothing returns nothing
return data[stack]
endfunction
If I were to fire the second example, it would run in this order-
Test1- data 1
Test1- data 2
Test2- data 2
Test2- data 1
For a clearer understanding-
Fire (1)
----run test1 (1)
--------Fire (2)
------------run test1 (2)
------------run test2 (2)
----run test2 (1)
As can be seen, the data is maintained ; D.
The other and better way is by using locals to store the data to save on an array and a global declaration.
JASS:
globals
private trigger myEvent = CreateTrigger()
private integer data = 0
endglobals
function OnMyEvent takes boolexpr c returns nothing
call TriggerAddCondition(myEvent, c)
endfunction
function FireMyEvent takes integer d returns nothing
local integer prev = data //store the previous data in a local
set data = d
call TriggerEvaluate(myEvent)
set data = prev //set the data back to the previous value
endfunction
function GetEventData takes nothing returns nothing
return data
endfunction
This essentially does the same thing as the stack method but faster. Array reads are also quite a bit slower than var reads, so it's a better design.
I'll answer this tomorrow
->2. How are structs instantiated? Please create an array struct with a create and destroy method.
I'd prefer someone else to answer it on this thread by tomorrow. Please answer if you learned the answer to this within the last day. The answer and fully commented code can be found on this thread *hint hint*
Interesting new Question
What do you suppose this does? //! i local id = getvarobject("nfr2", "units", "UNITS_UNIT_EVENT")
Inside of script that uses
Somewhere //! import "luajass.FILE_NAME.j"
The imported file before that function was run (doesn't exist)
--------------------------------------------------
After function was run for ABILITIES_UNIT_INDEXER
In a function in map script set u = CreateUnit(Player(14), UNITS_UNIT_EVENT, WorldBounds.maxX, WorldBounds.maxY, 0)
OM code (generates objects)
JASS:
//! i createobject("nfr2", id)
//! i makechange(current, "unam", "Unit Event")
//! i makechange(current, "unsf", "(Unit Event)")
//! i makechange(current, "uico", "")
//! i makechange(current, "uine", "0")
//! i makechange(current, "udro", "-")
//! i makechange(current, "usnd", "")
//! i makechange(current, "ushb", "")
//! i makechange(current, "umdl", "")
//! i makechange(current, "uubs", "")
//! i makechange(current, "ides", "")
//! i makechange(current, "utip", "")
//! i makechange(current, "usca", ".01")
//! i makechange(current, "ussc", ".01")
//! i local j = ((jass.globals.create(jassread())):read("ABILITIES_UNIT_INDEXER")).value:sub(2,5)
//! i makechange(current, "uabi", "Aloc," .. j)
//! i makechange(current, "ubdg", "0")
Grimoire Samples omtest.lua file (in case you don't know om tool)
Code:
setobjecttype("units") -- units, items, doodads, destructables, abilities, buffs, upgrades
mergefile("input.w3u", import) -- merge, replace, import
setobjecttype("doodads")
mergefile("input.w3d", replace)
setobjecttype("abilities")
mergefile("input.w3a", merge)
mergefile("more.w3a", merge)
if objectexists("AHbz") then
modifyobject("AHbz")
if (currentobject() == "AHbz") then
logf(currentobjecttype(), currentobject()) -- write debug information to log
makechange(current, "Tip", 3, "Lame Level 3 Tooltip")
makechange(current, "Cool", 2, 99.5)
makechange(current, "achd", 1)
makechange(current, "alev", 4)
end
end
if objectexists("S000") then
createobject("S000", "Sxyz") -- new id will be Sxyz
if (currentobject() == "Sxyz") then
logf(currentobjecttype(), currentobject()) -- write debug information to log
makechange(current, "Hotkey", "Q")
makechange(current, "Name", "My Chaos")
makechange(current, "EditorSuffix", "(Peasant)")
makechange(current, "CheckDep", 0)
makechange(current, "Cha1", 1, "hpea")
end
end
if objectexists("AHbz") then
createobject("AHbz", generateid("AHbz")) -- new id will be generated as substitute for the passed AHbz id
if (currentobject() ~= "") then -- "" would indicate that we do not have a current object
logf(currentobjecttype(), currentobject()) -- write debug information to log
makechange(current, "Levels", 10)
makechange(current, "Tip", 6, "Blizzard Level 6")
makechange(current, "ResearchTip", "Learn Blixxard")
makechange(current, "Tip", 5, "fuckfuckfuckfuckfuck")
resetchange(current, "Tip", 5) -- due to bad language
end
createobject("AHbz", generateid("AHbz"))
if (currentobject() ~= "") then
logf(currentobjecttype(), currentobject()) -- write debug information to log
makechange(current, "Name", "LOL")
resetobject(current)
end
end
setobjecttype("doodads")
createobject("ZOss", generateid("ZOss"))
createobject("ZOss", generateid("ZOss"))
createdid = currentobject()
-- we set this again because the modded, unmodded and custom groups refer to the state of the last time we called setobjecttype
setobjecttype("doodads")
makechange(custom, "dmis", 0.55) -- min scale for all custom doodads
makechange(original, "dmas", 300) -- max scale for all original doodads
makechange(unmodded, "dmis", 0.99) -- min scale for all unmodded original doodads
resetchange(modded, "dmas") -- max scale for all modded original doodads
modifyobject(createdid)
resetobject(current) -- resetobject also works with custom, original, unmodded, modded groups
Thank you so much Nes!
I'll try figuring them out first though, before reading the answers.
Also, I hope this isn't too much but, would you give me a simple question about JASS (Just one) just so that I can test out what I've learnt in terms of placing words in JASS?
->Also, I hope this isn't too much but, would you give me a simple question about JASS (Just one) just so that I can test out what I've learnt in terms of placing words in JASS?
This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
By continuing to use this site, you are consenting to our use of cookies.