PDA

View Full Version : World Editor- Advanced


Elf
02-08-2006, 08:28
Created by: Im_On_56k
Orginally from: www.thehelper.net/forums (http://www.thehelper.net/forums)
Special Thanks: SFlip

This “tutorial” is meant for those people who already know how to make JASS codes and got the hang of them. It should help you improve your code, and make it more advanced and efficient than it is. It contains a couple of tips, and it’s not really a tutorial.

1. Avoid functions whenever possible

It has been proven that functions have a lot of advantages. They allow you to split the program into coding parts, and so, allow you to simplify it, or make it more readable. Moreover, sometimes it comes much more handy to use a function to write a piece of code, than write that code five times. You call the function itself five times and the problem is solved.

However, functions have a big disadvantage: They are slow compared to main operations (comparisions and arithmetic operations). It is often more indicated to avoid functions if you do not find them extremely necessary. For example, function Pow. Here is an example on where to use it:

local real x = Pow(2,1/3)It's just like grade 3 root, which cannot be achieved through any other way (not even Square Root doesn't work). Of course you may achieve it in another way, but it's complicated. Function Pow simplifies a lot. However, here is where you are not supposed to use it:

local real x = Pow(y,2)Theoretical example of course. y is another real variable of course. Now, this can easily be replaced with the following syntax:

local real x = y*yWhy is it better? Because it is faster, and so, you do not have to call a function and slow the whole execution.

Another function to avoid is SquareRoot. It is supposed to be very slow, but very important, especially when calculating the distance between two points. We know that the formula is:

local real distance = SquareRoot((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1))However, when using it into a comparasion, it is much better to do something like this:

local real dist = (x2-x1)*(x2-x1)+(y2-y1)*(y2-y1)
if dist<(a*a)This would be of course used to compare dist with a, but we can avoid SquareRoot through this little trick.

2. Use Native Functions
For those who do not know, native functions are fast, and do not cause lag! You should use native functions and avoid the others whenever possible! Now, the problem comes, how you know which functions are native, and which aren’t. Well, firstly, all BJ functions are non-native. Try to avoid them. Why? Because non-natives call natives, and usually do it in an useless way. I already told you that calling another function consumes memory, so calling a function which calls another function consumes twice the memory.

However, the rest are pretty complicated. So how do we make difference? And even more important, how do we know what natives does the non-native use? The solution comes with an editor: Jass Shop Pro (http://wc3sear.ch/index.php?p=Tools&ID=76).

Let’s analyze the tool a bit. In the right side, there is a search function. That’s all we need. Search for the function you are not sure if it’s a native or not. As an example, I will take ShowUnitHide. Type this in the search bar and only this function should appear in the list. Click on it! On the bottom window, the function will appear. It is very important that the function’s name appears in italic. This means that your function is not a native! Moreover, for non-native functions you will see their code as well. Natives do not have a JASS “writeable” code and so, the program will only display the parameters and the value they return.

In this case, you will notice that the function simply calls the ShowUnit() function, for the parameter of the function, and the value false. You could do that manually, couldn’t you? It is much faster, and even though the code may not seem simpler, in time you will realize that it’s better this way.

Another way to detect the non-native functions in your code is by copy-pasting it in the program. You will notice that keywords are highlighted. Well, all function names (made by Blizzard) appear in green. Non-natives appear in Italic. Conclusion? You can replace those with natives, if the coding is not too complicated (and in most of the cases, it isn’t). You should be able to make difference between the problem-causing non-natives, and non-problem-causing non-natives.

And now, a last question will surely pop into your mind: “Why were natives created by Blizzard, if all they do is slow the game”? Hehe, it’s not really like this. When Blizzard created JASS, nobody knew the language. But then, people started learning it, and soon enough, Blizzard released it to the public. These non-natives are supposed to make things easier for the users, and that is why, most GUI functions are non-natives. I'll give you an example:

function UnitApplyTimedLifeBJ takes real duration, integer buffId, unit whichUnit returns nothing
call UnitApplyTimedLife(whichUnit, buffId, duration)
endfunctionIn this case, some people may find it easier to have first the duration, then the buffId and then the unit. I personally do not get the purpose of this BJ, but it might have one. On the other hand:

function UnitCanSleepBJ takes unit whichUnit returns boolean
return UnitCanSleep(whichUnit)
endfunctionWhat’s the purpose of this function anyway? It simply calls another function, and so, slows things up a little! That is why I really suggest that you avoid natives whenever you don’t find it extremely difficult. Just replacing things a little doesn’t hurt.


2. Use Coordinates instead of Locations
In a lot of cases, coordinates are faster than locations. Even though Locations are supposed to be faster, the fact that you must remove them makes things slower. But first, let’s see the differences.

Locations automatically store an X and Y value inside them, and represent a point on the map. They are much easier to work with, because you do not need two variables, but instead only one. On the other hand, they are handlers and so, must be removed once you no longer need them.

A coordinate, either X or Y is actually a real value. Coordinates as type of variable do not exist, they exist only in theory. The main disadvantage is the fact that you no longer with only one variable, but instead with two. However, they do not need to be removed or destroyed since they are not handlers and do not take much memory either.

There is also a way to transform coordinates into locations and vice-versa.

Coordinates into Location
local location l
local real x = 0.00
local real y = 0.00
local location l = Location(x,y)The native function Location takes two real values (coordinates) and returns the equivalent location. Pretty simple! In the code above, I took the coordinates of the central point of the map, and stored it as a location into the variable l.

Location into Coordinates
local location l = GetRectCenter(GetPlayableMapRect())
local real x = GetLocationX(l)
local real y = GetLocationY(l)The native functions GetLocationX and GetLocationY take a location and return the required coordinate (X in the first case, and Y in the second). In this case, I got into l the center of the map, and then by using the other native functions I got it’s X and Y coordinate.


What I wrote above is pure theoretical and are things I rarely use anymore. However, it should give you a general view upon the difference between Coordinates and Locations. Now, let’s see how can we replace locations with coordinates, by taking some special cases.

a) PolarProjection – Yes, it’s true, PolarProjection is an extremely useful function, but getting the X and Y value of the location it returns… You still have to remove the location and so, you gain absolutely nothing. Even worse, you have to call two useless functions, and you carry two coordinates instead of carrying a single location. So, how can we solve the problem?

Those who studied common.j, will notice that PolarProjection is not a native. I will post it here, so that everybody can see how it looks:

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)
endfunctionThe solution now is pretty simple. We have to create our own PolarProjectionX and PolarProjectionY functions, to get the X and Y coordinates of the point. The functions would look like this:


function PolarProjectionX takes real x, real dist, real angle returns real
return x+dist*Cos(angle*bj_DEGTORAD)
endfunction

function PolarProjectionY takes real y, real dist, real angle returns real
return y+dist*Sin(angle*bj_DEGTORAD)
endfunctionNow, to use them, simply call the right function for the X, respectively the Y coordinate. As parameters, use the same dist and angle, and as for the source, use the x, respectively the y coordinate of the point. That should solve your PolarProjection problem.

b) Using coordinates for functions that ask as a parameter location

This is an extremely frequent problem that comes when replacing locations with coordinates. You have used functions that require as parameters locations a lot already, and it’s obvious to know them. However, the problem comes when you want to use coordinates. Using as a parameter Location(x,y) is useless as I said before, because you automatically use a location, which needs to be cleared, and all the coordinates work was in vain. However, Blizzard, smart as they were, created both Locations and Coordinates native functions, or maybe even better, location functions based on coordinates natives.

I’ll give you an example.

function AddLightningLoc takes string codeName, location where1, location where2 returns lightning
set bj_lastCreatedLightning = AddLightningEx(codeName, true, GetLocationX(where1), GetLocationY(where1), GetLocationZ(where1), GetLocationX(where2), GetLocationY(where2), GetLocationZ(where2))
return bj_lastCreatedLightning
endfunctionI think it’s pretty obvious that this function uses a location native. All you have to do is search for the correct function. That’s what Jass Shop Pro is good at!

There are two additional functions I am willing to give you here, just because they do not exist for coordinates, and because they are very important. I’m writing them because some of you may not figure it out how to make them. One of them is calculating distance between two points, and another one angle between two points.

function GetDistanceBetweenPoints takes real x1, real y1, real x2, real y2 returns real
return SquareRoot((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1))
endfunction

function GetAngleBetweenPoints takes real x1, real y1, real x2, real y2 returns real
return bj_RADTODEG * Atan2(y2-y1, x2-x1)
endfunction
3. Functions to avoid

There are certain functions I would suggest you avoid. There were people who tested these functions (such as Vexorian, thanks Vex) and came to the conclusion that the alternative is faster.

a) Function Pow(x,2) vs x*x
I think I mentioned that natives are usually fast and do not cause lag. Well, in some cases avoiding even the native can prove to be faster. This is a case! Calling a function makes the computer jump somewhere else in the memory, transmitting the parameters and all the stuff, and so, in this case, just using x*x instead of the equivalent Pow() function is faster. I am not saying that functions do not have their advantages! Of course they do! You do not have to write a piece of code 10 times, it is much harder to make mistakes with functions. But in some few cases, when you can avoid them, it is suggested that you do so.

b) GetTriggerUnit() vs their equivalents
Once again, it has been proven that GetTriggerUnit() is faster than any other equivalent native. Do not ask me why, I do not know! But it has been proved! Equivalents are usually units who execute the function, such as GetDyingUnit() (responding to An Unit Dies) and GetSpellAbilityUnit() (responds to An Unit Begins casting an ability). GetTriggerUnit() remains even unaffected by waits, so it is much safer, and it seems even faster.


4. Constant Functions

Other JASS subtleties are the constant functions. By adding the prefix constant, in front of the keyword function, you make a function constant. What does this mean? That the function returns a constant value, and that it’s value does not vary. For example, GetTriggerUnit() is a constant function, because it always returns the unit which triggered the actions.

The advantage is that constant functions are slightly faster. Sometimes it is significant, sometimes it is not. I suggest you make rawcode functions constant, because those truly return a constant value. Example:

constant function Dummy_Raw takes nothing returns integer
return ‘h000’
endfunctionNote: Functions calling other functions that are not constant cannot be made constant themselves. Also, constant functions do not modify the value of the parameters.


5. Kattana’s Local Handle Vars

Some of you might’ve heard about them, some might not. I think a lot of people use them right now, and they proved to give an extreme improvement to JASS. Why? Because through them you are able to access a local variable through another local, and so you can avoid global variables even more than ever. This is an extremely vast subject, but I will try to keep it short.

First of all, get the system from here (http://wc3sear.ch/index.php?p=JASS&ID=39). You will need to copy-paste it into the header of your map, so that you can use it!

Now, let’s study the whole linking concept. By linking, we understand that you can access a handle or value through another handle (but not value). Example of handles include units, timers and triggers. There are the mostly used handles for linking, and you will soon see why.

Let’s take a classical example in which this system proves extremely useful: smoothly moving units. You probably all know that the minimum value for TriggerSleepAction is 0.27. Quite high value I might add! If you try to move units and simulate some kind of gliding you will fail. Moving the unit every 0.27 seconds is simply not enough. So how can we solve this problem? By using timers.

Timers are handles that are like a chronometer. They wait a limited number of seconds, and after that, they force the execution of a function. You have the option to even make a timer repeat, by resetting its value and again countdown to 0, until you destroy it. Timers value can be brought down to a very small value. But I think 0.035 is smooth enough. Do not give a too small value, because the game will lag, because of the high number of executions of the function.

So, the advantage of timers is the fact that they can simulate a very short wait. But another advantage is the fact that waits interrupt the execution of the following actions, thing unwanted maybe by some. So in this case, a timer could once again prove useful.

Now, let’s take the knockback example, and see how you can use the Handle Vars system. I won’t write the entire code, but only the part you need to understand.

function Knockback takes nothing returns nothing
local timer t = GetExpiredTimer()
local unit caster = GetHandleUnit(t, “caster”)
local unit target = GetHandleUnit(t, “target”)
local real x1 = GetUnitX(caster)
local real y1 = GetUnitY(caster)
local real x2 = GetUnitX(target)
local real y2 = GetUnitY(target)
call SetUnitPosition(target, PolarProjectionX(x2, GetDistanceBetweenPoints(x1,y1,x2,y2)+10.00, GetAngleBetweenPoints(x1,y1,x2,y2)), PolarProjectionY(y2, GetDistanceBetweenPoints(x1,y1,x2,y2)+10.00, GetAngleBetweenPoints(x1,y1,x2,y2)))

set t = null
set caster = null
set target = null
endfunction

function Execute_Knockback takes nothing returns nothing
local timer t = CreateTimer()
local unit caster = GetTriggerUnit()
local unit target = GetSpellTargetUnit()
call SetHandleHandle(t, “caster”, caster)
call SetHandleHandle(t, “target”, target)
call TimerStart(t, 0.035, true, function Knockback)
call TriggerSleepAction(0.5)
call FlushHandleLocals(t)
call DestroyTimer(t)
set t = null
set caster = null

set target = null
endfunctionOk, it may look complicated but it will soon clear up. Execute_Knockback is the function which starts when the caster casts the knockbacking spell at a target. Now, we create the timer, and get the caster and target into two separate variables. Now comes the complicate part: the linking.

I told you before that by linking, we assure that we can access a value or handle, through another handle. Well, the process of linking has three steps: Selecting the handle to which you want to link the value or the other handle. In this case, the linker is the timer. You will soon understand why.

The second step is choosing a label under which to link the variable. If you link more values/handles to something, how can you then make difference when accessing them? They must have different labels, which are strings. Make sure they are always different, or else you may mess things up.

Third and last step is simple, because you must choose the value or handle, which you want to link. In this case, we linked the caster and the target. Once again, be patient and you will see why.

Now, we start the timer. It has a 0.035 duration, it repeats, and after each expiraion it executes the function Knockback. And now comes the first problem. When executing a function and not calling it like you normally do, you cannot use parameters. So how can you use the caster and target? Using globals is not a solution because it ruins your multiinstanceability.

THAT is why we use linkage. Let’s go to the Knockback function and see what happens. Since the function responds to the expiration of a timer, we can access that timer through a native: GetExpiredTimer(). Well now, I told you that linkage means being able to access a value or handle through another handle. Since we have that another handle (the timer), we can now access our two units, the caster and the target.

How do we do that? Simple, by using the appropriate function. In this case, we know that we have to get an unit, so we use the GetHandleUnit function. The first parameter is the handle to which you linked the unit, and the second one is the label. You know the label, since you chose it! So by using the label and the timer, voila, you got the unit!

That’s mainly what you have to know about linkage! If you didn’t understand it, I suggest you study the process in detail again and again. You will get it in the end; it’s not that complicated. Do not read further until you get how it works!!!

Now, the last problem we will get is if we no longer need the value/handle linked. Linkage consumes memory, and not unlinking it will be considered leak. In the case above, if I would just destroy the timer and nullify it, the unit will remain linked to something in the memory, but with no purpose or effect. Conclusion, we have to break the link!

There are two ways to do it: Either by breaking the links one by one, or by breaking all the links done by a handle. Usually use the first variant when you link things to units, destructables, items, or other things you do not use in a single execution. For example, casting three simultaneous spells which link things to an unit, and breaking all the links for that unit in one of the spells will bug the other two, because all the links will disappear. However, in the case of a local timer or trigger, which is used only in that single execution and then destroyed is much faster!

a) Breaking all links
Extremely simple! Simply use the FlushHandleLocals() function, and give as a parameter the handle to which you want to break all the links.

b) Breaking links one by one
Simple as well. Take the links one by one, and for their label, link to the handle the value null (in the case of the handles). I’ll give you an example of such unlinking:

local timer t = CreateTimer()
local unit u = GetTriggerUnit()
local unit v = GetSpellTargetUnit()
call SetHandleHandle(t,”cast”,u)
call SetHandleHandle(t,“targ”,v)
//And now comes the unlinking
call SetHandleHandle(t, “cast”, null)
call SetHandleHandle(t, “targ”, null)Consider this equivalent to nullifying local variables.

I hope these tips have proven useful! If you have any other questions or improvements, tell me and I will do my best to make this tutorial better!

Elf
02-08-2006, 15:54
Variables & Arrays

Variables & arrays are a necessary part of programming and knowledge of them is very helpful. Many people on this forum have had conciderable trouble understanding and using variables & arrays, so I have to decided to write this in-depth guide to alleviate this confusion.

All variables can be created in the World Editor from the Variable Editor, which is found in the Trigger Editor window.

Variables

Overview:
What is a variable?
In the loosest sense a variable is something that can change. However in programming a variable is something slightly more specific than that. A variable allows you to save information for use later. Like a labeled filing cabinet, you give the variable a name (label) and then put something (data) inside it to be looked at again later.

All variables have the same parts:

Type Name = Value
Type: This is the type of your variable, all variables can only hold one type of information. Only certain types of things can fit in our cabinet and this is what kind of stuff will fit.
Name: This is the name of your variable. By using this name in your program it is the same using the information inside. This is the label of the cabnet, instead of telling the program "get the scissors" you can tell it "get what is inside the cabinet labeled Name"
Value: This is the information that is stored by the variable. This can also be an expression, variable or function that gives a result of the correct type.
Here's a quick example:
Let's make a variable!
We will make its type "Integer" (whole numbers)
Its name will be "Fish"
And its value will be "7.4"...
Wait a second we can't do that!
Its value (7.4) isn't the right type, it's not a whole number.

So that won't work. Instead we will make its value "13".

Now, in a trigger we could say:
13+7
OR
Fish+7

and we will get the same answer: 20!
Basic Uses:
What good does a variable do us?
Variables allow us to include things in our triggers when we don't necessarily know what they are. Does that sound a little weird? It may, but we do it all the time.

There are so many uses for variables there is no way to list even a fraction of those here, instead here is a simple guideline for when to make something a variable:

If you use something in your triggers that you expect to change over the course of the game, or if you want to store a value for use later: Make it a variable!

To tell the variable what information to hold you can either enter a value in the 'Variable Editor' or use the Action: Set Variable.

Advanced Uses:
Here are some more uses for variables:

Constants
If you use a value over and over again in your triggers, consider making it a variable so that if you ever decide to change it, you only have to change it in one place.

[More to be added]

Additional Info:
Types
Here are the common type of variables found in the WC3 engine and tips for choosing the correct type:
Integer: Whole number.
Real: Number with decimal point.
Note:Some values (HP, MP, etc) must be a "Real" while others must be an "Integer".
String: A sentence like this, also it can be 'null' (0 letters long).
Boolean: Either TRUE, or FALSE.
Item: A single unique item on the map.
Note: An example of this is, even though there are many apples around, an Item variable refers to only one unique apple.
Item-Type: This refers to a type of item.
Note: This is a generic item of a type, like apple. Use this type of variable for creating items.
Item-Class: This refers to a set of items of a certain level (1-8) and category (permanent, charged, etc).
Unit: This refers to a single unique unit on the map.
Note: This type is like Item. Example, even though there are many footmen an Unit variable only refers to one of them.
Unit-Type: This refers to a type of unit, like footmen or Archmage.
Note: Use this type of variable for spawning units.
All the rest of the types of variables are either self explanitory or seldom used.
[More to be added]

Techical Information & JASS:
This is information for those who desire a more technical understanding.

Natives
The types: Integer, Real, String, Boolean, Code, and "Handle" are considered 'native' types in JASS. All other types of variables are derived from "Handle" and are defined in WC3 itself. Handle is basically a pointer to the internal data structure. Code is a type that references another function and is seen mostly in functions dealing with triggers.

Scope
Variable scope is where we can use a variable from. There are two main scopes: Global and Local. Global variables are defined in the begining of a JASS script (see below) and can
used in any function (trigger) in the code.

globals
...
type name = expression
type name = expression
...
endglobals
Local variables are defined when a function is called and can only be used from that function.
function...
local type name = expression
...
endfunction
Local variables are useful in writing a function that may be called many times quickly, because gobal variables would be overwritten each time the function in run, while a local variable is indepent of how many other triggers (even the same one) are running.






Arrays

Overview:
What is an array?
Arrays are a powerful programming tool that allow the creation of more dynamic and simplified code. Once you understand their structure and usage, creating 'complicated' triggers will be well within reach. Just like a variable, arrays store data within them. Except that while a variable is like a cabinet, an array is more like a book with many pages. Each page has a number and that number is called an index.

An array is a simple thing, and all arrays have the same format:

Type Name = Value

Type: This is the type of the array, just like the type of a variable this deterimines what can be stored in the array.
Name: The name of your array, much like the name of a variable.
[Index]: The index is always contained within brackets "[ ]" and is always a positive integer (1, 2, 3, 4...). Also it may be any expression, variable, or function that returns a positive integer.
Value: Is the value of the array at the specified index (more on this later), and its type is always of the same type as the array.
Basic Concept and Use:
An array is very much like a list of variables, and each one has its own number (index). But why would you want to use an array over a group of variables?

One common use for arrays is organizing information by player number. Here a common example to illustrate this point:
Let's say we want to keep track of the number of kills for each player.
We could make an integer variable for each one: Player1_Kills, Player2_Kills,
Player3_Kills,... Or we could make an integer array: Player_Kills[]

We can think of this array like a table
INDEX | VALUE
1 | ?
2 | ?
3 | ?
.. | ..


Now, by choosing what index to change the value at,
it would be like choosing what variable to change if
we weren't using an array.

i.e:
Player_Kills[1] = Player1_Kills
Player_Kills[2] = Player2_Kills
Player_Kills[3] = Player3_Kills
...

This doesn't seem to much easier, except now we can have a
function choose the index for us, allowing us to simplify
what could be many triggers into one.

#Kill Counter
#Events: A Unit Dies.
#Condition: ((Dying Unit) is a Hero) equal to TRUE
#Actions:
#//Find out the Player Number of the Killing Player
#Set Player_Killer_Num = (Player Number of (Owner of (Killing Unit)))
#Set Player_Kills[Player_Killer_Num] = Player_Kills[Player_Killer_Num] + 1
To tell an array to hold information you may only use the Action: Set Variable, remember to put in something for the index!

Advanced Uses:

Maps
A map is simply a way of linking two things together, typically something that doesn't follow a patern. Other programming languages offer a more flexible way of doing this, however in the limited environment of Warcraft 3, this will have to suffice. As long as there is a way to recude one of the elements to an integer (for use as the index) you can link them together.

Here's a simple example using only integers:
Let's say we're making an ability with 4 levels and we want to have it deal more
damage based on level. However this damage does not follow a pattern, is there a
way other than if/then statements to solve this problem?

Yes, Arrays!

Integer array CoolAbility_Damage[], will be our array.

Then simply intialize it so that the index is [level of the ability]
And the value is the damage at that level.

i.e:
Set CoolAbility_Damage[1] = 31
Set CoolAbility_Damage[2] = 100
Set CoolAbility_Damage[3] = 777

In your ability trigger add this in the place where you had the damage

CoolAbility_Damage[(Level of Ability (CoolAbility) for (Casting Unit)]

Viola, your damage will come out as the right amount, without the hassle of a
ton of if/then statments.
Technical Info & JASS:
Creating
Arrays in JASS cannot be initialized, you must fill in the value for every index with a seperate Set statment.
[I]type array Name
set Name[I] = expression
set Name[I] = expression
...
Size
Arrays in JASS all have the same max index of 8192. This means that the 'size' field for arrays in the WE is useless (to my knowledge). In this sense arrays are more like hash-tables, as you will not recieve an 'index out of bounds' error. But it also means that every array you make will occupy a certain amount of space no matter how much or little data is put into it.



Final Words
Thanks for reading this, and I hope it was helpfull. As always comments, suggestions and questions are welcome.


Happy Mapping =].

Created by: Daelin
Orginally from: www.thehelper.net/forums (http://www.thehelper.net/forums)
Special Thanks: SFlip

Elf
02-08-2006, 15:57
Created by: Laika.
Orginally from: www.thehelper.net/forums
Special Thanks: SFlip

alex_181993
10-15-2006, 11:36
This is for making inventory items aprear on the INgame hero.
First of all you need some models(if you can't find some post here and i will post some atachments).
The models need to be units without weapons,shields etc. (so called blank units) and you may need some weapon models.

So you need these trigers for weapons.

function Trig_pickupweapon_Conditions takes nothing returns boolean
if ( not ( GetItemType(GetManipulatedItem()) == ITEM_TYPE_ARTIFACT ) ) then
return false
endif
return true
endfunction

function Trig_pickupweapon_Func002Func002C takes nothing returns boolean
if ( not ( GetItemType(GetManipulatedItem()) == ITEM_TYPE_ARTIFACT ) ) then
return false
endif
if ( not ( udg_WeaponHand[GetConvertedPlayerId(GetOwningPlayer(GetManipulati ngUnit()))] == true ) ) then
return false
endif
return true
endfunction

function Trig_pickupweapon_Func002C takes nothing returns boolean
if ( not ( GetItemType(GetManipulatedItem()) == ITEM_TYPE_ARTIFACT ) ) then
return false
endif
if ( not ( udg_WeaponHand[GetConvertedPlayerId(GetOwningPlayer(GetManipulati ngUnit()))] == false ) ) then
return false
endif
return true
endfunction

function Trig_pickupweapon_Actions takes nothing returns nothing
if ( Trig_pickupweapon_Func002C() ) then
set udg_WeaponHand[GetConvertedPlayerId(GetOwningPlayer(GetManipulati ngUnit()))] = true
else
if ( Trig_pickupweapon_Func002Func002C() ) then
call DisableTrigger( gg_trg_DropWeapon )
call SetItemPositionLoc( GetManipulatedItem(), GetItemLoc(GetManipulatedItem()) )
call EnableTrigger( gg_trg_DropWeapon )
else
endif
endif
endfunction

//================================================== =========================
function InitTrig_pickupweapon takes nothing returns nothing
set gg_trg_pickupweapon = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_pickupweapon, EVENT_PLAYER_UNIT_PICKUP_ITEM )
call TriggerAddCondition( gg_trg_pickupweapon, Condition( function Trig_pickupweapon_Conditions ) )
call TriggerAddAction( gg_trg_pickupweapon, function Trig_pickupweapon_Actions )
endfunction
This is the triger for shields.

function Trig_pickupshield_Conditions takes nothing returns boolean
if ( not ( GetItemType(GetManipulatedItem()) == ITEM_TYPE_CAMPAIGN ) ) then
return false
endif
return true
endfunction

function Trig_pickupshield_Func002Func002C takes nothing returns boolean
if ( not ( GetItemType(GetManipulatedItem()) == ITEM_TYPE_CAMPAIGN ) ) then
return false
endif
if ( not ( udg_ShieldHand[GetConvertedPlayerId(GetOwningPlayer(GetManipulati ngUnit()))] == true ) ) then
return false
endif
return true
endfunction

function Trig_pickupshield_Func002C takes nothing returns boolean
if ( not ( GetItemType(GetManipulatedItem()) == ITEM_TYPE_CAMPAIGN ) ) then
return false
endif
if ( not ( udg_ShieldHand[GetConvertedPlayerId(GetOwningPlayer(GetManipulati ngUnit()))] == false ) ) then
return false
endif
return true
endfunction

function Trig_pickupshield_Actions takes nothing returns nothing
if ( Trig_pickupshield_Func002C() ) then
set udg_ShieldHand[GetConvertedPlayerId(GetOwningPlayer(GetManipulati ngUnit()))] = true
else
if ( Trig_pickupshield_Func002Func002C() ) then
call DisableTrigger( gg_trg_DropShield )
call SetItemPositionLoc( GetManipulatedItem(), GetItemLoc(GetManipulatedItem()) )
call EnableTrigger( gg_trg_DropShield )
else
endif
endif
endfunction

//================================================== =========================
function InitTrig_pickupshield takes nothing returns nothing
set gg_trg_pickupshield = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_pickupshield, EVENT_PLAYER_UNIT_PICKUP_ITEM )
call TriggerAddCondition( gg_trg_pickupshield, Condition( function Trig_pickupshield_Conditions ) )
call TriggerAddAction( gg_trg_pickupshield, function Trig_pickupshield_Actions )
endfunction
Custom armor sets.

function Trig_Chainmail_Armor_Conditions takes nothing returns boolean
if ( not ( GetSpellAbilityId() == 'A01S' ) ) then
return false
endif
return true
endfunction

function Trig_Chainmail_Armor_Func001C takes nothing returns boolean
if ( not ( UnitHasItemOfTypeBJ(GetSpellAbilityUnit(), 'I017') == true ) ) then
return false
endif
return true
endfunction

function Trig_Chainmail_Armor_Actions takes nothing returns nothing
if ( Trig_Chainmail_Armor_Func001C() ) then
call UnitAddItemByIdSwapped( 'I01M', GetSpellAbilityUnit() )
call RemoveItem( GetItemOfTypeFromUnitBJ(GetSpellAbilityUnit(), 'I017') )
call DisplayTextToForce( GetForceOfPlayer(GetOwningPlayer(GetSpellAbilityUn it())), ( "Created" + ( " " + GetItemName(GetLastCreatedItem()) ) ) )
else
call DisplayTextToForce( GetForceOfPlayer(GetOwningPlayer(GetSpellAbilityUn it())), "You do not have the required items to create this item." )
endif
endfunction

//================================================== =========================
function InitTrig_Chainmail_Armor takes nothing returns nothing
set gg_trg_Chainmail_Armor = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Chainmail_Armor, EVENT_PLAYER_UNIT_SPELL_CAST )
call TriggerAddCondition( gg_trg_Chainmail_Armor, Condition( function Trig_Chainmail_Armor_Conditions ) )
call TriggerAddAction( gg_trg_Chainmail_Armor, function Trig_Chainmail_Armor_Actions )
endfunction

For every armor set u can simply change the name of the triger and the name in the triger and the functions.
BEST USED ON RPG MAPS.
GOOD LUCK ON CREATING YOU'RE CARACTERS.

Best writen in VARIABLES and you may need Units that dont have weapons,books shields etc.

the_pwner06
03-13-2007, 21:37
This trigger will grant you the ability to play ambient sounds in a random way and in a random time:
Variable:Sounds-Sound-Aray3
Trigger:
Event-
Condition-
Action:Set Variables:
-Set Sounds(1)=Sound(sound=sound wich you want to play)
-Set Sounds(2)=Sound
-Set Sounds(3)=Sound
Wait-Arithmetical-Random number between-10-45 Seconds
Play Sound-Variable-Sounds
Run Trigger-This Trigger Ignoring Condition





All Triggers Should Have Event,Condition and Action writen down at the turotial ass seen up _/\_

ShadoWbg
03-15-2007, 12:36
This thread contains tutorials for people who have already met the Basics of the Warcraft World Editor (http://eurobattle.net/showthread.php?t=45205) and have good knowledge of the editor. There is a Thread for Intermediate Users (http://eurobattle.net/showthread.php?t=45278)
If you have any questions and/or difficulties post in the Questions Thread (http://eurobattle.net/showthread.php?t=38435) and someone will answer you as quick as possible.

AJalex
05-15-2007, 21:20
As you know triggers can create spells but there are some things that need to be aproched.
First of all you need how to use VARIABLES and CUSTOM EFFECT TRIGGERS but,you can make spells based on a JASS SCRIPT.
For JASS the best thing is to see the Tools thread and download JASS editor and start with that (only for medium knowlege makers).

[B]I. Starting Trigger

First of all i will start with anexample for the first set of triggers called the SPARK wich starts the chain of events that create the spell.
Event and condition should look as in this image.

AJalex
05-15-2007, 21:36
II. Variables

Variables are parts of data that can varie in different ways.
First of all the basics of a trigger spell are the CASTING UNIT and TARGETED UNIT OF AN ABILITY BEING CAST and if you want you can make a temp point wich is the point where the ability is cast (mostly used when you want to make teleportation/swap/point effects).

When you make a CASTING UNIT and a TARGETED UNIT do not use the same the same variables for the same thing because the CASTING UNIT will get the full target effect and the TARGETED UNIT will not even count so use 2 separate variables.

In the first picture you can see how to setup a variable for CastingUnit and you can do the same thing for TargetUnit just make another variable with the same configuration.


In the second picture you can see how to setup a TempPoint variable used in point related spells.
(the point is on the map or it can be the position of the casting unit or target unit)

AJalex
05-15-2007, 21:46
III. Continuing the starting trigger

The second thing you have to do is to continue the Starting Trigger,by seting up the variables to you're specifications as seen in the images at the bottom of this post.

First of all go to Action->Set variables and set the variables that you want.
In the image you can see how to setup a casting unit variable.

AJalex
05-15-2007, 22:14
IV. Effects

The next thing you have to do is to setup the effects of the trigger wich can be made with triggers (only because they can be specificly timed)

In the image bellow you can see how to setup a simple effect for the Exclamation Mark above the head of a unit.