1. Join other hivers in a friendly concept-art contest. The contestants have to create a genie coming out of its container. We wish you the best of luck!
    Dismiss Notice
  2. The Melee Mapping Contest #4: 2v2 - Results are out! Step by to congratulate the winners!
    Dismiss Notice
  3. We're hosting the 15th Mini-Mapping Contest with YouTuber Abelhawk! The contestants are to create a custom map that uses the hidden content within Warcraft 3 or is inspired by any of the many secrets within the game.
    Dismiss Notice
  4. The 20th iteration of the Terraining Contest is upon us! Join and create exquisite Water Structures for it.
    Dismiss Notice
  5. Check out the Staff job openings thread.
    Dismiss Notice

Wurst resources

Discussion in 'Triggers & Scripts' started by inspicous, Feb 27, 2019.

  1. inspicous

    inspicous

    Joined:
    Feb 27, 2019
    Messages:
    14
    Resources:
    0
    Resources:
    0
    Hi Hive,
    I'm looking for some pointers with picking up Wurst syntax.
    How to iterate over all players in the game and spawn starting units for them?

    I've read most of the documentation on WurstScript • Home including WurstScript • Manual (#for-loops) however I'm still painfully stuck.
    Here's a pastebin of my current typical problems (wurstbin) and here's an example from it

    Code (Text):
    @test function testUnitTesting()
        let a = 5 * 2
        a.assertEquals(10) // passes

    @test function testGetPlayersUnitTest()
        let a = GetPlayers() + 100
        a.assertGreaterThan(0)
        // fails with compiler errors!
        // where to put that @compiletime ?

    init
        for player p in players
            print(p.getName()) // compiler error
     
    I know C++ (UnrealEngine) and web development (JavaScript), so I know what a variable is, how to loop, and other general programming concepts and I'm a diehard unit tester. But I've never used Java or Python, so Wurst is pretty foreign.

    • I'm looking for code examples and other resources (I'm not really used to coding without the glorious stackoverflow...)
    • Specifically answers to questions from that wurstbin (9 questions in total). Also, I'll buy you a cup of coffee for some chat time via some IM.

    I have no idea how Jass works, but am somewhat ok with GUI triggers (see for yourself below).
    Wurst is really pretty, so I would indeed like to pick it up.

    Generally, I belive if I could retype what I've done thusfar in GUI I would be ok.
    E.g. below is my creep wave spawner.



    • -------- Wave Increment --------
    • Actions
      • -------- Run wave --------
      • Trigger - Run Wave Load <gen> (checking conditions)
      • -------- Increment for next wave to total or reset to WaveDifficulty --------
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • Wave Less than WavesTotal
        • Then - Actions
          • Set Wave = (Wave + 1)
        • Else - Actions
          • Set Wave = (Min(WaveDifficulty, WavesTotal))
          • Set WaveDifficulty = (WaveDifficulty + 1)
      • -------- Start timer --------
      • Countdown Timer - Start Timer as a One-shot timer that will expire in TimerDuration seconds

    • -------- Trigger Wave Load --------
    • Actions
      • -------- Type A --------
      • Set SpwnCount = (SpwnCountA[Wave] + WaveDifficulty)
      • Set SpwnUnitType = SpwnUnitTypeA[Wave]
      • Trigger - Run Wave Spawn <gen> (checking conditions)
      • -------- Type B and C (nested if statements) --------
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • SpwnCountB[Wave] Greater than 0
        • Then - Actions
          • -------- Type B --------
          • Set SpwnCount = (SpwnCountB[Wave] + WaveDifficulty)
          • Set SpwnUnitType = SpwnUnitTypeB[Wave]
          • Trigger - Run Wave Spawn <gen> (checking conditions)
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • SpwnCountC[Wave] Greater than 0
            • Then - Actions
              • -------- Type C --------
              • Set SpwnCount = (SpwnCountC[Wave] + WaveDifficulty)
              • Set SpwnUnitType = SpwnUnitTypeC[Wave]
              • Trigger - Run Wave Spawn <gen> (checking conditions)
            • Else - Actions
        • Else - Actions
      • -------- Finish --------
      • Unit Group - Remove all units of SpwndGroups[0] from SpwndGroups[0]
      • Unit Group - Add all units of SpwnGroup to SpwndGroups[0]
      • Hashtable - Save Handle OfSpwndGroups[0] as 1 of 1 in Camps
      • Unit Group - Remove all units of SpwnGroup from SpwnGroup
      • -------- Testing --------
      • Game - Display to (All players) the text: (array + (String((Number of units in SpwndGroups[0]))))
      • Game - Display to (All players) the text: (single + (String((Number of units in SpwnGroup))))
      • Trigger - Run All Camps to Red <gen> (checking conditions)

    • -------- Trigger Wave Spawn --------
    • Actions
      • Unit - Create SpwnCount SpwnUnitType for Player 9 (Gray) at (Center of (Load 0 of 1 in Camps)) facing 0.00 degrees
      • Unit Group - Add all units of (Last created unit group) to SpwnGroup


    Cheers
     
    Last edited: Feb 27, 2019
  2. Frotty

    Frotty

    Wurst Reviewer

    Joined:
    Jan 1, 2009
    Messages:
    1,392
    Resources:
    10
    Models:
    3
    Tools:
    1
    Maps:
    4
    Tutorials:
    1
    Wurst:
    1
    Resources:
    10
    edit: Btw this is wrong forum. Should be trigger & scripts.

    I don't think you have problems with syntax, rather with understanding the underlying basics. They are more touched upon in beginner guide and blog posts.

    1-2. If the compiler tells you something, it's most likely correct. You don't need the imports because they are part of the auto imports.

    3. Only for group closures. You can ctrl + left click all references to jump into them and just check the package out to see what's inside (taught in beginner's guide)

    4. If you want to convert GUI, use the convert function in editor and check the emitted jass. Everything that exists in Jass exists in Wurst, though you should usually use wrappers.
    It just takes a little getting used to, and heavy usage of autocomplete and search. I don't know what you mean by MAP_RESOURCE_TRADING_ALLIES_ONLY. What you are doing there is simply defining global variables.

    5. "What is the command for compile in VSCode when using wurst?" it's "run map", what a surprise. You most likely simply aren't saving your files (ctrl + s) thus your code might appear without errors, but the on disk variant still has them. Make sure to save before running. This isn't really related to wurst.

    6. Tests are compiletime - only (compiletime is the time you run a run/build task in vscode). This means wurst interprets your code on your machine instead of Warcraft 3.
    This also means that only natives, that have been implemented in the wurst compiler, can be run. Exactly what the error tells you "The native <GetPlayers> has not been implemented for compiletime!"
    You can only make this test pass if the native were to be implemented - but even then those tests would require a map to read that data from.
    Thus I think it is pointless in the first place. It is nearly impossible to usefully test code that relies on wc3 intrinsics, since we don't know how a lot of things internally work.

    7. RTFM! you said you read the website, but obviously you didn't: WurstScript • Closure For Groups more on closures: WurstScript • Get close with closures
    Also, "u.GetUnitName()" is very incorrect. All extension functions start lowercase. If a function starts with uppercase, it's a native. Therefore no business even calling with dot.
    Also if you are looking for the extension func for something like "GetUnitName", the "unit" part is implied and therefore omitted in the wrapper name.
    What you're looking for is "u.getName()" - again, use autocomplete via ctrl + space.

    8. No. Just make multiple init blocks if you want that, but it seems like an anti-pattern to me.

    9. No. You can convert your triggers to Jass and start from there. But as said in every Jass tutorial, GUI is inherently different from Jass, and you will just need to learn and adapt.

    I think this is mostly stuff which is taught in beginner's guide. If you have specific suggestions for improvements I will gladly add them.

    Did you check the showcase? All my maps are open source in github and linked there, also my Frentity lib for bootstrapped map dev. It has a package which basically initializes players like you are trying:
    Frotty/Frentity


    You can, but it will result in very sub par code. Also since wurst is OOP you should foolow the paradigm and encapsulate your code. In my defense map I use a wave classes and a spawner class e.g.
    This is a freehand example without imports I just hacked together: wurstbin
    Often you also want to couple spawning with wurst object generation.

    Btw a few tips for our chat: We are mostly EU ppl with dayjob. If you write something at 2am or during normal working hours, and then don't stay still evening, we normally can't answer you.
    Also you should highlight someone, e.g. me, by writing their name.

    Cheers
     
    Last edited: Feb 27, 2019
  3. inspicous

    inspicous

    Joined:
    Feb 27, 2019
    Messages:
    14
    Resources:
    0
    Resources:
    0
    Yess! Thanks a bunch, this is exactly what I was missing. (That and showcase maps, which I've checked briefly, but I am mining through now.) I can now create trigger in Warcraft 3 standard GUI editor, go under Edit > Convert to JASS while the trigger is selected, then copy all of this to a dummy copy.j file (so I get jass syntax highlight in VSCode) and then Ctrl + Click function names to find required syntax. (And don't forget to delete / comment out / whatever this copy.j before running). Helped a TON man with this!

    Still, wondering if there's a quicker way to do this, because with a little script... I've created one for myself using windows macro and I'll come back to this later, maybe give new people an easier way once I can no longer call myself a complete newbie.

    I guess I need to learn JASS and then come back to wurst. I' currently rocking through Beginning JASS Tutorial Series
    Code (WurstScript):
    function setWildsPerRegion(int i, rect r) // int i should be refactored to be called region
        let g = GetUnitsInRectOfPlayer(r, wild) // wild is a player set to players[20] (player 21 coal; because neutral hostiles need to be reissued commands periodically because they return to their camps)
        ForGroup(g, function saveUserData)
        wilds.saveGroupHandle(i, KEY_WILDS_GROUPWILD, g)
        // KEY_WILDS_GROUPWILD is my int constant referring to a key, i.e. child key in hashtable wilds)

    function saveUserData()
         GetEnumUnit().setUserData(data)
        // I'd like to save integer (referring to a hashtable row, i.e. parent key)
        // similar to timer example attaching data?
    Question – Wurst is really simple to understand and seems GREAT as compared to call call call in JASS, but I guess I'll continue having this problems until I understand some specific JASS workings. Or?
    Code (WurstScript):
    function setWildsInRegion(int i, rect r)
        let g = GetUnitsInRectOfPlayer(r, wild)
        for unit u in g
            u.setUserData(i)
        wilds.saveGroupHandle(i, KEY_WILDS_GROUPWILD, g)
    I keep reading about "leaks" though I don't know if that's because of GUI, poor programming practices or built into some, in the end, JASS things? Like arrays not being sized (only in classes, but that's a wurst thing). Would this be a leak, am I iterating over 12783612836 or how many is there, empty units in that group?

    Question – Another thing I'm missing sorely is GUI unit (ability etc) icons compared to 'hmil' for Militia. I've found UnitIds.wurst but don't know how can I write full names instead of codes. <solved: import UnitIds and then call UnitIds class var with UnitIds.militia (I though I've tried that... maybe didn't import)>

    Presumably this would on compile time convert to pure integers anyway? I've read that you avoid using editor and instead write everything in wurst (e.g. by creating all important bits directly in code), but still, those icons are so nice. Currently I do it by setting dummy variables to unit types in GUI and copying that file to wurst (as described above) every time I need it, having edited data in GUI. Is there a better way to do this; or would you insist again that it's faulty because coding would be easier? Thanks.

    I get by with print("created " + i.toString()) with rerunning the map everytime :/

    Code (WurstScript):
    function spawn()
        let wave = waves.pop()
        doPeriodicallyCounted(0.5, wave.amount) cb ->
            createUnit(.., wave.unitId, start, ..)
            ..issuePointOrder(OrderIds.attack, target)
    Wow, thanks for that example. What do .. in createUnit do (i.e. what is it called and where can I read about it)?

    -------------------------------------

    War3 was running, therefore VSCode autosave couldn't save. I didn't notice because I was in fullscreen VSCode. Stupid mistake but that's how it is when you're learning something new man... Just hearing from another person that the code is fine, it's something else helps so much.. Yes I have RTFM (yes including the beginners section :p, but not closure events that much because it said advanced :( ), but it's hard when you've never used that specific manual and help from other people still helps ! And sorry for irking you with pushing, I didn't mean to demand help in any way. Thanks for the help, really. <3
     
    Last edited: Mar 6, 2019