1. Updated Resource Submission Rules: All model & skin resource submissions must now include an in-game screenshot. This is to help speed up the moderation process and to show how the model and/or texture looks like from the in-game camera.
    Dismiss Notice
  2. DID YOU KNOW - That you can unlock new rank icons by posting on the forums or winning contests? Click here to customize your rank or read our User Rank Policy to see a list of ranks that you can unlock. Have you won a contest and still havn't received your rank award? Then please contact the administration.
    Dismiss Notice
  3. The Lich King demands your service! We've reached the 19th edition of the Icon Contest. Come along and make some chilling servants for the one true king.
    Dismiss Notice
  4. The 4th SFX Contest has started. Be sure to participate and have a fun factor in it.
    Dismiss Notice
  5. The poll for the 21st Terraining Contest is LIVE. Be sure to check out the entries and vote for one.
    Dismiss Notice
  6. The results are out! Check them out.
    Dismiss Notice
  7. Don’t forget to sign up for the Hive Cup. There’s a 555 EUR prize pool. Sign up now!
    Dismiss Notice
  8. The Hive Workshop Cup contest results have been announced! See the maps that'll be featured in the Hive Workshop Cup tournament!
    Dismiss Notice
  9. Check out the Staff job openings thread.
    Dismiss Notice
Dismiss Notice
60,000 passwords have been reset on July 8, 2019. If you cannot login, read this.

Converting GUI into JASS

Discussion in 'Triggers & Scripts' started by GIMLI_2, Dec 16, 2015.

  1. GIMLI_2

    GIMLI_2

    Joined:
    Mar 21, 2011
    Messages:
    1,319
    Resources:
    2
    Maps:
    2
    Resources:
    2
    debug msg shows up, still does not work :/

    EDIT: fixed it, velocity had the same issues as the size

    Code (vJASS):

    function FloatingText takes string s, player p returns nothing
       
        local real r = GetRandomReal(1.00, 360.00)
        local texttag t = CreateTextTag()
        local real x = GetCameraTargetPositionX()
        local real y = GetCameraTargetPositionY()
       
        call SetTextTagText(t, s, 0.0345)
        call SetTextTagPos(t, x, y, 100)
        if (GetLocalPlayer() != p) then
            call SetTextTagVisibility(t, false)
        endif
        call SetTextTagVelocity(t, 0.044375*Cos(r*bj_DEGTORAD), 0.044375*Sin(r*bj_DEGTORAD))
        call SetTextTagPermanent(t, false)
        call SetTextTagLifespan(t, 3.00)
        call SetTextTagFadepoint(t, 2.00)

        set t = null
       
    endfunction
     


    do i need to destroy the floating text? or is it enough to null it?
     
    Last edited: Dec 17, 2015
  2. Wietlol

    Wietlol

    Joined:
    Aug 1, 2013
    Messages:
    4,641
    Resources:
    3
    Spells:
    3
    Resources:
    3
    Take a good look in how "SetTextTagVelocity(t, r, r)" works.
    The third parameter is NOT the angle.
     
  3. Zwiebelchen

    Zwiebelchen

    Joined:
    Sep 17, 2009
    Messages:
    6,789
    Resources:
    12
    Models:
    5
    Maps:
    1
    Spells:
    1
    Tutorials:
    1
    JASS:
    4
    Resources:
    12
    @Gimli: looks like your JASS knowledge is doing progress. Great to see someone who is actually trying to learn that thing instead of accepting horrible GUI in their maps. ;)


    Here's a suggestion for you, as you seem to have grasped the basics now:
    Look into library and scope definitions. It allows you to define custom dependencies for your scripts, define an initialization order and overall adds a lot of neat structure to your code through privacy keywords.

    The syntax looks like this
    Code (vJASS):
    library MyLib initializer init uses OtherLib

    function myPublicFunc takes nothing returns nothing
        //can also be called from outside the library
    endfunction

    private function myPrivateFunc takes nothing returns nothing
        //can only be called from inside the library
    endfunction

    private function init takes nothing returns nothing
        //runs at map init
    endfunction

    endlibrary


    Do you see how you can define a custom function in the library declaration that will be run on map init without having to use InitTrig_?
    That's neat and produces a lot cleaner code.

    There is also a
    public
    keyword, but tbh not many people use it, as it pointlessly dumps the library name in front of your function with an underscore like this:
    MyLib_MyPublicFunc

    ... hence why people just use functions without the public keyword, as they are essentially the same as public, but without the terrible underscore.


    Scopes work very similar, but have some restrictions and are always initialized after all libraries.

    As a rule of thumb: use scopes for spells and use libraries for systems and stuff that is required for your spells.
     
  4. GIMLI_2

    GIMLI_2

    Joined:
    Mar 21, 2011
    Messages:
    1,319
    Resources:
    2
    Maps:
    2
    Resources:
    2
    @zwiebelchen
    Thanks! I just had too many issues with gui and finally decided to learn jass :D
    About creating a library, what does "uses OtherLib" do?

    And what ive seen in many spells, they create functions that return constant values instead of creating globals. Why is that better?

    Currently im trying to make a spell but got stuck. In gui, i just used a unit indexer and had a cast trigger and a loop trigger with a periodic timer event. I could do that 1:1 in jass but there are better ways to do that, right?
     
  5. Wietlol

    Wietlol

    Joined:
    Aug 1, 2013
    Messages:
    4,641
    Resources:
    3
    Spells:
    3
    Resources:
    3
    when you create stuff in JASS and you want to call a function, you have to declare the function before you use it.
    This will not work:
    Code (vJASS):
    function foo1 takes nothing returns nothing
        call foo2()
    endfunction

    function foo2 takes nothing returns nothing
       
    endfunction

    But this will:
    Code (vJASS):
    function foo1 takes nothing returns nothing
       
    endfunction

    function foo2 takes nothing returns nothing
        call foo1()
    endfunction


    This gets really complicated when you want to use functions from other triggers, because there is little that you can do about the order of how they are created.
    In libraries, you can "use" or "require" another library by using the "uses" or "requires" keywords and it will place that used library above the one that uses it.

    In other words:
    Code (vJASS):
    library lib1 uses lib2
        function foo1 takes nothing returns nothing
            call foo2()
        endfunction
    library

    library lib2
        function foo2 takes nothing returns nothing
           
        endfunction
    endlibrary

    Will be:
    Code (vJASS):
    //library lib2
    function foo2 takes nothing returns nothing
       
    endfunction
    //endlibrary

    //library lib1 uses lib2
    function foo1 takes nothing returns nothing
        call foo2()
    endfunction
    //library





    Using functions instead of globals is better because of how configurables work.
    Lets say that you have a spell similar to Firebolt... can you guess how many configurables you need to make it cover pretty much everything?
    I guess you will guess below 100... but I can come to 4k without problems.
    And with configurables, you will never be prepared for in-game mechanics of the map that uses them.

    So instead of creating million globals, you just make one function that will take the index number of your spell (preferably) and return the damage, speed, duration, cooldown, whatever.




    In JASS, you dont need a new trigger for each periodic thing.
    You can just use timers :D
    But on the other hand, I recommend you to use a system.
     
  6. Flux

    Flux

    Joined:
    Feb 6, 2014
    Messages:
    2,333
    Resources:
    28
    Maps:
    1
    Spells:
    19
    Tutorials:
    2
    JASS:
    6
    Resources:
    28
    It means it requires the library named "OtherLib" for your library to work. It's mainly because your library will use some functions created in the OtherLib. In terms of compilation, the "OtherLib" will written be above your library so that your library can call functions in "OtherLib"

    It is not actually better. Those "many spells" must have been written in JASS not vJASS. In Normal/Vanilla World Editor, you can't create a global via scripting e.g.
    globals...endglobals
    so JASS users end up using function for configuration instead of variables. Still vJASS spells have some configurables written in function format mainly due to being dependent on a variable e.g. damage dealth per level will be configured in a way like this
    Code (vJASS):

    function Damage takes integer lvl returns real
       return lvl*100 + 100  //200, 300, 400
    endfunction
     



    You could also do that in JASS, remember, the only difference between GUI and JASS is the way the code is presented. In terms of algorithm, it is mostly the same. However the advantage in vJASS is you can create structs which automatically have an allocate function (much like a Unit Indexer giving a custom value to a unit) that allows you to get a unique unused integer which you can use as an index of a spell. I highly advise reading this if you want to move to vJASS which in my opinion is a lot easier.
     
  7. Wietlol

    Wietlol

    Joined:
    Aug 1, 2013
    Messages:
    4,641
    Resources:
    3
    Spells:
    3
    Resources:
    3
    Instead of having
    Code (vJASS):
    function Damage takes integer lvl returns real
       return lvl*100 + 100  //200, 300, 400
    endfunction

    You should be having
    Code (vJASS):
    function GetDamage takes integer id returns real
       return GetLevel(id)*100 + 100  //200, 300, 400
    endfunction
     
  8. Flux

    Flux

    Joined:
    Feb 6, 2014
    Messages:
    2,333
    Resources:
    28
    Maps:
    1
    Spells:
    19
    Tutorials:
    2
    JASS:
    6
    Resources:
    28
    Uhmmm, why? I'm talking about the configuration part. My resources uses
    Code (vJASS):
    function Damage takes integer lvl returns real
       return lvl*100 + 100  //200, 300, 400
    endfunction

    and mods have no problem with it.
     
  9. Wietlol

    Wietlol

    Joined:
    Aug 1, 2013
    Messages:
    4,641
    Resources:
    3
    Spells:
    3
    Resources:
    3
    Mods have no problem with it because mods dont care about the user's maps.
    They shouldnt care either.

    But let me take another example.
    I want my spell to also deal damage based on my targets missing health.
    So:
    Code (vJASS):
    function GetDamage takes integer id returns real
        local real damageBase = 100
        local real damagePerLevel = 100 * GetLevel(id)
        local real damageByMissingHealth = 0.2 * (GetUnitState(GetTarget(id), UNIT_STATE_MAX_LIFE) - GetWidgetLife(GetTarget(id)))
        return damageBase + damagePerLevel + damageByMissingHealth
    endfunction


    So let me take a quick guess in Shadow Flux's function:
    Code (vJASS):
    function Damage takes integer lvl returns real
        local real damageBase = 100
        local real damagePerLevel = 100 * lvl
        local real damageByMissingHealth = uhm... what?
        return damageBase + damagePerLevel + damageByMissingHealth
    endfunction


    If you think that it is bad because you have to call "GetLevel(id)" and "GetTarget(id)", then I recommend you to not use any configuration at all and ONLY write the stuff directly into your code.
    However, it is harder to edit and it will require some searching to find what you are looking for.
     
  10. Flux

    Flux

    Joined:
    Feb 6, 2014
    Messages:
    2,333
    Resources:
    28
    Maps:
    1
    Spells:
    19
    Tutorials:
    2
    JASS:
    6
    Resources:
    28
    He can also do this using my suggestion
    Code (vJASS):

    //somewhere in his global config
    private constant real DAMAGE_PER_MISSING = 0.2

    //somewhere in his function config
    private function Damage takes integer lvl returns real
       return lvl*100 + 100
    endfunction


    //somewhere in his onCast code
    set level = GetUnitAbilityLevel(this.caster, SPELL_ID)
    set this.staticDamage = Damage(level)

    //somewhere in his damaging code
    call UnitDamageTarget(this.caster, this.target, DAMAGE_PER_MISSING*GetUnitState(this.target, UNIT_STATE_MAX_LIFE) - GetWidgetLife(this.target) + this.staticDamage, ...)
     
     
  11. Wietlol

    Wietlol

    Joined:
    Aug 1, 2013
    Messages:
    4,641
    Resources:
    3
    Spells:
    3
    Resources:
    3
    Shadow Flux: "you won this round"

    It is better to use functions that are generically loading the entire data of your spell's instance (by either sending in the id as parameter, by using it inside the struct so "this." can be used, by any other way) than making whatever you can design. (Except changing the code directly.)

    But it is not bad to use variables or simple functions to load the data either.
    You can use either methods, but if you want 100% generic stuff, you really have to link the entire data to your functions.
     
  12. GIMLI_2

    GIMLI_2

    Joined:
    Mar 21, 2011
    Messages:
    1,319
    Resources:
    2
    Maps:
    2
    Resources:
    2
    so as long as the function is in my struct, i can give it the id of a certain unit and can use it inside the function?
     
  13. Wietlol

    Wietlol

    Joined:
    Aug 1, 2013
    Messages:
    4,641
    Resources:
    3
    Spells:
    3
    Resources:
    3
    No, you would require the id of the instance of the spell...
    when you use a struct, you can just use "this." but you should not be focussing on those things for now.

    First, just make yourself comfortable with JASS and it's uses.
    After that, you can make generic spells... or not.
     
  14. GIMLI_2

    GIMLI_2

    Joined:
    Mar 21, 2011
    Messages:
    1,319
    Resources:
    2
    Maps:
    2
    Resources:
    2
    ok

    i have a really weird problem.
    I made a periodic timer trigger which creates a random unit in a random point in a random location. it works fine, but it also creates those units outside the map boundary (and if they stack too much, they will pull themselves inside the boundary in the bottom left corner).
    the function runs only once, that's not the problem. It's really confusing
     
  15. Wietlol

    Wietlol

    Joined:
    Aug 1, 2013
    Messages:
    4,641
    Resources:
    3
    Spells:
    3
    Resources:
    3
    "a random point in a random location"
    I want to know how that works :D

    Your random point should be within the map bounds...
    So the random X should be higher than the minX and lower than the maxX.
    The same for the Y axis.
    If I could see how you wrote your random right now, I maybe could see where they are out of bounds or at least where they should be checked.
     
  16. GIMLI_2

    GIMLI_2

    Joined:
    Mar 21, 2011
    Messages:
    1,319
    Resources:
    2
    Maps:
    2
    Resources:
    2
    the thing is, it works fine. it just spawns a double at center of map obviously xD
    what i mean with random point in random location:
    i have 8 locations, one of them gets randomed, and in this one it will create a random point.

    what could be the problem is that i create a unit at 0, 0 and then run a function that moves the unit (SetUnitX() SetUnitY()), maybe that creates 2 units? :D
    one at 0, 0 and one at X, Y

    Code (vJASS):
    local unit u = CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE), Vehicle[i], 0, 0, 0.00)
    ...
    call RandomLoc(u, false, 0.00, "Abilities\\Spells\\Human\\MassTeleport\\MassTeleportTarget.mdl")


    Code (vJASS):

    function RandomLoc takes unit u, boolean b, real r, string s returns nothing

       
            local rect rt = LoadRectHandle(RegionHashtable, GetRandomInt(0, 7), 0/*udg_DialogIndex_Area*/)
            local real x = GetRandomReal(GetRectMinX(rt), GetRectMaxX(rt))
            local real y = GetRandomReal(GetRectMinY(rt), GetRectMaxY(rt))
            local player p = GetOwningPlayer(u)
           
            call SetUnitX(u, x)
            call SetUnitY(u, y)

            if (GetLocalPlayer() == p and b == true) then
                call PanCameraToTimed(x, y, r)
                call ClearSelection()
                call SelectUnit(u, true)
            endif
       
            if (s != "") then
                call AddSpecialEffect(s, x, y)
                call DestroyEffect( bj_lastCreatedEffect )
            endif

            set p = null
            set rt = null
            call RemoveRect(rt)
       
        endfunction
     


    sth else: setting a units x and y ignores pathing? how can i avoid that?




    EDIT: i changed the 0,0 to sth else and they do not spawn in the bottom left corner, so it has to do sth with that
     
  17. Wietlol

    Wietlol

    Joined:
    Aug 1, 2013
    Messages:
    4,641
    Resources:
    3
    Spells:
    3
    Resources:
    3
    First of all, you are not able to use "bj_lastCreatedEffect" that way.
    You have to store the actual effect (created with AddSpecialEffect()) in a variable and use that variable.
    In GUI functions, "bj_lastCreatedEffect" is the variable that is used.

    Setting rt to null before removing it is quite stupid dont you think?
    And what you are doing is making you unable to use that same rect (the one stored in the hashtable) for other things... so I guess you dont want to remove it.

    "b == true" can just be "b"

    SetUnitX/Y do indeed not check for pathing.
    You could use "SetUnitPosition(u, x, y)" instead which does check that.

    The removerect may be the cause of your problem... but I dont know for sure.
     
  18. GIMLI_2

    GIMLI_2

    Joined:
    Mar 21, 2011
    Messages:
    1,319
    Resources:
    2
    Maps:
    2
    Resources:
    2
    ok i fixed everything you mentioned.
    still spawning units at center
    it creates the unit, and when i move it, it looks like it copys the unit and moves the copy (or the other way around)

    oh my god, im stupid xD i'm really sorry

    found it
     
  19. Wietlol

    Wietlol

    Joined:
    Aug 1, 2013
    Messages:
    4,641
    Resources:
    3
    Spells:
    3
    Resources:
    3
    can you do a "call BJDebugMsg(I2S(rt))" just after the locals and give me the results?
     
  20. GIMLI_2

    GIMLI_2

    Joined:
    Mar 21, 2011
    Messages:
    1,319
    Resources:
    2
    Maps:
    2
    Resources:
    2
    i created the unit with the variable declaration, but i want to create it only every X seconds. i chose 2 seconds just for testing purpose and the trigger created 1 unit every second at 0, 0 and every 2 seconds, the unit got moved to the correct location.

    such a stupid mistake


    EDIT:
    for triggers like this, which are neither spells nor systems, do i need to put it in a library/scope or is it ok this way? i also declared the global variable in the same trigger
    Code (vJASS):

    globals
        integer VehicleTimer = 0
    endglobals

    function Trig_Vehicle_Conditions takes nothing returns boolean

            local integer i = GetRandomInt(0, 2)
            local unit u
        if (udg_Ev == false) then
           
            set VehicleTimer = VehicleTimer + 1
            if (VehicleTimer  == 2/*udg_Setting_Vehicle*/) then
                set u = CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE), Vehicle[i], 0, 0, 0.00)
                call RandomLoc(u, false, 0.00, "Abilities\\Spells\\Human\\MassTeleport\\MassTeleportTarget.mdl")
                set VehicleTimer = 0
            endif
               
           
        endif
       
            set u = null
       
        return false
    endfunction



    //===========================================================================
    function InitTrig_Vehicle takes nothing returns nothing
        set gg_trg_Vehicle = CreateTrigger(  )
        call TriggerRegisterTimerEvent( gg_trg_Vehicle, 1.00, true )
        call TriggerAddCondition( gg_trg_Vehicle, Condition( function Trig_Vehicle_Conditions ) )
    endfunction