HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

NEW! JASS function pack, please contribute

09-08-2003, 02:48 PM#166
Peppar
piRo-piOn: I wrote a small explanation in the beginning of the
dialog engine file, but I guess it wasn't very helpful (practice
makes perfect... :)). I'll try to explain further:

When a button is clicked the engine executes the trigger that was
specified at dialog init, but before that it sets For Loop Index A
to the index of the player who clicked the dialog, and For Loop
Index B to the index of the button that the player clicked. I should
have included these functions for simplicity:

Code:
function PlayerDialogGetClickedButtonIndex takes nothing returns integer
    return bj_forLoopBIndex
endfunction

function PlayerDialogGetTriggeringPlayerId takes nothing returns integer
    return bj_forLoopAIndex
endfunction

function PlayerDialogGetTriggeringPlayer takes nothing returns player
    return Player(bj_forLoopAIndex)
endfunction

I haven't tested them but they are pretty simple and should be
bug-free.

The UserData-field is for use if you want a button to have a
special value follow with the button for internal use. It is like the
UserData that Units have. UserData is mostly for dynamic dialogs.

Like if you have a dialog with buttons representing some (but not
all) players in a game, you might want to set the UserData to the
ID of the player that the button represents (and any Cancel
button to -1). You can then easily check which player was clicked
by retrieving the UserData (and abort if it was -1, if you included
a Cancel button).

Using HandleToInteger and IntegerTo[variableType], you can
store any handle-derived variable in the UserData.
09-09-2003, 03:56 AM#167
dataangel
There's no way to print the string of an item name other than a bunch of if statements. :(
09-12-2003, 04:19 AM#168
dataangel
I've been experimenting with creating triggers on the fly for complex functions, and I had an idea. Sometimes for a function, it might be necessary for you to check if something has happened after a wait. I wanted to make an AttachAOEDamage() function for the library, that would make a unit continuously emmit AOE damage for a duration or until the unit died, whichever came first. The problem was detecting the unit dieing. I could setup a separate trigger to set a global to be true or false, but I wanted this to be as self contained as possible without globals.

The solution was trigger attributes :). Of which there are only a few I know of -- whether a trigger waits on sleeps, the evaluation count, and the execution count. I haven't actually coded this, but I don't see why it wouldn't work...

Inside the function you'd create a trigger with the unit dies event, and the appropriate conditions to make sure it's the unit you want. You would store this trigger in a local trigger variable. Then after the wait has occurred, you check the execution count of the trigger. If it's greater than 0, you know the unit must've died at least once, and you can return the function and stop the continuous AOE damage.

I think this opens quite a wide range of function possibilities because you could have stuff like LockUnitManaUntil(unit, mpamount, event) and other neat stuff. All sorts of cool functions should be possible.

The library, IF I CAN EVER FIND A PHP/MYSQL EXPERT should grow pretty big :ggani:
09-14-2003, 09:24 AM#169
Peppar
@magnus99: Yes that was very helpful information. Thank you.
Sorry for the late reply.

@dataangel: Interesting idea. I think that would be a great
solution for many problems. You could do some general Wait for
event X, check every Y seconds.

And regarding your PHP/MySQL problems, why don't you create a
new thread in this forum or post them here? I'm sure that there
are many members who wouldn't dare to take on the title Expert
while they very well could handle the most complex of problems :P.
09-14-2003, 04:29 PM#170
dataangel
@Peppar: Yeah I'll make the post right after this.

Only problem I realized with my idea is that it wouldn't work in all situations because of conditions. In order to check for the right unit, I need to have a unit global :/ I ended up using bj_ghoul for this but their ought to be a better solution...
09-14-2003, 08:17 PM#171
Starcraftfreak
@dataangel:
Why do you want everything self-contained? As we know, that we can import blizzard.j into a map and that it gets well compressed (about 80%), we can just add as many globals as we want. Of course we should try to avoid using them if possible. But if that would result in a function, that is far too unstable or can produce random bugs (which can occur, if you try to (ab)use the existing globals for your data).
09-15-2003, 06:00 AM#172
PitzerMike
scfreak is right. But my tests with the advanced functions in WE Unlimited showed that a custom Blizzard.j seems to cause problems on bnet.
In my tests everyone got disconnected on initialization if the map was the first map played after connecting to bnet. I you played another map before everything went ok.
Maybe it was another file in my testmap and not blizzard.j but I'd rather do some testing before you use a modified blizzard.j.
09-15-2003, 06:37 AM#173
AIAndy
There might be an issue with Blizzard.j . I have encountered that too that only at the second map it actually gets loaded but I am not sure if it has to do with me using local files. I will investigate that some time.

But it would be nice to use some globals in these functions. I would have several that are pretty useful but rely on globals.

BTW, do you want only functions for triggers or also for AI scripts ?
09-15-2003, 07:46 PM#174
Starcraftfreak
I think both are welcome. It should be just a big community project, with a website, where you can post/discuss/request functions. So AI should also be covered as the AI is a very important part of Warcraft III and it's also coded in Jass.
09-19-2003, 09:39 PM#175
Peppar
@dataangel: I took time to make two functions based on your
discoveries.

Code:
function WaitForUnitEventSimple takes unit whichUnit, unitevent whichUnitEvent, real interval returns nothing
    local trigger t = CreateTrigger()
    local event e = TriggerRegisterUnitEvent(t, whichUnit, whichUnitEvent)
    loop
        call TriggerSleepAction(interval)
        exitwhen GetTriggerExecCount(t) != 0
    endloop
    call ResetTrigger(t)
    call DestroyTrigger(t)
endfunction

function WaitForUnitEvent takes unit whichUnit, unitevent whichUnitEvent, real interval, boolexpr condition returns nothing
    local trigger t = CreateTrigger()
    local event e = TriggerRegisterUnitEvent(t, whichUnit, whichUnitEvent)
    local triggercondition c = TriggerAddCondition(t, condition)
    loop
        call TriggerSleepAction(interval)
        exitwhen GetTriggerExecCount(t) != 0
    endloop
    call TriggerRemoveCondition(t, c)
    call ResetTrigger(t)
    call DestroyTrigger(t)
endfunction

I have tested these, and they work. No globals needed. Your idea
is truly excellent :).

If you want to use a condition, I recommend storing the boolexpr
you create in a local variable and later destroying it. This is
because I think that conditions aren't destroyed after their use,
and take up memory. I don't *know*, but it's better to be safe
than sorry, IMHO :).

To use boolexprs you would have to use the variable type
conditionfunc, which can be created with Condition(code) and
destroyed with DestroyCondition(conditionfunc)
09-20-2003, 02:31 AM#176
dataangel
Quote:
Originally posted by AIAndy
BTW, do you want only functions for triggers or also for AI scripts ?


AIScripts too, although be sure to indicate that ;)

You're a programmer guy, where are your PHP/MySQL friends? ;)

@Peppar: I was thinking of something like that =) And actually after looking at your code I think it might be possible to alter my code to work without bj_ghoul =)

@SCFreak: I'm just trying to avoid globals to make the code easy to copy and paste between maps and try to avoid messiness as much as possible. Also, staying away from globals means you don't have to worry about overlap in arrays -- although it's kinda hard to explain an example where that would come up.

BTW -- has anyone experimented with ExecuteFunc in common.j?

Update: @Peppar: Actually, I can't =( I thought the boolexpr variable type would let me do just that -- store a boolean expression so that I could generate conditions on the fly -- I wouldn't have to make a premade function. The problem is the only functions that returns boolexpr type are stuff like And/Or, and Condition() only takes functions. Wierder -- the TriggerAddCondition() function is only supposed to take boolexpr's, but Condition() returns conditionfunc's not boolexpr's, yet that's what WE generated code uses... :P
09-20-2003, 05:05 AM#177
dataangel
I just had another realization -- although it's hard for me to think of good applications at the moment. Whatever function you specify as your condition for a trigger is run every time the event occurs, and the actions only run when the condition returns true. But there's no reason you can't put normal code in the condition function, set globals and the like. This way you could split your actions up into two parts -- those in the condition function and those in the action function. Then you can retrieve how many times part1 has been run and how many times part2 has been run by getting the evaluation and execution counts of the triggers =)

Meanwhile, my latest difficulty has been with the Unit Enters Range event. GetTriggeringUnit() gives you the unit that came into range, not the unit you specified in the event, and there doesn't seem to be anyway to detect the unit you specified in the event :/ The only thing I can think of to do is to use the event, and then in the actions for it do a unit group of all units in range of the type that I specified in the event (luckily for my map there's only one unit-type I need this for). It'd be alot easier if there was a builtin function for this though... anyone have any ideas?

And yet another revelation: The change in real event works on local variables. Right now the only use I can think of is error checking, where you tell it to run a trigger displaying a message if a real becomes a certain value. I think I might be possible to writeup a LockRealConstant(real) function that would display a text message complaining if the passed real was changed -- but I haven't tested the event on passed variables yet ;) This would be alot more useful if there was a way to receive the triggering value...

P.S. If anyone figures out how to do true trigger scope variables or how to pass variables to action/condition funcs, then I will ordaine you God =)
09-20-2003, 09:09 AM#178
PitzerMike
As you were asking about ExecuteFunc.
This is a wonderful function, I love it. It takes the name of a the function to execute as string. So for example you say 'call ExecuteFunc("ClearSelection")
Obviously this only works for funcs that don't take any parameters.
I use it in my Dialog Engine to be able to set up all dialog buttons and their actions in only one triggeraction.

For WEU I also created a Triggername2Functionname function. For example it converts "Blizzard Cast" (the trigger name) to Trig_Blizzard_Cast_Actions so you can call the actions part of any trigger you like. I actually use that for the built in spell enhancer that calls the specified trigger when the specified ability is cast by the specified unit type.


And here are some of my functions that don't require BJ vars.
I didn't relly care to go with the naming of functions Blizzard but who does?
I could also add a WaitForEvent function for all available events if you want.
09-20-2003, 11:36 AM#179
AIAndy
Quote:
Originally posted by dataangel
The problem is the only functions that returns boolexpr type are stuff like And/Or, and Condition() only takes functions. Wierder -- the TriggerAddCondition() function is only supposed to take boolexpr's, but Condition() returns conditionfunc's not boolexpr's, yet that's what WE generated code uses... :P
That is because conditionfunc and filterfunc extend boolexpr. That means wherever a boolexpr is wanted you can give a conditionfunc or filterfunc.
09-22-2003, 07:18 PM#180
KaTTaNa
I think you should add this function. It's very simple, but useful when creating fake "Pick units in group" actions.
Code:
function CloneUnitGroup takes group source returns group
    local group A = CreateGroup()
    
    call GroupAddGroup(source, A)
    
    return A    
endfunction