• 🏆 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!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

[vJASS] Beginning Jass

Status
Not open for further replies.
Level 23
Joined
Jan 1, 2011
Messages
1,504
So I've begun learning jass, and it isn't half bad. I'd like to post my first ever function here to maybe get some tips of how to improve it. So here it is.
JASS:
library SUA
function SUA takes unit u, integer ut returns nothing
local integer i=LoadInteger(udg_Upgrade,ut,0)
local integer ui=GetUnitUserData(u)
local boolean b=LoadBoolean(udg_Lamp,ut,0)
if ut=='h005' then
call UnitAddAbilityBJ('A001',u)
else
if i>=0 then
call GroupAddUnitSimple(u,udg_Transferers)
call EnableTrigger(gg_trg_Transfer_Periodic)
else
set i=LoadInteger(udg_Factory,ut,0)
if i>=0 then
call GroupAddUnitSimple(u,udg_FactoryGroup)
call EnableTrigger(gg_trg_Factories)
else
set i=LoadInteger(udg_Mind,ut,0)
if i>=0 then
call GroupAddUnitSimple(u,udg_MindGroup)
call EnableTrigger(gg_trg_Mind_Control)
else
if b==true then
call GroupAddUnitSimple( udg_Unit1, udg_LampGroup )
call EnableTrigger(gg_trg_Lamps)
set udg_HasSight[ui] = false
call DestroyFogModifier(udg_LampSight[ui])
call RemoveDestructable(udg_LampDestructible[ui])
call TriggerExecute( gg_trg_Lamps )
endif
endif
endif
endif
endif
endfunction
endlibrary
 
Aaaaaaaaaah!
I can't read that D:

JASS:
library SUA
    function SUA takes unit u, integer ut returns nothing
        local integer i = LoadInteger( udg_Upgrade, ut, 0 )
        local integer ui = GetUnitUserData( u )
        local boolean b = LoadBoolean( udg_Lamp, ut, 0 )
        if ut=='h005' then
            call UnitAddAbilityBJ('A001', u)
        else
            if i>=0 then
                call GroupAddUnitSimple( u, udg_Transferers )
                call EnableTrigger( gg_trg_Transfer_Periodic )
            else
                set i = LoadInteger( udg_Factory, ut, 0 )
                if i>=0 then
                    call GroupAddUnitSimple( u, udg_FactoryGroup )
                    call EnableTrigger( gg_trg_Factories )
                else
                    set i = LoadInteger( udg_Mind, ut, 0 )
                    if i>=0 then
                        call GroupAddUnitSimple( u, udg_MindGroup )
                        call EnableTrigger( gg_trg_Mind_Control )
                    else
                        if b==true then
                            call GroupAddUnitSimple( udg_Unit1, udg_LampGroup )
                            call EnableTrigger( gg_trg_Lamps )
                            set udg_HasSight[ui] = false
                            call DestroyFogModifier( udg_LampSight[ui] )
                            call RemoveDestructable( udg_LampDestructible[ui] )
                            call TriggerExecute( gg_trg_Lamps )
                        endif
                    endif
                endif
            endif
        endif
    endfunction
endlibrary

Ahh, much better now.

edit
This would be the best implementation for that function:

JASS:
library SUA

    function SUA takes unit u, integer ut returns nothing
        local integer ui
        if ut == 'h005' then
            call UnitAddAbility(u, 'A001')
        else
			set ui = GetUnitUserData(u)
            if LoadInteger(udg_Upgrade, ut, 0) >= 0 then
                call GroupAddUnit(udg_Transferers, u)
                call EnableTrigger(gg_trg_Transfer_Periodic)
            elseif i = LoadInteger(udg_Factory, ut, 0) >= 0 then
                call GroupAddUnit(udg_FactoryGroup, u)
                call EnableTrigger(gg_trg_Factories)
            elseif LoadInteger(udg_Mind, ut, 0) >= 0 then
                call GroupAddUnit(udg_MindGroup, u)
                call EnableTrigger(gg_trg_Mind_Control)
            elseif LoadBoolean(udg_Lamp, ut, 0) then
                call GroupAddUnit(udg_LampGroup, udg_Unit1)
                call EnableTrigger(gg_trg_Lamps)
                set udg_HasSight[ui] = false
                call DestroyFogModifier(udg_LampSight[ui])
                call RemoveDestructable(udg_LampDestructible[ui])
                call TriggerExecute(gg_trg_Lamps)
            endif
        endif
    endfunction
	
endlibrary

What I did:
- Removed the useless and ugly BJs (The red functions)
- Changed b == true to simply b
- Removed some locals
- Restructured the thing

Here's a Jass rule that I made up a year ago and continue to follow till today:
- I declare a local integer/code/boolean/string/real if and only if I'm going to be calling a function that returns one of those types more than once
- I declare a local unit/widget/destructable/player/trigger/anything else if and only if I'm going to be calling a function that returns one of those types more than twice

That's assuming I'm passing the same arguments to that function.
See, I repeated LoadInteger, but I didn't use a local because the data it's going to return may be different since I passed different arguments :p
 
Indenting is important D:

You need to be able to read your code well D:

INDENTING IS FOR PROS BOI :>

That's pretty much it :eek:
By the way, in vJass, you can declare globals you know :p

JASS:
globals
    private integer i = 0 // this will only be accessible inside the library or scope
    public integer j = 0 // to access this, you would use LibraryName_j
    integer k = 0 // this will accessible everywhere. Yes, everywhere. (unless it's inside a scope)
endglobals
 
private globals can't be accessed outside the library they are in.
This allows you to avoid naming variables really long annoying names when you can give them nice, readable names like count, current, list, next, previous, data, etc...

public globals can be accessed outside the library, but they are referenced by adding a prefix with an underscore (meaning LibraryName_variableName)

globals with no prefix are just accessed however the hell you would usually access variables.

You can also have private constant, public constant, and constant.
constant means you can't change the value of the variable. Ever.
 
Level 23
Joined
Jan 1, 2011
Messages
1,504
I'd rather just use locals instead of globals for those quick functions that only fire once. Constants sound like a pain to use xD
Oh and while I was going through the function list it is missing a few functions. Like flush child hash n such :(
Some1 should update jass helper with those functions in it
And I discovered why Bjs are terrible... With natives you can reduce the code by a lot! cuz the bjs are just natives but fucked up for some reason with extra unneeded code..

Thanks for your explanation on a few things :)
 
Level 9
Joined
Apr 23, 2011
Messages
460
By the way Mag, you can also and need to use locals when writing a script that can be run on top of itself so it can iterate over its own instance of the script I.E. a hero revival spell. Two heroes can die at the same time, but using locals makes it run the script "twice" by allowing each unit to be stored to a local ; )
 
I'd rather just use locals instead of globals for those quick functions that only fire once. Constants sound like a pain to use xD

Constants are used when you want something to be configurable or something.
For example, in a spell, you would create a constant to define the raw code of the ability. Or you could make a constant to define the path of a special effect and such.

Oh and while I was going through the function list it is missing a few functions. Like flush child hash n such :(

They aren't listed, but they work perfectly.

Here's the list:

JASS:
LoadInteger(hashtable, key1, key2)
LoadStr(hashtable, key1, key2)
LoadBoolean(...)
LoadReal(...)
LoadXXXHandle(...)

where XXX could be anything like Unit, Widget, Destructable, etc...
LoadUnitHandle
LoadWidgetHandle
LoadDestructableHandle
^
As you can see, they're highlighted.

The Save functions are pretty much the same, except you would change Load to Save and there's an extra argument at the end of the function so you can input what you want to save.

On to other functions:
HaveSavedInteger
HaveSavedHandle
HaveSavedBoolean
HaveSavedString
HaveSavedReal

Those are all the HaveSavedXXX functions.
For all handles like units, widgets, destructables, players or triggers, you would use HaveSavedHandle.
These functions take the same arguments as the Load functions.

And here's the function you were looking for:
FlushChildHashtable(hashtable, parentKey)

edit

By the way Mag, you can also and need to use locals when writing a script that can be run on top of itself so it can iterate over its own instance of the script I.E. a hero revival spell. Two heroes can die at the same time, but using locals makes it run the script "twice" by allowing each unit to be stored to a local ; )

Actually, for a hero revival system, in order to avoid TriggerSleepAction calls, you would just use global arrays, dynamic indexing and a timer.

And I discovered why Bjs are terrible... With natives you can reduce the code by a lot! cuz the bjs are just natives but fucked up for some reason with extra unneeded code..

Not unneeded, just GUI-friendly in a sucky way :p
Most of the BJ variables are only used so you can call shit like (Last created unit) in GUI and such.
Of course, there are some good BJs like TriggerRegisterAnyUnitEventBJ
But, you can replace it using RegisterPlayerUnitEvent
 
Level 9
Joined
Apr 23, 2011
Messages
460
Maddeem. Something that isn't "vJass" or "Jass" method or required to do, but is something many coders along with myself do is instead of continually doing

JASS:
if check then
    //Do Actions
else
    if check2 then
        //Do Actions
    else
        if check3 then
            //Do Actions
        endif
    endif
endif

where check, check2, and check3 are boolean, you can do this. (To cut down on indenting)

JASS:
if check then
    //Do Actions
endif
if check2 then
    //Do Actions
endif
if check3 then
    //Do Actions
endif

It's a little cleaner and more closed in so you can read it somewhat better ;)

Edit:
Actually, for a hero revival system, in order to avoid TriggerSleepAction calls, you would just use global arrays, dynamic indexing and a timer.

I don't think you'd do that if you had multiple instances of the same hero type from multiple heroes owned by multiple players. Otherwise you'd run into index errors of overriding heroes wouldn't you? Like say player 2 has two heroes of type 'hpal'. If you dynamic index parent key 2, and child key 'hpal'. If both of them die, you have a net loss of 1 hero.
 
Level 17
Joined
Apr 27, 2008
Messages
2,455
Actually you can write a map with 0 locals and only globals, and still being MUI, as long you don't use any TSA, only timers.
But locals are just more convenient plenty of times, plus function arguments are already local (even not bugged one, not concerned by the handle reference bug, no need of set ... = null)
 
Level 23
Joined
Jan 1, 2011
Messages
1,504
edit
This would be the best implementation for that function:

JASS:
library SUA

    function SUA takes unit u, integer ut returns nothing
        local integer ui
        if ut == 'h005' then
            call UnitAddAbility(u, 'A001')
        else
			set ui = GetUnitUserData(u)
            if LoadInteger(udg_Upgrade, ut, 0) >= 0 then
                call GroupAddUnit(udg_Transferers, u)
                call EnableTrigger(gg_trg_Transfer_Periodic)
            elseif i = LoadInteger(udg_Factory, ut, 0) >= 0 then
                call GroupAddUnit(udg_FactoryGroup, u)
                call EnableTrigger(gg_trg_Factories)
            elseif LoadInteger(udg_Mind, ut, 0) >= 0 then
                call GroupAddUnit(udg_MindGroup, u)
                call EnableTrigger(gg_trg_Mind_Control)
            elseif LoadBoolean(udg_Lamp, ut, 0) then
                call GroupAddUnit(udg_LampGroup, udg_Unit1)
                call EnableTrigger(gg_trg_Lamps)
                set udg_HasSight[ui] = false
                call DestroyFogModifier(udg_LampSight[ui])
                call RemoveDestructable(udg_LampDestructible[ui])
                call TriggerExecute(gg_trg_Lamps)
            endif
        endif
    endfunction
	
endlibrary
That's what happens when I convert gui functions to jass xD I really need to memorize the important natives

Oh and I'm having trouble with unit groups, there is a "code" needed in the native, is this another function?
 
I don't think you'd do that if you had multiple instances of the same hero type from multiple heroes owned by multiple players. Otherwise you'd run into index errors of overriding heroes wouldn't you? Like say player 2 has two heroes of type 'hpal'. If you dynamic index parent key 2, and child key 'hpal'. If both of them die, you have a net loss of 1 hero.

You wouldn't index by type, you would use dynamic indexing so that the index wouldn't be related to anything.

Here's something I whipped up just now for you:

JASS:
struct Revive extends array
    
    /*
    *   Data variables
    */
    private static unit array hero
    private static real array x
    private static real array y
    
    /*
    *   Dynamic Indexing Variables
    */
    private static integer array rn
    private static integer ic = 0
    
    /*
    *   Hero revive filter
    */
    private static method filter takes unit u returns boolean
        return IsUnitType(u, UNIT_TYPE_HERO)
    endmethod
    
    /*
    *   Dynamic Indexing Functions
    */
    private static method allocate takes nothing returns thistype
        local thistype this = rn[0]
        if this == 0 then
            set ic = ic + 1
            return ic
        endif
        set rn[0] = rn[this]
        return this
    endmethod
    private method deallocate takes nothing returns nothing
        set rn[this] = rn[0]
        set rn[0] = this
    endmethod
    
    /*
    *   This will determine the revive time of a hero
    */
    private static method getReviveTime takes unit u returns real
        return GetHeroLevel(u)/2 + 5.
    endmethod
    
    private static method revive takes nothing returns nothing
        local thistype this = GetTimerData(GetExpiredTimer())
        
        /*
        *   Revive the hero at the stored position and show the effect
        */
        call ReviveHero(hero[this], x[this], y[this], true)
        
        /*
        *   Destroy the current instance along with the timer
        */
        call ReleaseTimer(GetExpiredTimer())
        call this.deallocate()
        set hero[this] = null
    endmethod
    
    private static method onDeath takes nothing returns nothing
        local unit u = GetTriggerUnit()
        local thistype this
        
        /*
        *   If the dying unit passes the filter, we allocate an instance,
        *   cache the data (the hero, the reviveX and the reviveY), then start
        *   a timer to revive him after a while.
        */
        if filter(u) then
            set this = allocate()
            
            /*
            *   Cache data
            */
            set hero[this] = u
            set x[this] = GetBaseCenterX(GetTriggerPlayer())
            set y[this] = GetBaseCenterY(GetTriggerPlayer())
            
            /*
            *   start timer to revive
            */
            call TimerStart(NewTimerEx(this), getReviveTime(u), false, function thistype.revive)
        endif
        
        set u = null
    endmethod
    
    /*
    *   "private static method onInit" will run on Map init before everything
    *   except for onInit static methods located inside modules that are implemented
    *   into a struct.
    */
    private static method onInit takes nothing returns nothing
        /*
        *   Registers a death event to the function onDeath
        */
        call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_DEATH, function thistype.onDeath)
    endmethod
    
endstruct
 
Level 9
Joined
Apr 23, 2011
Messages
460
UnitGroups are represented by group. Groups can hold instances of units. However note that groups need to be created via

JASS:
local group g = CreateGroup()

or

local group g
set g = CreateGroup()

same applies for force, which stores players where the native is CreateForce()

Additions are as simple as

JASS:
local group g = CreateGroup()
call GroupAddUnit(g, bj_lastCreatedUnit)

or

local force f = CreateForce()
call ForceAddPlayer(f, Player(0))

I might be forgetting something, but I haven't slept in a few days so, apologies.
 
Level 9
Joined
Apr 23, 2011
Messages
460
Something like this.

JASS:
function DoThis takes nothing returns nothing
    local unit u = GetEnumUnit()
    call GroupRemoveUnit(yourGroup, u)
    call RemoveUnit(u)
    set u = null
endfunction

function GroupTheseUnits takes nothing returns nothing
    local group g = yourGroup
    call ForGroup(g, function DoThis)
    set g = null
endfunction

When referring to units of a group through ForGroup(yourGroup, function yourFunction) you use GroupEnumUnit().
 
I wouldn't recommend ForGroup in most cases.

This is the best way to get units in range and do something to them:

JASS:
local unit u
call GroupEnumUnitsInRange(bj_lastCreatedGroup, x, y, radius, null)
loop
    set u = FirstOfGroup(bj_lastCreatedGroup)
    exitwhen u == null
    call GroupRemoveUnit(bj_lastCreatedGroup)
    // do stuff to unit u here.
    // if you want a filter, it would look something like this:
    if conditions then
        // do stuff here instead
    endif
endloop

Note: I'm only using bj_lastCreatedGroup because I don't want to create an extra group handle.
We do these kinds of things all the time to make sure we can use as little RAM as possible.
Also, I'm never going to need bj_lastCreatedGroup, so I might as well use it here.
 
By the way Mag, you can also and need to use locals when writing a script that can be run on top of itself so it can iterate over its own instance of the script I.E. a hero revival spell. Two heroes can die at the same time, but using locals makes it run the script "twice" by allowing each unit to be stored to a local ; )

This is not true.
Warcraft 3 is a single-threaded system, hence regardless of wether two functions are called at the exact same time or not, one will be called before the other. Unless there is some kind of timer or wait involved in that trigger, it doesn't matter wether he uses local or global.

One thing i noticed though, is that OP is using several hashtables, namely udg_Upgrade, udg_Factory, udg_Mind and udg_Lamp. All i cal say is.... WHY?!?!??
A single hashtable can hold all the relevant data you might ever want to save in a map. If you want to save more data to a single id, just use the child key (parent key should be the id of your unit/whatever, and child key is used to save multiple types of data). Like khamarr said though, you are also better off using GetHandleId() as a key rather than the unit type integer, since GetHandleId() returns a unique number for each object on the map.

This is how it would look if it was properly made:

JASS:
library myLibrary initializer Init

    globals
        hashtable Hashtbl
        integer Upgrade = 0
        integer Lamp    = 1
        integer factor  = 2
        integer Mind    = 3
    endglobals

    function Example takes nothing returns nothing
        local integer ut = GetHandleId(yourUnit)
        LoadInteger(Hashtbl, ut, Upgrade)
        LoadInteger(Hashtbl, ut, Mind)
        LoadBoolean(Hashtbl, ut, Lamp)
        //etc....
    endfunction

    private function Init takes nothing returns nothing
        set Hashtbl = InitHashtable()
    endfunction

endlibrary

The function i used named Init, which was defined as "initializer" in the first line, is a function that will be called on initialization, in which you can define all values you want for your variables (or functions you want to be run on initialization). You can effectively use it to replace triggers with "map initialization" event in most cases.

Finally:

Maddeem. Something that isn't "vJass" or "Jass" method or required to do, but is something many coders along with myself do is instead of continually doing

JASS:
if check then
    //Do Actions
else
    if check2 then
        //Do Actions
    else
        if check3 then
            //Do Actions
        endif
    endif
endif

where check, check2, and check3 are boolean, you can do this. (To cut down on indenting)

JASS:
if check then
    //Do Actions
endif
if check2 then
    //Do Actions
endif
if check3 then
    //Do Actions
endif

I disagree with this. With mags/everyone elses method, the script can skip the remaining evaluations if the first one returns true. In yours, it has to evaluate all "if"'s regardless of what the first one returns. After all, there is a reason we have the "else" statement.

A final hint i would like to give is, that selecting blocks of code while hitting TAB will indent it by four spaces. Perhaps everyone already know this, but i didn't when i started coding, so i spent half my time hammering the space bar. -.-'
 
Level 6
Joined
Jun 19, 2010
Messages
143
Hello, nice discussion here everyone.
I have tough question about my map's progress made by GUI halfway. I am learning Jass as many years of doing GUI made me pissed of. I kinda get used to functions and rudimentary scripting in Jass but still don't get one thing. Because the World Editor(GUI) segregate the whole yourmap.j, yourmap.wtg into many triggers. So should I convert everything into Jass? to getting more familiar with jass functions, of course I have a backup. Will you, all jass script writers, make the whole writing text in one trigger(JNGP interacts with GUI, so we see WE trigger in a map). I have seen several sample maps of your systems, your spells, Mag's ones. I see your jass writing are segregated in many WE triggers. Of course the core jass system is different to WE triggers, it makes the triggers itself by set gg_trg_Name=createTrigger(). Idk the way jass writers often do, you write the whole text in one, like writing in notepad but in one WE trigger in Jass, OR you write them separately. Maybe several complete maps can make me clear, please pass me some finished maps (maybe from somewhere, epicwar,...but I dont know which ones writteln in Jass and unprotected).

I realize writing Jass script in many WE triggers can be an advantage, easy to category & review, but I feel hard to have it run flawlessly & idk if I have to make sequences because of jass script in many separete WE triggers. Can they link to each other and whether sequences have any effects on them?

Although I never write a whole map of jass script, I also realize writing Jass script in one WE trigger (JNGP) or one script writer (Notepad,jasscraft) can create a mess with all thing, all functions, all scripts in it. Probably sequence is utmost important in this way of writing. How to think it clearly when writing? If i am right, I should think of writing from globals-endglobals, intialization function actions and function that create intialization like intialization with GUI, old way of my working. Then, game time sequence, what happened in the first place of gameplay, what happened next, what happened after...=functions,..Mag's timing system could be found useful.

You, Magtheridon, Bride,...also implemented the way of writing Jass-GUI; but I still find it quite reluctant when assuming with Jass I can make my game work faster, less memory consuming, lags reduced, script shortened rather than still working with GUI. I am just trying to pull myself into Jass scripting, otherwise I would be dragged with GUI as years around. However, your Jass-GUI is great idea, especially when I know Jass very well and can have them mingled flawlessly. Yet at the moment it confuses me at some extents, and make me confused the way two systems work in one map/game(sequence,timeline in what orders), as I have spent hours reading jass tuts, learning jass stuffs,...Though I can be just more practical using Jass only for creating spells, but that way I miss a great chance to practice more Jass and optimize my map. I can also miss alot since Jass have very many functions that GUI doesn't have, and many native functions that I have never known what they are used for.

Looking forward to your replies, advices on those of my tough questions.
Thank you very much.
 
I don't really understand what you were trying to say with all that text, but i can say as far as such that converting GUI triggers is ok, it is a great way of learning how jass works if you are a beginner. It doesn't matter wether you keep your code in one trigger or in several, since it will all be compiled into a single long row of text - but for the sake of readability, i strongly recommend that you sort your code into different triggers, it is much easier than browsing through one huge page of code.

Here's how i organize my maps:

*All my libraries are kept in an "empty" trigger with the same name as the library (as you see most people do). By empty i mean i create a trigger, convert it to JASS, and remove all of it's contents before i add my library to it. Smaller systems, such as some less complicated abilities, can be placed in scopes, also in their own trigger.

*All "common" libraries, such as TimerUtils, GroupUtils, ListModule, etc, i keep in a separate folder.

*Each large system has it's own library. Example can be my napoleon-style map, where i have one library for line formations, one for artillery formations, one for cannonballs objects, one for the custom menu object, etc. Global variables related to this system are kept in the top of the library.

*If the system requires any triggers, such as one for when a line is ordered to move somewhere and i want to communicate this to the related struct, i put this their own triggers and give the library and it's triggers an own folder with the library name on it.

*Each relevant object has it's own struct, for instance, if you have an RPG map, it can be a good idea to have a struct for your hero, or in any case where a single object have several related variables or behaviours related to it. The struct is then attached through hashtables or custom value to the object it is related to.

I don't know if this made any sense to you, but it is very hard to explain how to generally make systems, the only key would be to keep related things together.
 
Usually, we'd use one trigger for Jass scripts.
But, sometimes, we would split them up into triggers if we feel more comfortable doing so.
Sometimes, we even split up a big system into many tiny systems just to improve readability and maintainability.

As for organization, you'd start with globals at the top, init at the bottom, functions above the Init, private functions
above the normal functions, structs under private structs and private structs above private functions, but if you have
private functions or modules or structs or anything that have to do with configuration, you would put them at the top.

What timing system are you talking about? :eek:

And about the Jass-GUI way, Bribe came up with that.
I only learned to use it :p
 
Level 6
Joined
Jun 19, 2010
Messages
143
http://www.hiveworkshop.com/forums/submissions-414/system-invalid-req-elapsedgametime-209231/
That's the timing system I mentionned.

*All my libraries are kept in an "empty" trigger with the same name as the library (as you see most people do). By empty i mean i create a trigger, convert it to JASS, and remove all of it's contents before i add my library to it. Smaller systems, such as some less complicated abilities, can be placed in scopes, also in their own trigger.

*All "common" libraries, such as TimerUtils, GroupUtils, ListModule, etc, i keep in a separate folder.

*Each large system has it's own library. Example can be my napoleon-style map, where i have one library for line formations, one for artillery formations, one for cannonballs objects, one for the custom menu object, etc. Global variables related to this system are kept in the top of the library.

I see your point here. Do you often call the library to execute or it does automatically execute without being called by map initialiazation/ time expires. Can I call an user-defined function from the library?

Another thing I am not sure about is about hero picking functions (system if you already made that). Let says, in GUI, a trigger dealing with event peon (hero picker) enter circle of power to select a hero checks for its conditions before executing the actions.
I have 30 heros, there is a pain and memory consumption when dealing with 30 triggers in the old day of GUI, not to mention another 30 triggers for displaying hero skills to players for their chose.
Let's say I use global variables for all 30 types of heroes, all 30 types of skill tooltips.
Theoretically, Can I benefit from Jass by making firstly 1 function trig_Hero_Selection_Conditions to check the conditions (since they all check for the same conditions), then 30 or less functions trig_Hero_Selection_Actions.
Not sure condition function should be placed above the action function OR the other way around?
//========
then 1 exec functions to call function condition and those 30 functions action.
set gg_trg_Hero_Selection=createtrigger()
call TriggerAddAction(...)
call TriggerAddCondition(...) (the same question about placing them)
return //pick a hero for player by variable[array] defined

Is that all possible to work out? less functions as compared to huge amounts of triggers I used in GUI. I noticed there are many ways to do hero selection but my old system stayed for years up to now I really decide to change it.


__________
Recently I come up with new idea about picking heroes. Neutral hero(level 20 as e.g. of high level) becomes your hero (gettriggerplayer, change owner to trigger player) to let you see all skill details, clickable item or ability to select that hero (since I made hero with 6 skills, I would use item because there is no room for "pick hero" ability),
+ a function set movement speed of all neutral hero to 0 in the hero selection region or pathing blockers to block ally becoming hero from moving.
+ If selection region is where I'd like my hero selected to be in, then maybe a function to remove other neutral heroes, but problem of repick a hero is hard to solve.
either of the two above always requires 1 more function. Your hero returns to neutral when player select another hero. Else, A chosen one is then moved to your place as it's your hero.

I have played some maps with double-click hero selection and find myself hard to click a hero in order to choose one for me.
Tavern does not provide an interactive way of viewing the hero, hero stats, skills. Still but utmost important, I have to correct hero extended tooltip/text. This is painful. Peon could use a dummy skill to pick a hero but that option is not in my favor, many players are just dumb, they donno how to pick a hero!

Hope to see your advices, and if there is a hero picking library/system,...
Thank you very much.
 
Last edited:
Level 23
Joined
Jan 1, 2011
Messages
1,504
I've improved the original code I posted, with your tips :D
JASS:
library SUA
function SUA takes unit u, integer ut returns nothing
local integer ui=GetUnitUserData(u)
if ut=='h005' then
call UnitAddAbility(u,'A001')
elseif LoadInteger(udg_Upgrade,ut,0)>0 then
call GroupAddUnit(udg_Transferers,u)
call EnableTrigger(gg_trg_Transfer_Periodic)
elseif LoadInteger(udg_Factory,ut,0) >0 then
call GroupAddUnit(udg_FactoryGroup,u)
call EnableTrigger(gg_trg_Factories)
elseif LoadInteger(udg_Mind,ut,0)>0 then
call GroupAddUnit(udg_MindGroup,u)
call EnableTrigger(gg_trg_Mind_Control)
elseif LoadBoolean(udg_Lamp,ut,0)==true then
call GroupAddUnit(udg_LampGroup,u)
call EnableTrigger(gg_trg_Lamps)
set udg_HasSight[ui] = false
call DestroyFogModifier(udg_LampSight[ui])
call RemoveDestructable(udg_LampDestructible[ui])
endif
endfunction
endlibrary
 
It's not really laziness, I R REBEL. XD
No but seriously removing extra spaces saves map size (very very very insignificant), but hey its something.

No, it doesn't. Spaces are removed in the compiled code.


EDIT:

Can I call an user-defined function from the library?

Stuff put inside a library definition is just like any other code, except that you have the option to make it private. Private code can only be accessed by other code inside the same library. So the answer is yes, ofcourse.

Not sure condition function should be placed above the action function OR the other way around?

The order in which you register actions, conditions or events to your trigger doesn't matter.

If you want to discuss your map further though, i would recommend you to make your own thread.
 
Status
Not open for further replies.
Top