1. This site uses cookies. By continuing to use this site, you are agreeing to our use of cookies. Learn More.
  2. Group up and create a Warcraft hero based on a member of the Hive and win up to 100 rep and a rank icon. Enter the team contest now!
    Dismiss Notice
  3. The results for Mini-Mapping Contest #14 is up! Congratulate the winners here!
    Dismiss Notice
  4. The Concept Art Competition #10 has come to an end. Check out the results!
    Dismiss Notice
  5. Paired Modeling/Texturing Contest#3 has finished. Check out the results!
    Dismiss Notice
  6. The Music Contest #9 - Steampunk has begun! Tell the nearest aristocrat, aviator or adventurer.
    Dismiss Notice
  7. The rewards for the 27th texturing contest have been upped and deadline extended. Enter now to win the new cash price.
    Dismiss Notice
  8. The [$100 Prize Pool] Special Melee Mapping Contest - Results are out! Congratulate the winners!
    Dismiss Notice
  9. We need your help nominating resources for or next YouTube video. Post here now.
    Dismiss Notice

Best of the Wurst #2

Discussion in 'Latest Updates and News' started by Frotty, Dec 3, 2017.

  1. Frotty

    Frotty

    Wurst Reviewer

    Joined:
    Jan 1, 2009
    Messages:
    1,097
    Resources:
    9
    Models:
    3
    Tools:
    1
    Maps:
    3
    Tutorials:
    1
    Wurst:
    1
    Resources:
    9
    [​IMG]

    This is the second issue in a regular series of news posts about wurst and the wurstscript community. Unlike the previous issue, this one is short, and focused on this month's progress. We intend to use this format for all future posts.

    What is wurst? Wurstscript is a programming language that compiles to JASS (the language used for scripting warcraft 3 custom games), and is developed alongside a suite of tools, which provide a coherent and modern modding development experience. It can even work alongside maps written in vJass. Wurstscript is designed to make hard problems easier and more elegant, and easy problems dead simple.

    The theme of this issue is "wurstscript in practice", where we want to show how regular ordinary maps use wurstscript, instead of focusing on higher level language features.


    Toolchain updates
    • The setup tool has been moved to a separate repository. It now checks for new versions of itself as well as silently checking for compiler and project dependency updates. To get these __critical__ new features, please do update your tool by downloading at the link above.
    • Unit Tests now have map-wide read access to compiletime resources. This allows the author to unit-test some behaviors that were previously not possible.
    • Added "hashtable mocks" for string data operations, which allows them to work at compiletime and in unit tests.
    • Bug fixes:
      • Fixed some edge cases where vscode autocomplete would misbehave.
      • Fixed a bug which caused the `buildmap` command to emit an invalid mapfile in certain cases.
      • Changing between files in vscode no longer causes an invalid buffer ("ambigious reference error").
      • Standard library fixes, and new features.
      • Fixed some rare cases of ascii-int parsing problems, which improves JASS compliance.
    Special thanks to @DD_legionTN and @HappyTauren for their testing and contribution efforts.


    Hiveworkshop integration

    This month a number of us have been thinking about, and acting on, ways of improving unification between wurst's development and hive workshop.

    One achievement on this front is the addition of the Wurst tag, now enabled for all code-related submissions. This includes:
    • Spell submissions.
    • Triggers & Scripts posts.
    • JASS (code) submissions.
    [​IMG]

    We were also excited to see multiple submissions before this was even announced!

    You should expect further wurst-related activity in the near future as a number of community members are getting involved.

    We're excited to see what you've done that might be fun or interesting but doesn't quite fit in the standard library - and even moreso interested to see what kind of magic you can work up in spell submissions. For code review feedback always feel free to tag @Frotty or @Cokemonkey11 .

    ---

    As requested by our readers, we're going to include a code snippet example in our posts from now on. In line with this month's theme, here's a practical and simple example that shows how wurst can make an easy problem trivial:
    Code (WurstScript):
    package SimpleSpell
    // Augments the Warden blink ability to deal damage to units in the target
    // area.  Units with low enough health are instead slain.
    import Assets
    import ClosureForGroups
    import EventHelper
    import RegisterEvents

    constant ID_BLINK = 'A000'

    constant BASE_DAMAGE    =  100.
    constant DAMAGE_RADIUS  =  150.
    constant SLAY_THRESHOLD =  200.
    constant BLINK_RANGE    = 1000.

    constant EFFECT_POISON = Abilities.poisonStingTarget
    constant EFFECT_SLAY   = Objects.nightElfBloodArcher

    function onEffect()
        let caster = GetTriggerUnit()

        forUnitsInRange(getSpellTargetPos(), DAMAGE_RADIUS, (unit u) -> begin
            if caster.getOwner().isEnemyOf(u.getOwner()) and u.isAlive()
                if u.getHP() <= SLAY_THRESHOLD
                    u.addEffect(EFFECT_SLAY, "origin").destr()
                    caster.damageTarget(u, SLAY_THRESHOLD * 2.)
                else
                    u.addEffect(EFFECT_POISON, "origin").destr()
                    caster.damageTarget(u, BASE_DAMAGE)
        end)

    init
        registerSpellEffectEvent(ID_BLINK, function onEffect)
     
    Then when the wurst compiler is run, the above emits nicely readable Jass (see below). This is just one example of wurst providing zero-cost abstraction, since the inliner would ultimately inline e.g. getSpellTargetPos into 2 local definitions - a topic we will discuss more in future posts.

    Code (vJASS):
    function getSpellTargetPos takes nothing returns real
        set getSpellTargetPos_return_x = GetSpellTargetX()
        set getSpellTargetPos_return_y = GetSpellTargetY()
        return getSpellTargetPos_return_x
    endfunction

    function forUnitsInRange takes real pos_x, real pos_y, real radius, integer c returns nothing
        call pushCallback(c)
        call GroupEnumUnitsInRange(Group_ENUM_GROUP, pos_x, pos_y, radius, ClosureForGroups_filter)
        call popCallback()
    endfunction

    function onEffect takes nothing returns nothing
        local unit caster_2 = GetTriggerUnit()
        local real temp_x = getSpellTargetPos()
        local real temp_y = getSpellTargetPos_return_y
        local integer clVar = alloc_Closure_2()
        set caster[clVar] = caster_2
        call forUnitsInRange(temp_x, temp_y, 150., clVar)
        set caster_2 = null
    endfunction
     


    Next month we'll return to a more hardcore example, demonstrating `@compiletime function`s + expressions, and their uses.

    We look forward to your comments! As usual, we chat all things wurst at the #inwc.de-maps IRC channel.
     
    Last edited: Dec 4, 2017
  2. Chaosy

    Chaosy

    Joined:
    Jun 9, 2011
    Messages:
    9,287
    Resources:
    13
    Spells:
    8
    Tutorials:
    5
    Resources:
    13
    Because it sounds like "worst" which is kinda humorous.
    (at least that's what I'd like to think)
     
  3. BlueSaint

    BlueSaint

    Joined:
    Jun 18, 2012
    Messages:
    2,562
    Resources:
    2
    Spells:
    2
    Resources:
    2
    Nice. I like the tags.
     
  4. HappyTauren

    HappyTauren

    Joined:
    Nov 3, 2006
    Messages:
    7,838
    Resources:
    84
    Models:
    61
    Icons:
    20
    Packs:
    1
    Tutorials:
    2
    Resources:
    84
    Speaking of the wurst inliner, it is actually pretty amazing, for processing long chains of commands it can create a single function that no human would write and maintain, and wurst code would still be pretty to look at even though the emitted jass is very optimized. I think people who are skeptical of wurst's performance seriously need to check out how it deals with processing functions and vector math, which are all really fast, and the abstractions have little or no cost.
     
  5. Cokemonkey11

    Cokemonkey11

    Wurst Reviewer

    Joined:
    May 9, 2006
    Messages:
    3,074
    Resources:
    16
    Maps:
    5
    Spells:
    3
    Tutorials:
    1
    JASS:
    7
    Resources:
    16
    I'm really quite happy with this post for a bunch of reaasons. Just to recap

    * We really wanted to break the chain and get regular, monthly posts. This is the first step to that and went quite smoothly.
    * Unification has been huge. It was never really my intenton to "recruit" hive users, but rather, just to inform. The interest (imo) been quite great, and I can especially thank Ralle for timely feedback and responses to us.
    * Bugs fixed by new users and activity from old ones too. Cool! Testing loads of standard library stuff has never been something I had time for because my first priority was map making. Having people interested in showing the standard library to be high quality is huge.
    * Blog themes seemed to have worked well. I'm pleased that we managed to write a month worth of content about 'wurstscript in practice'.

    Please give us feedback on the blog format and the script example. Is the blog still at too high a level? What do you want to hear about?

    > Speaking of the wurst inliner, it is actually pretty amazing, for processing long chains of commands it can create a single function that no human would write and maintain, and wurst code would still be pretty to look at even though the emitted jass is very optimized. I think people who are skeptical of wurst's performance seriously need to check out how it deals with processing functions and vector math, which are all really fast, and the abstractions have little or no cost.

    Yes, it's cool. Optimisation and inliner is something we talked about for a blog theme maybe in the near future.
     
  6. Trigger.edge

    Trigger.edge

    Joined:
    Jun 21, 2012
    Messages:
    423
    Resources:
    0
    Resources:
    0
    I am really impressed with this, maybe if post more samples of how to use it, would convince me even more :D
     
  7. HappyTauren

    HappyTauren

    Joined:
    Nov 3, 2006
    Messages:
    7,838
    Resources:
    84
    Models:
    61
    Icons:
    20
    Packs:
    1
    Tutorials:
    2
    Resources:
    84
    You can make a specific suggestion if you want - what kind of a sample would you like?
     
  8. Trigger.edge

    Trigger.edge

    Joined:
    Jun 21, 2012
    Messages:
    423
    Resources:
    0
    Resources:
    0
    Okay, let's say a simple spell snipet with basics functions: OnInit, OnCast, OnLoop, destroy, etc...
     
  9. HappyTauren

    HappyTauren

    Joined:
    Nov 3, 2006
    Messages:
    7,838
    Resources:
    84
    Models:
    61
    Icons:
    20
    Packs:
    1
    Tutorials:
    2
    Resources:
    84
    There you go. This is a simple dash spell written in about 60 lines of code, it can obviously be further customized. It also saves a reference from unit to the instance of dash (if ongoing) so you can easily associate units with their instance of a particular spell.

    Code (vJASS):

    package Dash
    import LinkedListModule
    import ClosureTimers
    import HashMap

    public class Dash
        use LinkedListModule

        protected static constant TIMEOUT = 0.01
        protected static constant ABIL_ID = 'A000'

        protected static let map = new HashMap<unit, thistype>()
        protected static let duration = 1.0

        protected unit caster
        protected real dist
        protected int ticks

        function durationOfLevel(int lvl) returns real
            return lvl * 0.6

        construct(unit caster)
            let lvl = caster.getAbilityLevel(ABIL_ID)
            this.caster = caster
            this.dist = lvl * 400.
            this.ticks = (durationOfLevel(lvl)/TIMEOUT).toInt()

            map.put(caster, this)

        function process()
            caster.setPos(caster.getPos().polarOffset(caster.getFacingAngle(), dist * TIMEOUT))
            ticks--
            if ticks <= 0
                destroy this

        ondestroy
            map.remove(caster)

        static function onLoop()
            for inst in Dash
                inst.process()

        static function onInit()
            CreateTrigger()
                ..registerAnyUnitEvent(EVENT_PLAYER_UNIT_SPELL_CAST)
                ..addCondition(Condition(()-> GetSpellAbilityId() == ABIL_ID))
                ..addAction(()-> new Dash(GetTriggerUnit()))

            doPeriodically(TIMEOUT, (CallbackPeriodic cb) -> onLoop())

        static function ofUnit(unit u) returns thistype
            if map.has(u)
                return map.get(u)
            else
                return null

    init
        Dash.onInit()

     
     
    Last edited: Dec 5, 2017
  10. Trigger.edge

    Trigger.edge

    Joined:
    Jun 21, 2012
    Messages:
    423
    Resources:
    0
    Resources:
    0
    I have this error

    [​IMG]
     

    Attached Files:

  11. HappyTauren

    HappyTauren

    Joined:
    Nov 3, 2006
    Messages:
    7,838
    Resources:
    84
    Models:
    61
    Icons:
    20
    Packs:
    1
    Tutorials:
    2
    Resources:
    84
    Have you set the standard library as a dependency?

    Oh btw, your package name has to be the same as your file name (without the extension)! It can't be "DashSpellTest" and "Dash".

    If you want to test my script, you have to name the file Dash.wurst. Or rename the package.
     
    Last edited: Dec 5, 2017
  12. Trigger.edge

    Trigger.edge

    Joined:
    Jun 21, 2012
    Messages:
    423
    Resources:
    0
    Resources:
    0
    I solved it, I put the same name of the file ;) ,
    However, I get these new errors:

    upload_2017-12-5_18-37-44.png

    upload_2017-12-5_18-38-47.png
     
  13. Trigger.edge

    Trigger.edge

    Joined:
    Jun 21, 2012
    Messages:
    423
    Resources:
    0
    Resources:
    0
    How I can re-compile the solution?
     
  14. HappyTauren

    HappyTauren

    Joined:
    Nov 3, 2006
    Messages:
    7,838
    Resources:
    84
    Models:
    61
    Icons:
    20
    Packs:
    1
    Tutorials:
    2
    Resources:
    84
    What is "\b" supposed to escape?

    Also, your war3map.j has to be wurst compatible. I don't know exactly what that includes, but @Frotty or @Cokemonkey11 might be able to help. I also suggest you create a new thread with the [Wurst] tag to further discuss these specific things.
     
  15. Frotty

    Frotty

    Wurst Reviewer

    Joined:
    Jan 1, 2009
    Messages:
    1,097
    Resources:
    9
    Models:
    3
    Tools:
    1
    Maps:
    3
    Tutorials:
    1
    Wurst:
    1
    Resources:
    9
    @Trigger.edge please make a new thread with this problem instead of this news thread.
    On that note, "\b" isn't an allowed escapestring in wurst at the moment. should it be?
    "step" is a reserved wurst keyword. You will need to rename the variable to something else.
     
  16. Trigger.edge

    Trigger.edge

    Joined:
    Jun 21, 2012
    Messages:
    423
    Resources:
    0
    Resources:
    0
    I'm sorry, all above was a mistake on my part, since I was trying to test a map with MemoryHack script.
     
  17. Frotty

    Frotty

    Wurst Reviewer

    Joined:
    Jan 1, 2009
    Messages:
    1,097
    Resources:
    9
    Models:
    3
    Tools:
    1
    Maps:
    3
    Tutorials:
    1
    Wurst:
    1
    Resources:
    9
    yes, but by doing that you discovered a legit bug in the Jass parsing :)
    I take it then, that the ExampleMap works fine?
     
  18. Trigger.edge

    Trigger.edge

    Joined:
    Jun 21, 2012
    Messages:
    423
    Resources:
    0
    Resources:
    0
    At the moment it has worked correctly.

    It is possible to add a functionality like
    //# +nosemanticerror
    to prevent parsing some jass code?