• 🏆 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!

WeWarlock - A Jass Preprocessor

Status
Not open for further replies.
Level 11
Joined
Oct 13, 2005
Messages
233
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:

JASS:
//! 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:

JASS:
//! 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:
JASS:
//! 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:
JASS:
//! 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:

JASS:
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:
JASS:
//! 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:

JASS:
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:

JASS:
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:

JASS:
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:
JASS:
//! 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:

JASS:
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:
JASS:
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:
JASS:
<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:
JASS:
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.
 

Attachments

  • WeWarlock-0.9.3.zip
    2.1 MB · Views: 268
Last edited:
Level 32
Joined
Oct 23, 2006
Messages
5,291
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?
 
Level 11
Joined
Oct 13, 2005
Messages
233
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:
Level 11
Joined
Oct 13, 2005
Messages
233
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:
Level 12
Joined
Mar 11, 2004
Messages
600
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.
 
Level 11
Joined
Oct 13, 2005
Messages
233
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.

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.
 
Status
Not open for further replies.
Top