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.

[Release] WurstScript - A Wurst to Jass Compiler & IDE

Discussion in 'Warcraft Editing Tools' started by Frotty, Jul 25, 2013.

  1. Frotty

    Frotty

    Wurst Reviewer

    Joined:
    Jan 1, 2009
    Messages:
    1,437
    Resources:
    11
    Models:
    3
    Tools:
    1
    Maps:
    5
    Tutorials:
    1
    Wurst:
    1
    Resources:
    11

    WurstScript


    by peq & Frotty
    with contributions from Crigges & muzzel


    [​IMG]
    [​IMG]

    WurstScript is a Scripting language, which can, similar to vJass, cJass and zinc, be translated to Jass.


    Why a new Scripting language?




    The only alternative to Wurst is vJass (or cJass, zinc, ..., which are basically all the same).

    If you are interested in what we did not like about vJass click the button:
    vJass critique


    1. Editor Support



    vJass is mostly based on text-replacements and generation (vJass modules, textmacros). This makes it hard to create a good editor for vJass, including features like autocomplete.

    Wurst instead goes for simple, structured code, that can be analyzed in a single compiler-phase. vJass however needs more phases.

    2. Type-safety



    vJass isn't typesafe. Look at this example:

    *vJass Code*

    Code (vJASS):
    struct A
        endstruct

        struct B
        endstruct

        private function init takes nothing returns nothing
            local A a = A.create()
            local B b = A.create() // no error ...
            set a = 42 // no error ...
            set a = "bla" // pjass error
        endfunction


    vJass doesn't check if a variable of type B only stores values of type B. This leads to frequent errors, which can be discovered late or you receive a pJass Error, which isn't easy to understand.

    The Wurst counterpart (Screenshot from the Eclipse Plugin):

    [​IMG]

    3. Verbose syntax



    vJass features several redundant Syntax-Elements. For example "set", "call" or "takes nothing returns nothing". Additionally vJass doesn't have many features that allow for writing readable, clear code. Particularly there only exists one type of loop.

    WurstScript features less verbosity, but without losing similarity to (v)Jass so switching is easier, and rapid code production for faster map creation.


    Syntax





    So how does it look like? Here is a simple spell to give you a first idea. The spell fires a missile to the target location, where it damages and knocks back all units in a certain range.

    Code (vJASS):

    package WarStomp

    import ClosureEvents
    import ClosureTimers
    import Fx
    import Knockback
    import TempGroups

    constant spellId = 'A001'
    constant impactAoe = 600.
    constant missileType = "AbilitiesWeaponsAncientProtectorMissileAncientProtectorMissile.mdl"
    constant missileSpeed = 1000.
    constant gravity = 981.
    constant effectType = "AbilitiesSpellsHumanThunderclapThunderClapCaster.mdl"
    constant effectType2 = "ObjectsSpawnmodelsUndeadImpaleTargetDustImpaleTargetDust.mdl"
    constant maxSpellDamage = 100.
    constant lvlDamageBonus = 25.
    constant knockbackStrength = 700.
    constant knockbackTime = 1.5

    class WarStomb
        unit caster
        int spellLvl
        Fx missile
        vec3 missileVelocity
        timer t = getTimer()
       
        construct(unit caster, int spellLvl, vec2 targetPos)
            this.caster = caster
            this.spellLvl = spellLvl
            vec2 casterPos = caster.getPos()
            angle castDirection = casterPos.angleTo(targetPos)
            real distToTarget = casterPos.distToVec(targetPos)
           
            // the initial z-speed is calculated, so that the z-speed will be 0 after half the flytime
            let flyTime = distToTarget / missileSpeed
            let speedZ = (flyTime/2) * gravity
           
            let missileVelocity2D = missileSpeed * castDirection.direction()
            missileVelocity = missileVelocity2D.withZ(speedZ)
           
            missile = new Fx(casterPos, castDirection, missileType)
            missile.setScale(1.5)
           
            t.setData(this castTo int)
            t.startPeriodic(ANIMATION_PERIOD, function callMoveMissile)
           
        static function callMoveMissile()
            (GetExpiredTimer().getData() castTo WarStomb).moveMissile()
           
        function moveMissile()
            vec3 missilePos = missile.getPos3d()
            missilePos += missileVelocity * ANIMATION_PERIOD
            missile.setPos(missilePos)
            missileVelocity.z -= gravity * ANIMATION_PERIOD
            if missilePos.z <= 0
                onImpact()
           
        function onImpact()
            let missilePos = missile.getPos2()
            //create a big effect at location location of the missile
            Fx fx = new Fx(missilePos, angle(0), effectType)
                ..setScale(2)
                ..flash(effectType2)
            //destroy the effect after 2 seconds
            doAfter(2, () -> destroy fx)
           
            for unit u from ENUM_GROUP..enumUnitsInRange(missilePos, impactAoe)
                let distToImpact = missilePos.distToVec(u.getPos())
                let distanceFactor = 1 - (distToImpact / impactAoe)
                //damage the unit relative to it's damage distance to the caster
                let damage = (maxSpellDamage + spellLvl * lvlDamageBonus)*distanceFactor
                caster.damageTarget(u,  damage)
               
                //knockback the target unit away from the impact location
                new Knockback(caster, u, knockbackStrength * distanceFactor,
                                knockbackTime, missilePos.angleTo(u.getPos()))
            destroy this
           
        ondestroy
            t.release()
            destroy missile
           
    init
        //Creates a new instance of the class WarStomb if the spell is casted
        onPointCast(spellId, (unit caster, int spellLvl, vec2 targetPos) ->
            new WarStomb(caster, spellLvl, targetPos))
     



    As you can see, Wurst has an indentation based syntax, and therefore you do not have to write words like endif or endfunction. The example also shows some of the syntactic sugar in Wurst, for example the for-from loop, update-assignments with +=, or the dot-dot-expression. You can also see some of the features like packages, classes, closures and tuples.

    Features



    The full list of features is documented in the Wurst Manual. Here we present only some selected features.



    Local Type Inference + Local Variable Freedom



    The type of local variables can automatically be derived from the initial value. Furthermore variables can be declared at any position in a function, not just the beginning.

    Code (vJASS):
       
        // "let" defines a local constant
        let harald = CreateUnit(Player(0), 'hfoo', x, y, 0)
        // "var" defines a local variable
        var otto = CreateUnit(Player(0), 'hfoo', x, y, 0)
        // traditional way works too
        unit heinz = CreateUnit(Player(0), 'hfoo', x, y, 0)
     


    We encourage you to use let whenever possible, because code is easier read when you know which variables are changed later and which variables keep their initial value.

    Extension functions



    Extension functions allow to add specific functions to an already existing type, which can be used via dot-syntax.

    Declaration:
    Code (vJASS):

        public function unit.getOwner() returns player
            return GetOwningPlayer(this)
           
        function player.getName() returns string
            return GetPlayerName(this)
     


    Usage:

    Code (vJASS):
       
        print(GetKillingUnit().getOwner().getName() + " killed " +
            GetTriggerUnit().getOwner().getName() + "!")
     



    Extension functions have two pros in comparison to normal functions:
    • Functions are easier to find using auto-complete in Eclipse
    • In many cases the readability is improved, as chained calls are often easier to read than nested calls. With chained calls the order of execution is from left to right, while with nested calls the execution is from the inner to the outer:
      Code (vJASS):

          // nested function calls:
          name = GetPlayerName(GetOwningPlayer(u))
          // chained function calls
          name = u.getOwner().getName()
       


    Tuples



    A Tuple is a very simple Datatype. It allows to group several values into one. This allows treating the group of values as a group. Other than classes, tuples don't create any overhead. They don't have to be created or destroyed and can be used for primitive data types (int, string, etc.). A good example are vectors(from the stdlib):

    Definition:

    Code (vJASS):

        // A 2d vector with the components x and y
        public tuple vec2( real x, real y )
       
        // Operator overloading functions:
        public function vec2.op_plus( vec2 v )  returns vec2
            return vec2(this.x + v.x, this.y + v.y)
       
        public function vec2.op_minus( vec2 v ) returns vec2
            return vec2(this.x - v.x, this.y - v.y)
           
        public function vec2.op_mult(real factor) returns vec2
            return vec2(this.x*factor, this.y*factor)
       
        // dot product:
        public function vec2.dot( vec2 v ) returns real
            return this.x*v.x+this.y*v.y
       
        // length:
        public function vec2.length() returns real
            return SquareRoot(this.x*this.x+this.y*this.y)
       
        // normalized Vector:
        public function vec2.norm() returns vec2
            real len = this.length()
            real x = 0
            real y = 0
            if (len != 0.0)
                x = (this.x / len)
                y = (this.y / len)
            return vec2(x,y)
       
        public function vec2.polarOffset(real angle, real dist) returns vec2
            return vec2(this.x + Cos(angle)*dist, this.y + Sin(angle)*dist)
     


    Usage:

    Code (vJASS):

        // A projectile homes the target unit(variable following)
        function followHero()
            // Increase angle
            angle += TURN_SPEED*DT
            // calculate new position
            let newPos = following.getPos().polarOffset(angle, RANGE)
            // current velocity is calculated from the difference between old and new position
            vel = (newPos - pos)*(1/DT)
            pos = newPos
            fx.setPos(pos.x, pos.y)
            SetUnitFacing(fx, (angle + bj_PI/2)*bj_RADTODEG)
            checkCollisions()
           
        // projectile moving forward
        function moveForward()
            // Add velocity to position
            pos = pos + vel*DT
            if not pos.inBounds()
                destroyed = true
            else
                fx.setPos(pos.x, pos.y)
                checkCollisions()
     


    Anonymous functions / closures



    With anonymous you can define a new function where it is needed. This is useful for timers, as shown in the following example, where the timer t is started with an anonymous function:

    Code (vJASS):

    class Fireball
        timer t
        //...
       
        construct(unit caster, vec2 target)
            // ...
            t = getTimer()
            t.setData(this castTo int)
            t.start(0.05, () -> begin
                let fireball = GetExpiredTimer().getData() castTo Fireball
                fireball.move()
            end)
       
        function move()
            // do stuff
     


    Closures are more than just anonymous functions. They also capture variables. This allows to write some very concise code. For example it is easily possible to destroy an Fx after some time:

    Code (vJASS):

        let fx = new Fx(pos, facing, model)
        fx.setScale(2.0)
        // destroy fx after 2 seconds:
        doAfter(2.0, () -> destroy fx)
     


    Here the closure captured the local variable fx without the need to get a timer, attach stuff to the timer, and all that boilerplate code. The doAfter function is defined in the standard library and it can not only destroy Fx objects. You can write any code inside the closure and it will run after the given time.

    Of course you can do more crazy stuff with closures. Here is the spell from the introduction, but implemented with closures instead of a class:

    Code (vJASS):

    package WarStompCl

    import ClosureEvents
    import ClosureTimers
    import ClosureForGroups
    import Fx
    import Knockback

    constant spellId = 'A001'
    constant impactAoe = 600.
    constant missileType = "AbilitiesWeaponsAncientProtectorMissileAncientProtectorMissile.mdl"
    constant missileSpeed = 1000.
    constant gravity = 981.
    constant effectType = "AbilitiesSpellsHumanThunderclapThunderClapCaster.mdl"
    constant effectType2 = "ObjectsSpawnmodelsUndeadImpaleTargetDustImpaleTargetDust.mdl"
    constant maxSpellDamage = 100.
    constant lvlDamageBonus = 25.
    constant knockbackStrength = 700.
    constant knockbackTime = 1.5

    init
        onPointCast(spellId, (unit caster, int spellLvl, vec2 targetPos) -> begin
            let casterPos = caster.getPos()
            let castDirection = casterPos.angleTo(targetPos)
            let distToTarget = casterPos.distToVec(targetPos)
           
            // the initial z-speed is calculated, so that the z-speed will be 0 after half the flytime
            let flyTime = distToTarget / missileSpeed
            let speedZ = (flyTime/2) * gravity
           
            let missileVelocity2D = missileSpeed * castDirection.direction()
            var missileVelocity = missileVelocity2D.withZ(speedZ)
           
            let missile = new Fx(casterPos, castDirection, missileType)
                ..setScale(1.5)
           
            doPeriodically(ANIMATION_PERIOD, (CallbackPeriodic cb) -> begin
                var missilePos = missile.getPos3d()
                missilePos += missileVelocity * ANIMATION_PERIOD
                missile.setPos(missilePos)
                missileVelocity.z -= gravity * ANIMATION_PERIOD
                if missilePos.z <= 0
                    let impactPos = missilePos.toVec2()
                   
                    //create a big effect at location location of the missile
                    let fx = new Fx(missilePos, angle(0), effectType)
                        ..setScale(2)
                        ..flash(effectType2)
                    //destroy the effect after 2 seconds
                    doAfter(2, () -> destroy fx)

                    forUnitsInRange(impactPos, impactAoe, (unit u) -> begin
                        let distToImpact = impactPos.distToVec(u.getPos())
                        let distanceFactor = 1 - (distToImpact / impactAoe)
                        //damage the unit relative to it's damage distance to the caster
                        let damage = (maxSpellDamage + spellLvl * lvlDamageBonus)*distanceFactor
                        caster.damageTarget(u,  damage)
                       
                        //knockback the target unit away from the impact location
                        new Knockback(caster, u, knockbackStrength * distanceFactor,
                                        knockbackTime, impactPos.angleTo(u.getPos()))
                    end)
                   
                    destroy missile
                    // stop periodic call:
                    destroy cb
                   
            end)
        end)
     


    Please note, that this coding style is not recommended. Dividing code into several named functions is much more readable. Also the performance is worse, when using closures.

    Compiletime functions



    You can execute Wurst code at compile-time. Wurst includes some pseudo-natives which can be executed at compile-time to generate object-editor entries. This is similar to what can be done with the ObjectMerger tool, but it also comes with nice readable method names. Here is an example which creates a spell based on Channel and a tower unit for each level:

    Code (vJASS):

    @compiletime function generateSpell()
        // based on shadow hunter serpent wards
        int levelCount = 4
        let def = new ChannelSpellPreset(GUN_TURRET_SPELL_ID, levelCount)
            ..setName("Gun Turret")
            ..setIcon("ReplaceableTexturesCommandButtonsBTNElvenGuardTower.blp")
            ..setIconNormal("ReplaceableTexturesCommandButtonsBTNElvenGuardTower.blp")
            ..setTargetType(Targettype.PTARGET)
            ..setOption(Option.VISIBLE, true)
            ..setFollowThroughTime(0.4)
            ..setDisablesOther(false)
        for lvl = 1 to levelCount
            createTower(lvl)
            def.setCastingTime(lvl,0)
            def.setCastRange(lvl, 300)

    function createTower(int lvl)
        // based on high elven guard tower:
        let def = new BuildingDefinition(GUN_TURRET_TOWER_ID + lvl, 'negt')
            ..setName("Gun Turret Level " + lvl.toString())
            ..setHitPointsMaximumBase(100 + lvl*100)
        // no projectile
        def.setAttack1ProjectileArt("")
        // 0 damage
        def..setAttack1DamageBase(-1)
            ..setAttack1DamageNumberofDice(1)
            ..setAttack1DamageSidesperDie(1)
            ..setAttack1CooldownTime(attackCooldown(lvl))
            ..setAttack1Range(attackRange)
            ..setScalingValue(0.8)
            ..setGroundTexture("")
     


    It is even possible to share code between compile-time functions and normal in-game functions. For example the constant GUN_TURRET_SPELL_ID or the function attackCooldown can be used to configure the generated objects and they can be used in the code for the spell.

    Optimizer



    Wurst has an integrated optimizer, with several optimizations:
    • inline functions (can inline most functions, exception are multiple return statements in a function)
    • inline constants
    • simple local optmizations (e.g. optimize
      3*4
      to
      12
      or remove
      if false ...
      )
    • name-compression
    • tree-shaking (remove unused variables and functions)
    • automatic null-setting of handles


    Eclipse Plugin




    [​IMG]
    (Click to enlarge)

    Run your map from eclipse



    You can compile all scripts and run your map directly from eclipse. This can be much faster than saving the map in WorldEditor first, because only the script is updated and eclipse already has the script in memory.

    Live errors and warnings



    [​IMG]

    Errors and warnings are directly shown in your code without the need for pressing compile or saving the whole map.



    Context-sensitive auto-complete



    [​IMG]

    If you have an expression with a dot, then auto-complete will show you all members available for the given type. This is especially useful when used with extension methods, because it is very easy to find the function you are looking for.

    Hotdoc



    As already seen in the auto-complete screenshot, Wurst has support for documenting functions with so called Hotdoc comments. These comments are shown in auto-complete and when you hover your mouse above a function call.

    Jump to declaration



    Hold down the Ctrl key and click on a variable or function and you will directly jump to the place where it is declared.

    Console and REPL



    [​IMG]

    You can use the console to evaluate expressions and test your code in eclipse, without even starting WarCraft. Of course this is limited, as not all natives are implemented in the Interpreter, but it is nice for testing data-structures or mathematical calculations.


    Other benefits of using eclipse



    Many features are already available in Eclipse and not specific to the Wurst-Plugin:
    • Press Ctrl+Shift+R to quickly jump to a file. It even supports using wildcards for searching files.
    • Powerful search (and replace) in all files.
    • Integration with version control (Git & co).
    • ...

    Manual



    You can read about all features in the Wurst Manual.

    Installation / Download



    Please find the installation instructions on GitHub.

    Other links:

    Youtube Tutorials:



    Download, Installation & Setup Eclipse & WorldEditor workflow
    http://youtu.be/JYhUkRsQe-o http://youtu.be/dRhw17Hxhv0


    Projects using Wurst





    FAQ (Frequently asked questions):




    Can I use vJass together with Wurst?


    Yes, you can use both. However it is not possible to call Wurst-functions from vJass and calling vJass from Wurst is not very convenient.


    I have further problems, suggestions or questions. Where can I get help?



     
    Last edited: Jan 1, 2014
  2. Nestharus

    Nestharus

    Joined:
    Jul 10, 2007
    Messages:
    6,146
    Resources:
    8
    Spells:
    3
    Tutorials:
    4
    JASS:
    1
    Resources:
    8
    It really is too bad that this doesn't play nice with vJASS.

    As a result, and due to lack of control over class behaviors (like allocation etc), and a few other things, this'll likely never be adopted by more than a small portion of the community :\

    Furthermore, does this work directly with the mpq archives? If so, does it maintain the JASS code already in the archive? Does it allow one to have the map open and compile it in eclipse?
     
  3. Frotty

    Frotty

    Wurst Reviewer

    Joined:
    Jan 1, 2009
    Messages:
    1,437
    Resources:
    11
    Models:
    3
    Tools:
    1
    Maps:
    5
    Tutorials:
    1
    Wurst:
    1
    Resources:
    11
    The videos/manual showcase most of what you ask.
    Of course it's an alternative to vJass - control over class behavior doesn't make much sense if it's handled correctly by the compiler/language (Wurst is pretty restrictive).

    It handles mpqs directly, you can however have normal Jass code outside of Wurst Packages.

    Eclipse is not linked to the editor at all(also all scriptfiles are external). You can compile your project (with "compile" in console and through reconciling) in eclipse without even having wc3 installed (so it works on any OS, too).
    Just the map "build process" has to be done by the WurstWe.
     
    Last edited: Jul 26, 2013
  4. PurgeandFire

    PurgeandFire

    Code Moderator

    Joined:
    Nov 11, 2006
    Messages:
    7,426
    Resources:
    18
    Icons:
    1
    Spells:
    4
    Tutorials:
    9
    JASS:
    4
    Resources:
    18
    This is really cool. Plus the syntax definitely fits wc3--it is exactly how I would envision a solid alternative to JASS (apart from vJASS).

    Any plan on implementing a feature similar to hooks? I know it is not incredibly useful for personal mapping, but it would open a lot of doors system-wise (ex: hooking RemoveUnit() or UnitDamageTarget()... just examples). It would be a pretty nice leg-up over vJASS since its hooks aren't implemented well.

    By hooking, I mean rewriting the function completely. All instances of the function would call the hook-replacement instead. This would allow for full control over what happens.

    Anyway, congrats on releasing it. I saw the documentation a while back and I liked how thorough it was in its explanations. Great job.

    EDIT: lol'd at the license text. How lovely.
     
  5. Nestharus

    Nestharus

    Joined:
    Jul 10, 2007
    Messages:
    6,146
    Resources:
    8
    Spells:
    3
    Tutorials:
    4
    JASS:
    1
    Resources:
    8
    Are you keeping GUI code at least?
     
  6. Crigges

    Crigges

    Joined:
    Nov 20, 2011
    Messages:
    201
    Resources:
    1
    Tutorials:
    1
    Resources:
    1
    Pls read what Frotty wrote:

    And as u should know GUI get's compiled to Jass. So yes ofc u can use GUI.
     
  7. Nestharus

    Nestharus

    Joined:
    Jul 10, 2007
    Messages:
    6,146
    Resources:
    8
    Spells:
    3
    Tutorials:
    4
    JASS:
    1
    Resources:
    8
    Crigges, I don't know if Frotty meant custom JASS script is not maintained (Frotty needs to maintain some of the script, like the map settings, or the map would go boom) or if all JASS Script wasn't maintained (meaning that Frotty is either maintaining the bare minimum, those being the map settings, or reading the map, or expecting a user to input the map setting script, which would be nasty).

    It is very easy to maintain all script generated by warcraft 3, and there is really no excuse not to do this, unless Frotty is planning a new GUI editor and is going to read the map's settings out of the mpq archive ;).
     
  8. Frotty

    Frotty

    Wurst Reviewer

    Joined:
    Jan 1, 2009
    Messages:
    1,437
    Resources:
    11
    Models:
    3
    Tools:
    1
    Maps:
    5
    Tutorials:
    1
    Wurst:
    1
    Resources:
    11
    Maybe you got this wrong.
    Jass code inside the war3map.j is not maintained. Stuff in the other files of course is.

    Honestly we don't see any purpose in hooks, since almost all natives are rewritten by extension functions anyways.
    (RemoveUnit(u) gets u.remove())
    Therefore you could just modify that or write your own extension function to use instead of the native.
     
  9. muzzel

    muzzel

    Joined:
    Jun 27, 2008
    Messages:
    1,303
    Resources:
    2
    JASS:
    1
    Wurst:
    1
    Resources:
    2
    Finally the release!

    The penguins will celebrate this days anniversary forevermore \o/
     
  10. Almia

    Almia

    Joined:
    Apr 24, 2012
    Messages:
    4,842
    Resources:
    35
    Spells:
    30
    Tutorials:
    4
    JASS:
    1
    Resources:
    35
    I think hooks just insert a function call of a function name inside the hooked function. That's why it still works if you call a function that you want to be hooked inside the hooking function.
     
  11. muzzel

    muzzel

    Joined:
    Jun 27, 2008
    Messages:
    1,303
    Resources:
    2
    JASS:
    1
    Wurst:
    1
    Resources:
    2
    Thats how hooker functions work, yes. However i think hooks (especially those without a defned scope) are very bad style since they make your code intransparent.
    If you need hooks to write well structured code then ur doing something wrong anyway.
     
  12. peq

    peq

    Joined:
    May 13, 2007
    Messages:
    171
    Resources:
    1
    Maps:
    1
    Resources:
    1
    I think you and Nestharus have a different understanding of "maintained".

    Jass code is not maintained in the sense that it will just be copied to the output script. Instead it will be parsed, optimized and then printed to the output. So in practice you can use a subset of what is possible in Jass and it will still be there (in some similar form) after Wurst has processed your map.
     
  13. Nestharus

    Nestharus

    Joined:
    Jul 10, 2007
    Messages:
    6,146
    Resources:
    8
    Spells:
    3
    Tutorials:
    4
    JASS:
    1
    Resources:
    8
    Ok, so you are parsing war3map.wct and the map setting stuff then?


    I just want to know if GUI in a map + that map's settings (the generated main etc) is compatible with Wurst or not >.<.
     
  14. Frotty

    Frotty

    Wurst Reviewer

    Joined:
    Jan 1, 2009
    Messages:
    1,437
    Resources:
    11
    Models:
    3
    Tools:
    1
    Maps:
    5
    Tutorials:
    1
    Wurst:
    1
    Resources:
    11
    Read what peq wrote.
    Wurst is compatible with GUI and Jass - the code inside the map "will be parsed, optimized and then printed to the output.".
     
  15. bhusta

    bhusta

    Joined:
    Mar 6, 2008
    Messages:
    841
    Resources:
    4
    Icons:
    1
    Maps:
    2
    Tutorials:
    1
    Resources:
    4
    Congrats for the release. The revolution of warcraft scripting begins ;)
     
  16. Nestharus

    Nestharus

    Joined:
    Jul 10, 2007
    Messages:
    6,146
    Resources:
    8
    Spells:
    3
    Tutorials:
    4
    JASS:
    1
    Resources:
    8
    Ok, so you are parsing war3map.j then?

    Ok

    The next question is, given this scenario, what would happen

    1. Save the map with WE (done doing stuff)
    2. Write some Wurst
    3. Save the map with Wurst compiler
    4. Write some more Wurst
    5. Save the map with Wurst compiler

    Do you clean out your generated Wurst stuff from the map? Or will you end up having double the Wurst code in there? Or do you somehow recompile the map with the compiler in WE before going to Wurst? Or do you actually compile the map yourself and then go to Wurst? Or do you save the map under a different name (that way you can keep the map open with WE and won't run into issues of double Wurst).

    In any case, am I right to assume then that people will still be able to use vJASS and GUI, just that they won't be able to communicate with Wurst or use Wurst resources, like 2 different zones.

    Wurst Zone | vJASS/GUI zone (can't see each other)
     
  17. Menag

    Menag

    Joined:
    Aug 26, 2009
    Messages:
    188
    Resources:
    4
    Spells:
    1
    Wurst:
    3
    Resources:
    4
    Viva la revolution!
     
  18. PurgeandFire

    PurgeandFire

    Code Moderator

    Joined:
    Nov 11, 2006
    Messages:
    7,426
    Resources:
    18
    Icons:
    1
    Spells:
    4
    Tutorials:
    9
    JASS:
    4
    Resources:
    18
    After looking into the project a bit more I also realize that hooks would be completely useless/impractical (for other reasons).

    I didn't ever intend to use it to write "well-structured-code". Rather, hooks would be something useful in creating public systems (particularly ones aimed at being GUI-friendly). However, it isn't really practical for Wurst after I read in on it, so I agree with your guys' perspectives.
     
  19. edo494

    edo494

    Joined:
    Apr 16, 2012
    Messages:
    3,846
    Resources:
    5
    Spells:
    1
    JASS:
    4
    Resources:
    5
    hook always generates trigger evaluation because when you hook native you may have code that calls that native above your function, and you cant call functions defined below the caller so it must do it the way it is

    proof of my claiming:

    Code (vJASS):

        function myFunction takes unit getKiller returns nothing
        call TriggerSleepAction(0.00)
        call BJDebugMsg("myFunction hooked")
    endfunction

    hook KillUnit myFunction
     

    ->
    Code (vJASS):

    globals
    trigger array st___prototype2
    unit f__arg_unit1

    endglobals

    function sc___prototype2_execute takes integer i,unit a1 returns nothing
        set f__arg_unit1=a1

        call TriggerExecute(st___prototype2[i])
    endfunction
    function sc___prototype2_evaluate takes integer i,unit a1 returns nothing
        set f__arg_unit1=a1

        call TriggerEvaluate(st___prototype2[i])

    endfunction
    function h__KillUnit takes unit a0 returns nothing
        //hook: myFunction
        call sc___prototype2_evaluate(1,a0)
    call KillUnit(a0)
    endfunction

    function myFunction takes unit getKiller returns nothing
        call TriggerSleepAction(0.00)
        call BJDebugMsg("myFunction hooked")
    endfunction

    //some shit in main function

    //Struct method generated initializers/callers:
    function sa___prototype2_myFunction takes nothing returns boolean
        call myFunction(f__arg_unit1)
        return true
    endfunction

    function jasshelper__initstructs41037420 takes nothing returns nothing
        set st___prototype2[1]=CreateTrigger()
        call TriggerAddAction(st___prototype2[1],function sa___prototype2_myFunction)
        call TriggerAddCondition(st___prototype2[1],Condition(function sa___prototype2_myFunction))

    endfunction
     
     
  20. muzzel

    muzzel

    Joined:
    Jun 27, 2008
    Messages:
    1,303
    Resources:
    2
    JASS:
    1
    Wurst:
    1
    Resources:
    2
    You better do. We dont wanna wake the penguins concentrated anger, do we?