1. Music Contest #10 - Results are finally published! Drop by to check some retro songs and congratulate the winners!
    Dismiss Notice
  2. Join Terraining Contest #19 and witness the aftermath!
    Dismiss Notice
  3. The 3rd Melee Mapping Contest is ON! Join in on a ride of a 4v4 melee experience!
    Dismiss Notice
  4. The 30th edition of the Modeling Contest is finally up! The Portable Buildings need your attention, so come along and have a blast!
    Dismiss Notice

Best of the Wurst 5

Discussion in 'Latest Updates and News' started by Frotty, Mar 23, 2018.

  1. Frotty

    Frotty

    Wurst Reviewer

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

    1.29 AND PTR


    The wurst team is excited and curious to see what the new PTR changes will mean for the wc3 modding community. We are anticipating the release to the stable battle.net realms, and will add support to the wurst toolchain as soon as possible.

    At this time, we do not plan to have a separate branch to support PTR installs. However, if the classic team continues to make extensive use of the testing realm, we may consider that option in the future.

    We are actively thinking about what the PTR changes will mean for us and how it should affect 2018's timeline. For example, now that 24-player maps are coming, we will prioritize support for editing map player metadata from vscode.

    [​IMG]
    24 unique player-colors, in wurst!


    UPDATES


    We are quite a bit late with our blog post this month, as there were no major updates to present and we were focusing on quality work as well as keeping an eye on Wurst's stability. That being said, in march we revamped the lambda syntax for more flexibility and cleaner code. Additionally we again have received a number of contributions from the community.

    • Type inference plus new block handling for lambda expressions and closures
    • We resolved several opened issues (#44, #45, #48) and merged 7 pull requests (#47, #49, #50, #51, #51, #54, #55, #56) for the standard library.
    • The Wurst Setup received several stability updates and we are working on further integration with the wurst tool suite.

     
    Last edited by a moderator: Mar 26, 2018
  2. Frotty

    Frotty

    Wurst Reviewer

    Joined:
    Jan 1, 2009
    Messages:
    1,291
    Resources:
    9
    Models:
    3
    Tools:
    1
    Maps:
    3
    Tutorials:
    1
    Wurst:
    1
    Resources:
    9

    NEW LAMBDA SHENANIGANS


    Types are now optional when writing lambda expressions:
    Code (WurstScript):
    interface UnitFunction
        function run(unit u)
     
    function group.foreach(UnitFunction closure)
        ...

    // Before:
    g.foreach((unit u) -> print(u.getName()))
    // Now also possible:
    g.foreach(u -> print(u.getName()))
    // Works for multiple params too:
    list.foldl((x,y) -> x+y)
    Additionally, you can now get rid of
    begin
    and
    end
    keywords for statement lambdas if the lambda is the last argument in the current line. The lambda is them moved behind the function call like so:
    Code (WurstScript):
    // Before:
    doAfter(10.0, () -> begin
        u.kill()
        createNiceExplosion()
        doMoreStuff()
    end)

    // Now also possible:
    doAfter(10.0) ->
        u.kill()
        createNiceExplosion()
        doMoreStuff()
    With the new syntax the indentation defines the block. This allows one to define customized control flow, which looks very similar to a construct built into the language.

    The
    begin
    and
    end
    syntax will of course remain for backwards compatibility and for when the lambda isn't the last argument.



    WURST SPELL EXCURSION


    Spells are a very popular choice to script in wc3, and most maps have at least some scripted abilities.

    Here we will show a concise example of how to combine object-editing, event listening and the use of closures to create a decent spell without much hassle.

    In this case we are making a timed explosion spell called "Conflagration". The explosion applies a burn debuff to hit enemies, which causes successive conflagration hits to deal bonus damage. We aim to make the spell easily configurable and in the end upload it to github so it can be easily imported into a wurst project.

    CONFIGURATION PACKAGE


    To make a nicely configurable spell, it can sometimes help to think about the configuration package first. Based on the concept, we know in what way we want to allow the user to customize the ability, like:

    - base damage, bonus damage
    - spell radius, effect, duration
    - buff duration, effect

    To put this into wurst code, we create a new package with the variables from the list. In order for them to be configurable by the user, we must annotate them with
    @configurable
    .

    Code (WurstScript):
    package ConflagrationConstants
    import public Assets

    @configurable public let BASE_DAMAGE = 50.
    @configurable public let BONUS_DAMAGE = 50.

    @configurable public let SPELL_EFFECT_PATH = Units.infernalBirth
    @configurable public let BONUS_EFFECT_PATH = Abilities.fireBallMissile
    @configurable public let SPELL_EFFECT_DURATION = .75
    @configurable public let SPELL_RADIUS = 256.

    @configurable public let SPELL_ICON = Icons.bTNBreathOfFire
    @configurable public let SPELL_NAME = "Conflagration"
    @configurable public let SPELL_TT_NORMAL = "Cast Conflagration"
    @configurable public let SPELL_TT_EXTENDED = "Conjures a firey explosion at the " +
        "target, damaging nearby enemies and applying a buff, which will cause them to " +
        "take more damage on succeeding hits of this spell."

    @configurable public let BUFF_DURATION = 7.5
    @configurable public let BUFF_EFFECT_PATH = Abilities.incinerateBuff

    @configurable public let BUFF_NAME = "Conflagrated"
    @configurable public let BUFF_TT = "This unit has weakness to fire"
    Clearly, the above paints a picture of a quick, unit-style spell with fairly low damage and duration.

    SPELL OBJECTS


    Next we'll generate the required objects for our spell. We will be needing an ability object for the unit that uses the spell, and a buff object that displays the presence of conflagration visually and as status.

    Thus we create a new package:
    Code (WurstScript):
    package ConflagrationObjects
    import public ConflagrationConstants
    import public BuffObjEditing
    import ChannelAbilityPreset

    public let SPELL_ID = compiletime(ABIL_ID_GEN.next())
    public let BUFF_OBJ = compiletime(createDummyBuffObject(BUFF_NAME, BUFF_TT,    Icons.bTNFireBolt, Abilities.incinerateBuff, "chest"))

    @compiletime function genObj()
        new ChannelAbilityPreset(SPELL_ID, 4, true)
        ..setName(SPELL_NAME)
        ..presetTooltipNormal((int lvl) -> SPELL_TT_NORMAL)
        ..presetTooltipNormalExtended((int lvl) -> SPELL_TT_EXTENDED)
        ..presetIcon(SPELL_ICON)
        ..presetButtonPosNormal(0, 0)
        ..presetManaCost((int lvl) -> 0)
        ..presetCooldown((int lvl) -> 4.)
        ..presetHotkey("Q")
        ..presetTargetTypes(Targettype.POINT)
        ..presetAreaofEffect((int lvl) -> SPELL_RADIUS)
        ..presetOption(Option.TARGETIMAGE, true)

    SPELL EFFECT


    Finally we create the actual effect. At the map's initialization we register a spell event listener, which will fire when any unit casts our generated spell.

    Code (WurstScript):
    package Conflagration
    import ConflagrationObjects
    import ClosureTimers
    import ClosureForGroups
    import RegisterEvents
    import EventHelper
    import HashMap

    let buffId = BUFF_OBJ.abilId
    let buffMap = new HashMap<unit, CallbackSingle>()
    init
        registerSpellEffectEvent(SPELL_ID) ->
            let caster = GetTriggerUnit()
            let tpos = getSpellTargetPos()
            flashEffect(SPELL_EFFECT_PATH, tpos)
            doAfter(SPELL_EFFECT_DURATION) ->
                forUnitsInRange(tpos, SPELL_RADIUS)  u ->
                    if u.hasAbility(buffId)
                        caster.damageTarget(u, BONUS_DAMAGE)
                        flashEffect(BONUS_EFFECT_PATH, tpos)

                    caster.damageTarget(u, BASE_DAMAGE)
                    u.addAbility(buffId)
                    if buffMap.has(u)
                        destroy buffMap.get(u)
                    let cb = doAfter(BUFF_DURATION) ->
                        if buffMap.has(u)
                            buffMap.remove(u)
                            u.removeAbility(buffId)
                    buffMap.put(caster, cb)

    [​IMG]
    The spell in action


    CREATING A REPOSITORY FOR OUR PROJECT


    Finally, let's create a git dependency from our wurst project. We will be using GitHub and it's corresponding desktop app which requires a free account. If you don't already have one, please create an account and setup the app.

    Once you have the app setup, we can create a new git repo inside our project folder by choosing
    File -> Add Local Repository
    . Select the root of your project and then select
    create a repository
    :

    [​IMG]

    Leave all settings as is and create the repository:

    [​IMG]

    Hooray, our repository is created. All our existing files have been added to an initial commit. Files that shouldn't be versioned are automatically ignored by the configuration generated by the setup tool. We can now publish our repository:

    [​IMG]

    If everything went well, you repository is now published. You can view the repository we created in this blog post here: Frotty/ConflagrationSpell

    Note If you want to know more about the git workflow, you can checkouts everal tutorials online, like this one.

    USING THE REPOSITORY AS WRUST DEPENDENCY


    Open the setup tool and import the wurst.build file of some other project. Under
    Advanced
    you can now enter the link to the repository that we created above. Hit
    Update Project
    to update the dependencies.

    [​IMG]

    [​IMG]

    Reload VSCode and you should be able to import the spell as necessary.





    And that's it! Thanks for reading another Best of the Wurst blog-thing.

    Cheers
    Frotty & Cokemonkey11
     
    Last edited by a moderator: Mar 26, 2018
  3. BlueSaint

    BlueSaint

    Joined:
    Jun 18, 2012
    Messages:
    2,668
    Resources:
    3
    Tools:
    1
    Spells:
    2
    Resources:
    3
    omg the landba features are cool they are cool!
    upload_2018-3-26_22-32-6.gif
     
  4. Robbepop

    Robbepop

    Joined:
    Mar 6, 2008
    Messages:
    857
    Resources:
    7
    Maps:
    6
    Spells:
    1
    Resources:
    7
    I can see myself becoming a WurstScript user if I happen to start modding WC3 again. :)
     
  5. Chaosy

    Chaosy

    Joined:
    Jun 9, 2011
    Messages:
    10,395
    Resources:
    17
    Maps:
    1
    Spells:
    10
    Tutorials:
    6
    Resources:
    17
    Kinda unrelated but, are there plans of adding a better way of combining strings?

    in C#
    $"{u.getName()}'s owner is {u.getOwner().toString()}"

    in Javascript
    `${u.getName()}'s owner is ${u.getOwner().toString()}`

    or maybe it exists and I am just unaware.
     
  6. Frotty

    Frotty

    Wurst Reviewer

    Joined:
    Jan 1, 2009
    Messages:
    1,291
    Resources:
    9
    Models:
    3
    Tools:
    1
    Maps:
    3
    Tutorials:
    1
    Wurst:
    1
    Resources:
    9
    Long time no see Robbe :)
    Maybe with the next patches it becomes more interesting again.

    Yea we have thought about adding
    "You got $(goldVal) gold"
    but it's not a priority right now.
    If you want Java-like auto usage of .toString() you could overload the + operator for those types. Though not really recommended.
    There also exist the .format() functions.
     
    Last edited: Mar 29, 2018
  7. MyPad

    MyPad

    Spell Reviewer

    Joined:
    May 9, 2014
    Messages:
    1,088
    Resources:
    2
    Models:
    1
    Icons:
    1
    Resources:
    2
    What kind of sorcery is this? Such a spell cast on me has converted me, and I will rue the day I no longer became a vJASSer.

    Seriously, this kind of stuff is impressive.
     
  8. Magnum666

    Magnum666

    Joined:
    Jul 8, 2008
    Messages:
    22
    Resources:
    0
    Resources:
    0
    That Looks so Easy Now , as _OBJ Spell && Effect
    (if someone doesnt know what is OBJ , go search in the WEB for Coders what is OBJ and how can i use it)