• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

LuckyParser: an abandoned JASS parser concept

Should JassHelper be updated?


  • Total voters
    56
Status
Not open for further replies.

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,464
Edit August 2023 - Please see GitHub - wurstscript/WurstScript: Programming language that compiles to Jass and Lua (the language to create Warcraft III Maps). for the actual parser that should be used if you prefer this type of syntax.

old stuff, will not be done:

I'm going to be writing an entirely new compiler. It will be like Jass Shop Pro where it doesn't interface directly with World Editor or Jass NewGen Pack, so it will work on Mac OS X systems as well as PC's. It will have its own GUI with syntax highlighting, very beginner-friendly syntax checking that displays proper error messages, and of course it compiles as well. In fact, you won't even have to have WarCraft III installed on the computer in order to open, edit and save a project.

It will work with a map that was already saved with World Editor or Jass NewGen Pack so backwards compatibility will already be there by default.

Unlike Jass Shop Pro, the war3map.j contents will be invisible while editing, so you have an interface more like the trigger editor where each library can have its own frame, making it so you don't have to throw all of the script together yourself.

To finish by end-of-June:
  • Getting the right API for Luck
  • Writing the parser for Luck (keywords, operators, optimization, procedures, writing it to war3map.j, etc.)
  • Enabling the parser to write to MPQ
  • Compiling the parser
To finish afterwards:
  • Syntax Highlighting plugin (I will release a Notepad++ UDL so you WILL have syntax highlighting, just not built-in with the program itself just yet)
  • Compiler to turn vJass scripts into Luck scripts
  • Adding more functionality to procedures


Code:
library Fraction:
"""
    Fraction, based on the fraction module from Python, allows you to do math
    without floating points & automatically simplifies ((3, 12) becomes (1, 4)).
"""
   
    real struct: # adds its members to the real struct to allow syntax like bj_DEGTORAD.round()
        public integer round():
            return R2I(this + real.tertiaryOp(this > 0, 0.50, -0.50))
       
        public boolean rational(integer p=3):
            p = R2I(10 ** p)
            return this * p == R2I(this) * p
       
   
    integer struct:
        public integer length(): return I2S(this).length()
   
        # Greatest-common-denominator for a fraction to be simplified into.
        public integer getGCD(integer(num, den)):
            while den > 0:
                integer pnum = num
                num = den
                den = pnum % den
            return num
   
   
    struct fraction:
       
        readonly integer num, den
       
        # f.set(1, 2) sets the numerator & denominator to whatever you want.
        public:
            fraction set(integer(a, b)):
                local integer d = integer.getGCD(a, b)
                if d != 0:
                    this.num = a / d
                    this.den = b / d
                else:
                    this.num = 0
                    this.den = 1
                return this
       
            static fraction create(integer(num, den)): return fraction.allocate().set(num, den)
           
            # Ease-of-use API:
           
            static fraction fromInt(integer i):
                local fraction this = fraction.allocate()
                this.num = i; this.den = 1
                return this
           
            static fraction fromFloat(real f, integer p):
                p = R2I(10 ** p)
                return fraction.create(R2I(f * p), p)
           
            real product(): return num / I2R(den)
       
            fraction copy(): return fraction.create(num, den)
           
            nothing display(real duration):
                print(duration, "Fraction(" + num + ", " + den + ")")
           
            # Math API
           
            fraction add(fraction f): return this.set(this.num * f.den + this.den * f.num, this.den * f.den)
       
            fraction sub(fraction f): return this.set(this.num * f.den - this.den * f.num, this.den * f.den)
       
            fraction mul(fraction f): return this.set(this.num * f.num, this.den * f.den)
       
            fraction div(fraction f): return this.set(this.num * f.den, this.den * f.num)
       
            # Comparison API
           
            boolean eq(fraction f): return this.num == f.num and this.den == f.den
           
            boolean gt(fraction f): return this.num * f.den > f.num * this.den
       
            boolean lt(fraction f): return this.num * f.den < f.num * this.den
       
   
    # Returns a this-destroying fraction instance.
    public fraction Fraction(integer num, integer den):
        local static:
            timer clock = CreateTimer()
            fraction list[]
            integer size
       
        local fraction this = fraction.create(num, den)
        list[size] = this
        size++
        clock.start(0, false, lambda nothing:
            integer i = size - 1
            size = 0
            while i >= 0:
                list[i].destroy()
                i--
        )
        return this
As you can see based on this script, I am using Python-style comments and block comments for personality's sake. JASS comments and vJass block comments will not parse.

More like JASS, the "local" keyword is required to declare local variables. However, you can also declare local functions and local static variables, making it very easy to name your variables (without risking conflict with other systems).

JASS:
globals
    private integer i = 0
endglobals
 
function foo takes nothing returns nothing
    call BJDebugMsg(I2S(i))
endfunction
 
globals
    private integer i = 1 //Conflict!
endglobals

function bar takes nothing returns nothing
    call BJDebugMsg(I2S(i))
endfunction
The normal solution is to include things in different "scopes", but it is more logical to associate it directly with the only function that uses it.

Code:
nothing spam():
    local static integer i = 0
    print(i)
 
nothing eggs():
    local static integer i = 1 # No conflict
    print(i)



  • Primary language will be Luck. vJass backwards-compatibility will be added after the initial release. Zinc will not be supported. For now I have no plans for a c-like build.
  • hooks restructured to allow hooking either before or after. I will include the option to fully overwrite the function as well, but the function can only be overwritten once (syntax error for duplicate overwrite attempts).
    Code:
    # Overwrite hook
    hook:
        nothing PauseUnit(unit u, boolean flag):
            if u.shouldBePaused: u.pause(flag)
            debug else:          print("Tried to pause a unit that should not be paused!")
       
    # Hook after
    hook.after:
        nothing CreateItem(item i):
            data++
            i.userData = data
    
    # Hook before is the current incarnation of vJass hooks
    hook.before:
        boolean UnitDamageTarget(unit u, unit t, real f, boolean ranged, boolean attack, attacktype a, damagetype d, weapontype w):
            u.scriptedAttack = true
  • Concatenating an integer or real directly will automatically add I2S or R2S wrappers to soften the workload for you.
    Code:
    print("JASS max array size is: " + JASS_MAX_ARRAY_SIZE)
    
    # is the same as:
    print("JASS max array size is: " + I2S(JASS_MAX_ARRAY_SIZE))
    
    # You can also do:
    print(JASS_MAX_ARRAY_SIZE.varName) # This produces a string of the variable name itself.
  • You can design a function to have optional parameters.
    JASS:
    public unit NewUnit(player p=Player(0), integer id='hfoo', real(x=0, y=0, face=0)):
        return CreateUnit(p, id, x, y, face)
    The above can be written dynamically, with intuitive variations.
    JASS:
    unit u = NewUnit()
    unit u = NewUnit('ewsp')
    unit u = NewUnit(face=180) # Use this flavor to skip to a specific param in case there are multiple entries of the same type.
  • Anonymous functions are pretty easy to make:
    Code:
    onInit:
        local trigger t = trigger.create()
        t.addCondition(Filter(lambda boolean: return true))
        t.addAction(lambda nothing:
            print("I am awesome")
        )
        if t.evaluate(): t.execute()
  • Textmacros totally redefined as procedures to give maximum functionality. You can basically define your own compile-time rules now.
    Code:
    # Old:
    //! textmacro macro
            call DoNothing()
    //! endtextmacro
    
    # Call via:
    //! runtextmacro macro()
    
    # New:
    define process(): write("DoNothing()")
    
    # Call via:
    #! process()
    You do not need "#!" when called from a procedure.
  • Modules are deleted in favor of merging them into procedures.
    Code:
    define module():
        write(true, "readonly static real x, y") # Only this procedure can set these
       
        write("onInit: x = 10; y = 10") # Works.
    The "write" procedure's optional boolean parameter lets the parser know that it should follow the same general rules as vJass modules. It defaults "false" if omitted.
  • Procedures can have variables of their own and use "define" objects as "globals".
    Code:
    define GLOBAL = 0
    
    define process(name, type):
        GLOBAL++
        local wrapper = ""
        if type.type == 'handle':
            wrapper = '.id'
        elif type.type != 'integer':
            throw "'type' must be an integer or a handle!"
        local i = 10
        while i > 0:
            write("""\
                integer GetData""" + GLOBAL + i + (" + type + """ myVar):
                    return data.get(myVar""" + wrapper + ")"
            )
            i--
  • Procedures can be nested and taking into account multi-layered writing:
    Code:
    define A(): return "DoNothing()"
    
    define B(): write(A())
    Works like this:
    "A" returns "DoNothing()", "B" writes what A returns, so "B" writes "DoNothing()"​
  • You also have the bookmark keyword to specify where to write to.
    Code:
    define duo():
        write(myBookmark, """\
            t.addAction(lambda nothing:
                DoNothing()
            )
        """)
    
    #! duo()
    
    onInit:
        local trigger t = trigger.create()
        #! bookmark myBookmark
        # 't' automatically sets to null at the end because t.type is a handle.
  • Strings can be indicated either by '' or "". Single and quadruple-length ''-type strings will be treated as integer rawcodes if passed as an integer value, otherwise they will be treated as a string. The advantage is ''-type strings are taken literally so they avoid the need to escape quotes or escape backslashes.

    Current: string s = "Abilities\\Weapons\\FarseerMissile\\FarseerMissile.mdx"

    New: string s = 'Abilities\Weapons\FarseerMissile\FarseerMissile.mdx'
    This also makes it so a straight copy-paste of the model path is now possible without having to change everything to double-backslash, making your script a lot faster to tinker around with.
  • Multi-line strings are marked with triple-quotes, like in Python.
    Code:
    """
    this
    spans
    multiple
    lines
    """
    '''
    so
    does
    this
    '''
  • Writing "static if" is going to throw a syntax error. Normal if's should intelligently sort out which if's will be static and which will be dynamic.
  • All functions, variables and methods are treated as "internal" by default. The "public" keyword needs to be injected to indicate the object can be accessed outside of the library, though "private" and "protected" will be available and the "internal" keyword can be injected for clarity if you wish.
  • Script optimization is done automatically. Functions, variables, etc. that are not referenced are deleted during compilation. Shortening names is done as well.
  • Structs are a mix between array structs and normal structs but have more syntax potential. Allocate and deallocate can be overwritten and, as mentioned earlier, things that are not referenced are destroyed during optimization. Another thing, "onDestroy" will not use a trigger evaluation unless the struct is also extended. This should make it easier for users who don't want to bother with both overriding "destroy" and calling "deallocate" from it, while still preserving speed.
  • I will not include support for custom-defined arrays. Use of the Dictionary library is more clear and much more dynamic.
  • The new "throw" keyword allows you to define your own syntax errors.
    JASS:
    if myStruct.onDestroy.exists:
        this.onDestroy()
    else:
        throw 'Error: "onDestroy" not found!'
  • Readonly library variables
  • All initializers inside of a library will run before all initializers in a library that requires it. This eliminates the need to hack the initialization process by abusing module initializers, as well as restore struct & library initializers as useful creatures. The initialization process inside of each library will be "priority->struct->library". "onInit.priority" is just something you can hardcode to make it initialize before other things.


Please post requests, comments and/or constructive criticism.

Alternate discussion: http://www.thehelper.net/forums/showthread.php/163961-JassHelper-Update
 
Last edited:
Level 11
Joined
Sep 30, 2009
Messages
697
Would be awesome if you could do this. Have you tried to contact Vex atleast? (not that I would care that much about that :p)

I really like the throw thingie. Already thought about doing soemthing like this with static ifs and textmacros or so, but having a simple keyword would be awesome :D

The hooks would also be a great new thing making much systems way easier.

What I would like to see would be some sort of injecting modules. Right now you have to use implement would be cool if you could do something like:

module <name> inject <struct> <position>
module <name> inject <method> <position>

Also a is Module.implemented for static ifs would be nice.

Maybe I have more ideas ;)
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,464
Apologies for the design on hooks as that was a miscommunication. I meant "possible syntax". I see your point and I totally missed that with hooks (it never occurred to me for some reason that more than one library would hook the same native, which is pretty bad). Yes, the design I was thinking of involved no trigger evaluations, just a simple wrapper for the function.

The hook.before and hook.after design doesn't seem bad at all now that I see trigger evaluations are all but unavoidable.

Thank you for sharing that logic with me. Judging by my mishap with this one, I'm glad this is a public discussion so as to make sure this project is executed correctly.

If I were to re-write the source code of JassHelper, yes it would parse faster but I would not be able to deliver a bug-free draft for quite a while. I'd much rather work in a low-level language than work in Pascal, but I can get a lot of these bugs fixed just by editing Vexorian's work directly. The re-write process would take much longer than patching some holes and filling in some blanks.
 
Level 31
Joined
Jul 10, 2007
Messages
6,306
Actually, if you organize the functions and so on, you could avoid some of the trigger evaluations, but then we run into possible op limit hits =p.

But let's say that a hook just does something like SetItemUserData. It wouldn't need a trigger evaluation then would it?

Let's say a hook, with functions organized, doesn't end up needing a trigger evaluation.

Etc....

Also, the hooking on the same native wasn't the only problem with your design. With your CreateItem on the inside, CreateItem would have been hooked-

call HookCreateItem -> call HookCreateItem

etc, etc, thus infinite items would be generated. If you were to remove hooks on the inside of hooked natives, then other hooked natives wouldn't function properly (like a hook calling another native that should also call other hooks).

And then when you think of other hooks calling other hooks, we get back to the trigger evaluation deal.

So here is the thing... a trigger evaluation should only be made for a hook if it is absolutely necessary. For example, a hook with only SetItemUserData doesn't need a trigger evaluation.

Hooks should have a before/after, the before taking just the arguments and the after taking the return type.

My example here
JASS:
hook.before CreateItem takes integer id, real x, real y, item i returns nothing
    call SetItemUserData(i, 100)
endhook
hook.before CreateItem takes integer id, real x, real y, item i returns nothing
    call SetItemUserData(i, 100)
endhook

Was wrong, those should have been hook.after (after the native call), because before the native is called, the item doesn't exist ;p.

Default hooks (no . etc in them) are hook.before automatically (since that's how vjass currently handles all hooks).
 

Dr Super Good

Spell Reviewer
Level 63
Joined
Jan 18, 2005
Messages
27,197
While you are doing it, you should probably write auto optimization into it. Afterall the map script is not meant to be read anyway.

You could also add smart locals and smart function calls.
By this, I mean these 2 features.
1. The ability to declare locals anywhere within a function (the precompiler works out how to declare them at the function start).
2. The ability to call functions physically below a function (the precompiler reorganizes the functions to be in compilable order).
 

Dr Super Good

Spell Reviewer
Level 63
Joined
Jan 18, 2005
Messages
27,197
C would be the best as it is a universal language, simalr to the language used in SC2 and is taught by a lot of course.

A lot of what JASS does can be mapped directly into C.
example
function test takes integer i returns integer
return 0
endfunction

translates to
integer test(integer i){
return 0;
}

or even

integer test(integer i){return 0;}

which is potentially a lot neater

on top of that you can introduce C++ elements that we know from vjass like packages and privicy.

I would advise keeping the full name of types although some could also support short universal form like.
integer is also an int (and potentially some other type but I forget)
real is also a float

This is because those types basically are those C types.

Additionally, types like long and double could be implimented via astandard library but their use should not be nescescary.

A standard library for binary opperators should also be included so <<, >>, ~, &, ^ and | are all valid (but again their use should be very limited).

Structs can be prety much what structs in vjass are. Avoid any form of true struct mechanics as those are increadbly unsafe.

Another useful feature I thought of was the auto null of local handles. The compiler checks for if a handle of a leakable type has a chance to make it to the end of the function and if so it then nulls it automatically.
 
Last edited:
Level 26
Joined
Aug 18, 2009
Messages
4,097
Actually, if you organize the functions and so on, you could avoid some of the trigger evaluations, but then we run into possible op limit hits =p.

The hook should know if it was necessary to evaluate, so make an optional flag to force evaluation.

etc, etc, thus infinite items would be generated. If you were to remove hooks on the inside of hooked natives, then other hooked natives wouldn't function properly (like a hook calling another native that should also call other hooks).

Then only forbid hooks of those names you are already in. If there were two hooks on the same name, it would be already in arbitrary order.

Things I have wanted while triggering:

-pass data from vJass to external script and vice versa in one saving and where you want (or change the whole compiler a mightier language?)
-code-internal variables that you can have a custom key-function for example
-not only hook but a general way export code/general //! inject similar to what Axarion proposed
-some compiler-time functions like Power to calculate things in constant variables and have it inlined
-nestable textmacros/modules with parameters
-that textmacro calls can be unfolded to see the output and you can change/insert lines of it in another color to have more flexible macros
-have folders in structs that have their own identifiers and do not conflict with upper names
-declare static variables inside methods
-working folding of blocks or maybe even custom folding by setting starting and ending point
-...
 
Last edited:

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,464
I plan to support vJass syntax, but there is a lot of robustness involved with efficient coding. Subsequently, I think the vJass build should not have all the features of the c-based build in all cases. Lambda functions, for example, largely defy JASS syntax.

I don't feel all of Zinc's syntax should be preserved. Typing "function foo() -> integer" doesn't make as much sense as typing "integer foo()".

What I do with Zinc will be based on the c-build and much will be different. Current structs will be Classes, array structs will be Structs.

Here's a short syntax preview:

JASS:
struct List extends Table { //Would-be array structs that extend each other
    static int test (int node=0) //Optional parameter, can just call test() and node defaults 0
    {
        DoNothing();
        int i = 0; //Free-form declaration like cJass
        return i;
    }
}

struct asdf extends unit { //Extending a native type
    void test()
    {
        call KillUnit(this); //A unit-based method ;)
    }
}

struct Alabaster extends asdf, List { //Multiple inheritance
}

//class notReal extends asdf //Syntax error, classes cannot extend structs
//struct notReal2 extends notReal //Syntax error, structs cannot extend classes
//class jackyl extends unit //Syntax error, classes cannot extend native types

class Superdude {
    static thistype create()
    {
        return .allocate(); //Classes are those vJass structs, with the hidden methods
    }
}

class Childnoob extends Superdude { //Classes work pretty much the same as vJass structs
    static thistype create()
    {
        return .allocate();
    }
}
 
Last edited:

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,464
No, structs will gain more features over classes like extending handle types.

Classes will be almost just like they work in vJass but without the useless kthis variable ;)

How is a class going to declare onDestroy for something like... a texttag? That's why handles should only be extended by "array structs".

I updated the post from when you last read it.

Adiktuz, this would preserve vJass, but would not preserve Zinc.
 

Dr Super Good

Spell Reviewer
Level 63
Joined
Jan 18, 2005
Messages
27,197
Another idea could be to have vJASS come with a large numbers of library systems that can be automatically referenced like natives/bjs. This would be mostly useful for things like timer recycling and very basic systems. Logicall it only imports them into the map if they are actually referenced so no bloat code.
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,464
I've thought of doing that as well and I think it's a great idea. Obviously not compiling them with the map would be the best bet.

The optimizer I will include will obliterate all functions that aren't called. So if you have a multi-purpose library, and half the functions are never used, those functions just get deleted.
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,464
A short example of syntax I'm playing with (it's a mix of everything I like in a language construct)
JASS:
library Something
    //Free-form global declaration
    
    hashtable h //Private by default, like Zinc
    public int yes //Non-prefixed public variable
    public int _yes //Prefixed public variable
    
    init //The "init" keyword indicates the block will be compiled during initialization
        loop
            exitwhen int i == 0 //Can free-form declare locals like in cJass
            print(i) //Auto-wrap i with I2S during compilation (same goes for reals)
            print("i is equal to " + i) //Works with concatenation
            i ++ //++ and -- operators are supported to an extent
        print("Finished!") //Notice no "endloop" is required, like Python
    
    boolean foo (float f) //A function header which takes real returns boolean
        return false
    
    init
        print("I am called during init too!")
        
        TriggerAddCondition(trigger t = CreateTrigger(), Condition(lambda
            DoNothing()
            if (true & \
                !false) //The \ operator joins lines.
        ))
        
        TriggerAddAction(t, DoNothing) //Notice "function" does not need to be typed.
    
    struct Alpha //This is an array struct in vJass
        static int thisIsSimple = 123 //Pretty much the same as in vJass
        
        static int thisIsToo()
            if (cool)
                string s = "this is cool"
            elseif (!sexy)
                s = "this is not sexy"
            else
                s = "This is pretty bad"
            print(s)
    
    struct Beta extends unit //Implies "unit" instead of "integer" within methods
        unit getSelf()
            return this
        
        int asInt()
            return GetUnitUserData(this)
        
        static void test()
            unit u = CreateUnit(0, 'hfoo', 0, 0, 0) //Hint: I typed 0 instead of Player(0)
            //u will automatically set to null during compilation
    
    class Dude //A normal vJass struct, can't extend handles
        unit foo = 1 //Initial value of 1
 
Level 23
Joined
Jan 1, 2009
Messages
1,608
I'm very happy about this! I Hope you get at least a small working update going.

@Syntax Tbh I kinda like the Jass-written way without {}(which u arent using).
Tho some keywords like "then" are kinda unnecessary.
Above that all I would like some kind of programm or template file to set an own syntax, so you could define your own, fastest way of writing it, if you dont want to publish the code as a System e.g. (But its not that necessary)

Some features I would really like to see:
  • readonly/protected methods
  • optional Parameters
  • Nested Textmacros
  • Better Errormsgs
  • .exists() method for structs(without interfaces)
  • Make it open sorce from the very first
  • Fix Bugs and keep it updated ;)

e:In the loop example you use insertions instead of endblocks? Thats neat(so phyton)
Are the brackets in ifs needed? I dont like them, pls make them optional.
@Poll, I dont see any sense in not updating and waiting for vex is also a bad choice. Definitively yes!
The only better thing than updating it would be the creation of a new preprocessor.( I would like that even moar, and I think its even easier, tho more work)
Also you should include an auto-updater like in cJass(or at least a checker + dllink).

e2:
I dont really care about the name, but bribeJass(bJass) or just Boa or Viper or WipeJass (since its like Phyton) should be fine.
 
Last edited:

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,464
The primary language is going to be Luck and the parser I'll probably rename to LuckyParser as I'll be re-writing the entire parser from scratch. I don't want to make the first language vJass as Luck is much easier to program in.

An if/else block is no longer going to require "\" to join lines, and I will try to see about doing it without parenthesis "()" as well.

I thought about coding this langauge in a C-like syntax first, with curly brackets "{}" - but honestly, if you don't have to type curly brackets, why should I make them as a requirement?

Semicolons ";" could make multilines easier to parse but I also plan to have a more accurate syntax checker (one that throws easy-to-interpret errors) which will catch mistakes naturally, so I don't think semicolons as a necessity. I feel the language structure in Luck has already trimmed as much verbosity as possible, and I hope it will prove to be extremely easy to write and read.
 
well, I kinda liked that there's no need for the {} and the ; (coz I forget that ; on zinc a lot of times...)

The no endblock is fine and pretty easy to read/write though not sure about its readability when it comes to long codes... but anyway, you always have the start block...

and I also like the fact that you can directly use the type rather than putting

JASS:
function blahblah returns blah

or

function blah -> integer
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,464
Yes, it's much like Python in that way. But it's also got similarities with C as you write the return type instead of writing "function".

"real, integer, nothing" types are replaced with "float, int, void".

Operator overloading will have curly brackets "{}" as well as square brackets "[]".

I plan to have additional types of operator overloading as well, "+, -, *, /" as well as using "%" to modulate two values (will be ModuloInteger if only ints, otherwise it will be ModuloReal) and "^" to do something to the power of x. I will include struct operators to overload these as well.

Typecasting will not be required for braces like "<>", whereas in vJass it throws syntax errors when comparing a struct to an integer, even when the struct doesn't overload those operators. Typecasting will only be required if the struct DOES overload those operators.
 
Level 3
Joined
Jun 3, 2010
Messages
47
Moyack's Runes in Luck.

JASS:
# luck
library Runes
	globals
		constant integer SpellID = 'A000'
		constant integer RuneID  = 'o000'
		constant real    dt      = 0.2

	//==========================================================
	//  CONFIGURATION
	//==========================================================

	float Range(int level)                    // The range where the runes detect units.
		return 120. + 50. * (level - 1)

	float Radius(int level)                   // The radius where the runes will be placed.
		return 2 * Range(level)

	integer Amount(int level)                 // The amount of runes to be placed
		return 4 + 1 * (level - 1)

	float Damage(integer level)               // The damage dealt to units near the rune.
		return 350. + 50. * (level - 1)

	float Duration(integer level)             // The damage dealt to units near the runes.
		return 40. + 5. * (level - 1)		

	//==========================================================
	//  END OF CONFIGURATION
	//==========================================================

	globals
		group G = CreateGroup()

	string GetFX(integer id)
		return GetAbilityEffectById(SpellID, EFFECT_TYPE_SPECIAL, id)

	class rune
		public unit c
		public player p
		public effect f
		public float x
		public float y
		public float d = 0.
		public integer l
		public integer i

		static integer counter=0
		static thistype array runes
		static integer do=0
		static integer id=0
		public static unit dummy=null

		filter GetUnits() // This is a filter type, so just throw in return false for me at the end, please.
			unit u = GetFilterUnit()
			if (GetWidgetLife(u) > 0.405 and !IsUnitType(u, UNIT_TYPE_FLYING)) 
				SetUnitOwner(rune.dummy,rune.runes[rune.id].p,false)
				if (GetWidgetLife(rune.runes[rune.id].c) > 0.405)
					UnitDamageTarget(rune.runes[rune.id.c,u,Damage(rune.runes[rune.id].l),false,false,ATTACK_TYPE_SIEGE,DAMAGE_TYPE_NORMAL,WEAPON_TYPE_ROCK_HEAVY_BASH)

				else
					UnitDamageTarget(rune.dummy,u,Damage(rune.runes[rune.id].l),false,false,ATTACK_TYPE_SIEGE,DAMAGE_TYPE_NORMAL,WEAPON_TYPE_ROCK_HEAVY_BASH)
			rune.do++
			u=null

		void destroy()
			DestroyEffect(.f)
			if (.d < Duration(.L))
				DestroyEffect(AddSpecialEffect(GetFX(1),.x,.y))
				DestroyEffect(AddSpecialEffect(GetFX(2),.x,.y))
			rune.counter--
			rune.runes[rune.counter].i=.i
			rune.runes[.i]=rune.runes[rune.counter]

		public static void Start(unit c,real x,real y)
			rune R=thistype.allocate()
			if (IsPlayerAlly(GetLocalPlayer(),GetOwningPlayer(c))
				set R.f=AddSpecialEffect(GetFX(0),x,y)
			else
				set R.f=AddSpecialEffect("Abilities\\Spells\\NightElf\\TreeofLifeUpgrade\\TreeofLifeUpgradeTargetArt.mdl",x,y)
			R.c=c
			R.p=GetOwningPlayer(c)
			R.x=x
			R.y=y
			R.l=GetUnitAbilityLevel(c,SpellID)
			R.i=rune.counter
			rune.runes[rune.counter]=integer(R)
			rune.counter++

		public method Update()
			integer i=0
			loop
				exitwhen i >= rune.counter
				rune.id = i
				rune.do = 0
				rune.runes[i].d=rune.runes[i].d+dt
				GroupEnumUnitsInRange(G,rune.runes[i].x,rune.runes[i].y,Range(rune.runes[i].l),Condition(rune.GetUnits))
				if (rune.do>0 or rune.runes[i].d>=Duration(rune.runes[i].l))
					rune.runes[i].destroy()
				i++

	boolean Conditions()
		return GetUnitTypeId(GetSummonedUnit()) == RuneID

	void Actions()
		unit c=GetSummoningUnit()
		unit r=GetSummonedUnit()
		real lx=GetUnitX(r)
		real ly=GetUnitY(r)
		real fc=GetUnitFacing(c)*bj_DEGTORAD
		real a=Amount(GetUnitAbilityLevel(c,SpellID))
		real R=Radius(GetUnitAbilityLeveL(c,SpellID))
		real angle=2*bj_PI/a
		integer count=0
		real x
		real y
		RemoveUnit(r)
		Rune.start(c,lx,ly)
		loop exitwhen count == a // just push it down one line.
			x = lx + R * Cos(fc + count * angle)
			y = ly + R * SIN(fc + count * angle)
			rune.Start(c,x,y)
			count++
		c=null
		r=null

	void onInit
		trigger t=CreateTrigger()
		TriggerRegisterAnyUnitEventBJ(t,EVENT_PLAYER_UNIT_SUMMON)
		TriggerAddCondition(t,Condition(Conditions))
		TriggerAddAction(t,Actions)
		Preload(GetFX(0))
		Preload(GetFX(1))
		Preload(GetFX(2))
		rune.dummy=CreateUnit(Player(15),RuneID,0,0,0)
		ShowUnit(rune.dummy,false)
		TimerStart(CreateTimer(),dt,true,rune,Update)

# endluck
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,464
That "Runes" build would have a few syntax errors. This is Timer32 written in Luck:

JASS:
library T32
    
    globals
        public constant float _PERIOD = 0.03125
        public constant int   _FPS    = R2I(1 / PERIOD)
        public int            _Tick   = 0
        
        trigger Trig = CreateTrigger()
    
    init
        TimerStart(CreateTimer(), PERIOD, true, lambda
            Tick++
            TriggerEvaluate(Trig)
        )
    
    public module T32x
        private thistype next
        private thistype prev
        
        #if ! thistype.periodic.exists
            throw "T32 Error: The .periodic() method could not be found in the struct!"
        
        void startPeriodic()
            debug if this.prev != 0 | thistype:0.next == this
                print "T32 ERROR: Struct #$this had startPeriodic called while already running!"
            thistype:0.next.prev = this
            this.next = thistype:0.next
            thistype:0.next = this
            this.prev = 0
        
        void stopPeriodic()
            debug if this.prev == 0 & thistype:0.next != this
                print "T32 ERROR: Struct #$this had stopPeriodic called while not running!"
            this.prev.next = this.next
            this.next.prev = this.prev
            debug this.prev = 0
        
        init
            TriggerAddCondition(Trig, Condition(filter
                thistype this = thistype:0.next
                while this != 0
                    this.periodic()
                    this = this.next
            ))
 
Last edited:
Level 17
Joined
Apr 27, 2008
Messages
2,455
Good luck with that.
Personally i wouldn't care to support vJass, Zinc or cJass, because it's just to much work, and to be honest i don't believe in wc3 scripting future that much.
But ofc you will have more users if you support at least vJass.

Here are my 2 cents :

- No endword keyword, ok, but would you be able to update TESH or whatever else in order to detects blocks of code in the JNGP ?

- debug block would be cool

- I don't really like the implicit typecasting, it does to much code abstraction for me, for example the coder couldn't notice he use many times I2S(sameIntegerValue), instead of using a string variable.

Quite the same for "free-form declare locals like in cJass", for short codes it would be easy to notice which variables you are using but with long ones you could create useless variables.

- "All is object" like ruby would be cool

Code:
integer i
string s = i.toString()
real x = unit.getTrigger().getX() // or something neater
trigger trig = trigger.create() // or maybe even juste .create() but i'm not a fan of this and would make the parser slower.
trig.addCondition(...)

It would make function usage name convention much more reliable than the regular jass, and so even easier to learn/use for a beginner.

- the semi-colon operator ";" would be a very nice toy, for things likes initializing a static trigger (create & add event/condition)

In fact if it was me i wouldn't even support regular jass :p
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,464
I don't know what you mean by semicolon helping to initialize a static trigger. I think I should add semicolon as an OPTIONAL way to join statements on one line (I think Python does this too iirc).

I don't think typecasting every function in the API is worthwhile... yet ;)

I'm eliminating the standalone "i" thing, I'm replacing it with print "$i" (this will display the value of i instead of displaying "i")
 
Level 17
Joined
Apr 27, 2008
Messages
2,455
I don't know what you mean by semicolon helping to initialize a static trigger. I think I should add semicolon as an OPTIONAL way to join statements on one line (I think Python does this too iirc).

It was just a concrete example where semicolon is "useful", or at least a very nice optional way ;)

I don't think typecasting every function in the API is worthwhile... yet ;)

It's all up to you, in fact it is one of my goal for my personal jass parser (once i own quite well a real language xD).
I just love this philosophy.

I'm eliminating the standalone "i" thing, I'm replacing it with print "$i" (this will display the value of i instead of displaying "i")

That's better for me, but i would still not allow this (but again it's me)

Also what's about the other points ?
 
Level 17
Joined
Apr 27, 2008
Messages
2,455
TESH: Yes, an update goes without saying.
Fine, even if TESH is laggy with many lines of code.

Debug block, I don't see how that doesn't exist already?

I mean something like that :

Code:
debug { s = "this is just a debug" ; BJDebugMsg(s)
s = "i don't like using DisplayTextToPlayer with GetLocalPlayer for debug message because GetLocalPlayer is lame in replays" ; BJDebugMsg(s) }

I've just realized there is already static if and the boolean DEBUG_MODE, and it would fit better with your indentation-based language.
Or hmm, you could consider debug as a block code if you use an end line (enter) just after it, like that :

JASS:
debug
    // your debug stuff
    // go here

DoNothing() // end of debug
 
Status
Not open for further replies.
Top