Dismiss Notice
60,000 passwords have been reset on July 8, 2019. If you cannot login, read this.

WeWarlock - A Jass Preprocessor

Discussion in 'Warcraft Editing Tools' started by wyrmlord, Apr 3, 2007.

  1. wyrmlord

    wyrmlord

    Joined:
    Oct 13, 2005
    Messages:
    252
    Resources:
    5
    Tools:
    1
    Maps:
    1
    Tutorials:
    3
    Resources:
    5
    Current version = 0.9.3

    Tool by: Karukef
    Edited a little by: wyrmlord

    What is it?
    WeWarlock is first and foremost a JassPreprocessor. It allows us to extend the current syntax and possibilities on Jass, creating systems and syntax that would otherwise be impossible, such as //! include, static keyword, SmartAttach/Stack/Arrays and Callables.

    Second it is also a very practical tool. It allows things such as Rawcode Renaming (as found in the Widgetizer), automatically adding a directory of files, checking the syntax with PJASS and more.

    Right now it is in beta stage which means that the program has been tested for several weeks in a complex actual project. In other words, I can both claim it is somewhat stable while at the same time being sure that there are still bugs to be found.

    Running the Program
    This program can be run on either Jass scripts (.j files) or entire maps (.w3x files). WeWarlock is a command-line tool, which means it must be run from the command-line. The arguments when running the program are "-i inputfile.w3x [-d]". What this basically means is you have -i and then the filename of the file you're going to compile. If the filename has any spaces in it, it should be surrounded by "quotes". You can optionally include a -d at the end, which I would recommend, which will display message boxes for errors or will tell you when the program finishes.

    If you're unfamiliar with using the command-line, you can instead create a .bat file to run. To do this, create a new file in notepad and then save it as a .bat file (when saving, save it as "name.bat" including the quotes and name being whatever you want). Inside the .bat file, you'll need to include the text:

    "C:\Program Files\WeWarlock-0.9.3\WarlockCompiler.exe" -i map_name.w3x -d

    You should replace the "C:\Program Files\WeWarlock-0.9.3" with the path to WeWarlock. If you're confused, first open the folder. At the top of the folder you'll see Address, then a folder icon, and then a bunch of text. Replace the C:\Program Files\WeWarlock-0.9.3 with that (make sure to leave the \WarlockCompiler.exe at the end though). You should also replace map_name.w3x with the name of your map or Jass script.

    Parse Includes
    Very useful options that recursively parses all //! require commands. You may for example put the following in the custom script section of your map:
    //! require script MySpell.j It searches the /source folder and all the content of 'MySpell.j' will be inserted at that point. If MySpell.j has a globals/endglobals section, the globals will be merged, so each file can easily declare its own globals.

    A more advanced example would be, in your custom script to //! require script main.j and in "main.j" you can have the following:
    JASS:

    Code (vJASS):
    //! require script SystemUtility.j
    //! require script ProjectileSystem.j
    //! require script UltraLich_Spells.j
    //! require script MegaKobold_Spells.j


    Then 'ProjectileSystem.j' can use functions from SystemUtility.j and both the spell files could use anything above them. This is very useful for structuring large projects.

    To require files from WeWarlock's library folder, you use //! require library filename.j There are files, however, that you shouldn't include: Jlib, SmartAttachHeaderStatic, OrderEvents, SmartAttach

    Replace Parser
    Parses //! ReplaceLocal commands.
    In the following segment, MAX is replaced with 100.
    JASS:

    Code (vJASS):
    //! ReplaceLocal MAX 100
    function DoSomething takes integer i returns boolean
        if i < MAX then
            return true
        endif
        return false
    endfunction


    //! ReplaceLocal affects ALL instances of the given text in the file it is found. So a ReplaceLocal command in "SomeFile.j" will only affect code in that file. It is generally smart to use unique names for the replace, so that you avoid replacing text that shouldn't be replaced.

    JassPreprocessor

    Oboy. This one has a LOT of features. I will write down some of them.

    SmartAttach
    Note: You need to require the SmartAttach preprocessor to use this:
    Code (vJASS):
    //! require preprocessor SmartAttach


    Check Karukef's posts over at wc3c to see how it's used. (Link at bottom of post).

    Static
    Note: To include this feature in your map, you must require the Static preprocessor:
    Code (vJASS):
    //! require preprocessor Static


    The 'static' keywords allow you to easily define a local that is initialized to a value on map init. Perfect for some situations where you would be building and destroying the same value all the time. In the following example it is used to store a boolexpression.

    JASS:

    Code (vJASS):
    function ExcitingSpell takes unit source, unit victim, real damage returns nothing
        static boolexpr target_options = And(TargetEnemy, TargetIsNot)
       
        call CS_EnumUnitsInAOELoc(possible_targets, victim_pos, area, target_options)
        set target_options = null



    Notice that you dont destroy it at the end of the function, but you do have to null it.

    Event Commands
    Note: You must require the CommandParser preprocessor for this to work:
    Code (vJASS):
    //! require preprocessor CommandParser


    Registering functions to run when certain events happen is very useful. The Event Commands makes this easier and more effective than ever before.

    Commands:
    //! initfunc (no args) - Add a call to the function in the maps init function.
    This one is VERY useful and simple.
    JASS:

    Code (vJASS):
    function SomeFunction takes nothing returns nothing
        //! initfunc
        //This function now runs on map init
    endfunction



    //! BeginAbility rawcode - When a unit starts casting ability, but before the actual effect happens.
    //! BeginEffect rawcode - When the effect happens.
    //! StopAbility rawcode - If the unit stops casting, this will be triggered. Also triggers after FinishAbility.
    //! FinishAbility rawcode - Triggers when the unit has finished casting completely AND the casting animation is finished.

    The above commands are used as follows:
    JASS:

    Code (vJASS):
    function ABIL_Fireball takes nothing returns nothing
        //! BeginEffect A003
        //This function is now run when the ability 'A003' begins it's effect.

        //The A003 cannot have ' marks surrounding it

    endfunction


    //! ObjectOrderEvent order_integer_id
    //! PointOrderEvent order_integer_id
    //! InstantOrderEvent order_integer_id

    These trigger when ObjectOrder, PointOrder or InstantOrders are issued.
    JASS:

    Code (vJASS):
    function ABIL_DrainSpellChange takes nothing returns nothing
        //The following orders are when enabling or disabling 'bloodlust'
        //! InstantOrderEvent 852102
        //! InstantOrderEvent 852103
        //This function now runs when bloodlust (or an ability based on it) is right clicked.
    endfunction


    Callables
    Note: You need to require the Callable preprocessor to use these:
    Code (vJASS):
    //! require preprocessor Callable


    Yet another very powerful feature. Allows calling of functions by variable, "downward" calling, optional Fastcall/Threadedcall as well as passing arguments to and receiving returnvalues from the called functions.

    Syntax:
    JASS:

    Code (vJASS):
    local integer a_function = Func("SomeFunction")
    //Call the function below
    //It is required to specify what the function returns, in this case nothing
    call Call(nothing a_function)

    function SomeFunction takes nothing returns nothing
        //do something
    endfunction

    //Define a much more interesting callable
    callable AwesomeFunction takes unit u, real speed returns location
        return Location(GetUnitX(u) + speed, GetUnitY(u) + speed)
    endfunction

    function MoveUnit takes integer move_func, unit whichUnit, real speed returns nothing
        local location loc
        //Notice how it is vital to define the types the function return (argument 1)
        //as well as the type of each argument.
        set loc = Call(location move_func, unit whichUnit, real speed)
        call SetUnitPositionLoc(whichUnit, loc)
        call RemoveLocation(loc)
        set loc = null
    endfunction

    //To call the above function with AwesomeFunction:
    call MoveUnit(Func("AwesomeFunction"), someUnit, 100.0)


    Attach Classes
    This is one of the most powerful features of WeWarlock. This allows you to create classes (like in programming languages). These classes can contain variables and/or functions specific to each instance. Here's an example of one:
    Code (vJASS):
    attachclass MySpell
     unit caster
     unit enemy
     real damage

        function DamageTarget takes nothing returns nothing
            call UnitDamageTarget(self.caster, self.enemy, self.damage, <other arguements>)
        endfunction

        // This function is called when you create an attachclass
        function INIT takes unit caster, unit enemy, real damage returns nothing
            set self.caster = caster
            set self.enemy = enemy
            set self.damage = damage
        endfunction

        // This function is called when the attachclass is destroyed, it should take nothing and return nothing
        function DESTROY takes nothing returns nothing

            // Make sure to release the id used by the attachclass when the class isn't being used anymore

            call SA_IdRelease(self)
        endfunction
    endclass

    function Some_Function takes nothing returns nothing
    // MySpell is used like a regular variable type
    // The 'MySpell' function creates a new instance of MySpell.
    // It's like creating a new handle; it must be destroyed when it's done being used
     local MySpell spell = MySpell(SA_IdNew(), GetTriggerUnit(), GetSpellTargetUnit(), 5.0)

    // Perfectly legal, they both point to the same instance of MySpell
    local MySpell spell2 = spell

        // Call the DamageTarget function from the spell2 instance of the class
        call spell2.DamageTarget()

        // You can also set values inside the attachclass if needed
        set spell.caster = <unit variable>

        // 'Destroys' the class so that its id can be reused
        call Destroy(spell2)

    // There's no need to null attachclass variables, they're actually only integers
    endfunction

    Hopefully this section explains some of the general features to people who already know what classes in other languages are. For those of you who don't know and can't interpret the meaning through the commented code, here's some info:
    -An attachclass can hold any number of variables or functions (as well as callables) When you declare variables inside them, it's declared <type> <name> as you can see in the code

    -To access part of a class, you need to do 'instance.member'. Member could be either a variable or a function. Instance can either be a variable of the correct type, or if you want to refer to a member of the class inside the class, you can just use self.member instead.

    -Functions are still called the same way inside classess. However, you can't use functions inside classes as callback functions (like for timers and such), but there is a class inside the WeWarlock library that allows using callables inside classes as callbacks. If you don't have a clue what anything in this paragraph means, just ignore it.

    -When creating a new instance of an attachclass, you use the syntax:
    Code (vJASS):
    <attach_class_name>(<integer>, <additional arguements if any>)
    For the integer part, you need to use either SA_IdNew(), SA_UnitNew(unit), SA_ItemNew(item), SA_TimerNew(), or SA_TimerStartNew(rate, periodic, callback). Note: SA_UnitNew and SA_ItemNew use unit/item user data so that means you can't use them anywhere else.

    For advanced users, attachclasses also allow single or multiple inheritence which is used like so:
    Code (vJASS):
    attachclass MyClass extends OtherClass1, OtherClass2

    For those of you who don't know what inheritence is, it basically means the new class will contain all the functions and variables in the other classes. I won't go too in-depth about this, as it's more advanced. If you want to read further on this, check out the VoD2 link.

    In addition to attachclasses, there are also regular classes as well. The only difference between them is that classes don't require an id to be used. They are automatically supplied an id when they're created (you don't need to provide it), but that doesn't mean you shouldn't destroy them when finished.

    That should just about cover attach classes as far as I can tell.

    Additional PreProcessor functions not documented yet:
    GcData

    For more info on WeWarlock, here are some links:
    VoD2 Development Forum
    Note: attachstruct is now attachclass. Also, some information presented may be VoD2-specific (meaning it can't be used) This has the newest information and contains some examples of using WeWarlock commands.

    Original Thread
    This is the original thread over at wc3c that Karukef posted. The links at the top shouldn't be used as they're old (and the subversion source contains a bug I fixed) This thread also contains a link to his original SmartAttach thread.

    Now, it's tricky trying to use something new and different without any examples of usage. Therefore I'll be posting some spells using WeWarlock on the site (which I've a large amount of comments in). Karukef stopped working on WeWarlock a long time ago, so I decided to fix a bug and hopefully continue work in it. If anyone has some skill in using python, I could use your help as I have none (I can code in C++ though).

    Post any bugs (if any) that you find.

    Update1
    -Now supports:
    //! ObjectOrderEvent orderid
    //! PointOrderEvent orderid
    //! InstantOrderEvent orderid

    Update2
    Using an older CommandParser.pyc file that supports all commands like it originally should have

    Update3
    Compiled with pyinstaller now. py2exe wasn't compiling the source properly which caused certain features not to work

    Update4
    -Added SFmpq.dll to the folder so WeWarlock can open mpq files properly.
     

    Attached Files:

    Last edited: Sep 4, 2007
  2. wyrmlord

    wyrmlord

    Joined:
    Oct 13, 2005
    Messages:
    252
    Resources:
    5
    Tools:
    1
    Maps:
    1
    Tutorials:
    3
    Resources:
    5
    Update

    Sorry for the double post, but I've just updated the file.
    Updates
    -Now supports:
    //! ObjectOrderEvent orderid
    //! PointOrderEvent orderid
    //! InstantOrderEvent orderid
     
  3. wyrmlord

    wyrmlord

    Joined:
    Oct 13, 2005
    Messages:
    252
    Resources:
    5
    Tools:
    1
    Maps:
    1
    Tutorials:
    3
    Resources:
    5
    Update

    Another update. Instead of using my external program for the command parsing, I found an older version of WeWarlock's CommandParser (compiled) and am using that now instead. From testing, it appears to be working as it should.
     
  4. Wolverabid

    Wolverabid

    Joined:
    Oct 23, 2006
    Messages:
    8,302
    Resources:
    5
    Tutorials:
    5
    Resources:
    5
    WeWarlock

    wyrmlord...WOW, I had no idea that this tool even existed until today. Thanks for bumping the thread to bring it to everyone's attention.

    (IMO) You really should send a PM to Daelin, DSG, PP, Vex and as many other JASS cats as you can think of. They might be able to help you further analyze, test and upgrade this puppy! (I realize that it has already been run through the wringer over at 3c.)

    Will you (or Karukef himself) post it in the Hive's tool resource section?
     
  5. wyrmlord

    wyrmlord

    Joined:
    Oct 13, 2005
    Messages:
    252
    Resources:
    5
    Tools:
    1
    Maps:
    1
    Tutorials:
    3
    Resources:
    5
    Karukef gave up on Wc3 awhile back and we were unable to finish the AoS we were working on. I've been wanting to continue it for some time, but the WeWarlock version he had been working on wouldn't compile the map correctly.

    About the PM thing, I don't think that's necessarily needed. People will find it if they need it. Vex has known about WeWarlock for quite some time as JassHelper allows it to be called when needed. Most people already use vJass, and it's a bit hard to use both at once if you're using the attachclasses used in WeWarlock.

    Update: Added info on attachclasses.
     
    Last edited: Apr 20, 2007
  6. moyackx

    moyackx

    Joined:
    Feb 15, 2006
    Messages:
    801
    Resources:
    7
    Maps:
    4
    Spells:
    2
    Tutorials:
    1
    Resources:
    7
    Hmm, WeWarlock... A good tool indeed. I believed that this tool died when Vexorian released the JASS new generation pack.
     
  7. wyrmlord

    wyrmlord

    Joined:
    Oct 13, 2005
    Messages:
    252
    Resources:
    5
    Tools:
    1
    Maps:
    1
    Tutorials:
    3
    Resources:
    5
    And now I'm attempting to bring it back to life, somewhat. I bet if I found out how to have it called from Grimoire, it would be used more. That, or maybe I could try adding a user interface to it... only I'm not too experienced with the Win32 API and even less with python.

    WeWarlock does some of the same things as vJass does, but not all. (And viseversa as Vex points out)
     
    Last edited: Apr 21, 2007
  8. Vexorian

    Vexorian

    Joined:
    Mar 11, 2004
    Messages:
    649
    Resources:
    1
    Maps:
    1
    Resources:
    1
    WeWarlock doesn't support any of the features vJass does nor viceversa, so please don't ever say that again. So please don't ever say "This supports all the useful features that vJass supports" again.

    Next is just an opinion and shouldn't be taken seriously:

    Attachclasses are a great example of what is wrong with wewarlock. Why the feck use attachclasses when you already have 'classes'? Seriously, it is all about karukef's lame attach method and how hard he tries to push it.
     
  9. wyrmlord

    wyrmlord

    Joined:
    Oct 13, 2005
    Messages:
    252
    Resources:
    5
    Tools:
    1
    Maps:
    1
    Tutorials:
    3
    Resources:
    5
    That's Karukef's alternative to gamecache for units/timers/items. I can agree it's not very good, but if I recall correctly he messed with SmartAttach to stop it from working correctly at one point. At least, I heard him say it wouldn't work correctly on the VoD2 forums.
     
  10. wyrmlord

    wyrmlord

    Joined:
    Oct 13, 2005
    Messages:
    252
    Resources:
    5
    Tools:
    1
    Maps:
    1
    Tutorials:
    3
    Resources:
    5
    Update

    Apparently py2exe doesn't compile the WeWarlock source as it should and as a result, doesn't work properly. This new version was compiled with pyinstaller and has been working as it should.