How Warcraft 3 helped me learn a couple of YPs

After reading the article, I decided to talk about how Warcraft helped me. I’ve been doing cartography for Warcraft 3 for quite a while. For many, it’s probably a secret, but Blizzard, which released the game, gave users a fairly powerful map editor with an interpreted programming language, which they called JASS (more on the wiki ). . Blizzard’s "World Editor" haunted the "bourgeois" map makers, and they released its hack version, which was called JNGP (Jass New Gen Pack) : the hack loaded different libraries and added different goodies - code highlighting, disabling the limit of objects on the map parsers (about them below).

Native worldeditor

Jngp

This language has a fairly verbose syntax, as well as an event-oriented structure, so two well-known (in the world of mapping) people created language preprocessors, which are also written on the wiki. The first - vJass (v - from the creator’s nickname - Vexorian ) added to JASS the features and all the resulting goodies (encapsulation, etc.). After the Russian programmer ADOLF released its parser, which created a new dialect - cJass , the parser wrote on MASM. He made JASS syntax look like classic C, and also added preprocessing (enumerations, macros, connection of external scripts, for handler, the increment, decrement operator, abbreviated calculations (+ =, - =, / =, * =) and much more). Example below:

Code
function test takes nothing returns integer
    local integer i = 0
    set i = i + 1
    return i
    //Simple function on "pure JASS"
endfunction


int test()
{
    int i = 0;
    return ++i;
    //Same on cJass
}


Unfortunately, the project was abandoned, and there are very few knowledgeable assemblers in the circle of map makers. But not about that.
Once, it occurred to me to compose my own parser. Since I do not understand programming in a practical way, my choice fell on Delphi . Giving the parser a trivial name ( JASP - Just Another Script Preprocessor), I sat down to compose the buns. This is how dynamically typed variables (like in C # ), a single declaration of global variables, destruction of objects, etc., that was so lacking in vJass & cJass, were born . After composing the first two versions of the parser, in which I added all these small, but useful buns (they can be studied in the manual), I realized that we need to improve. My choice fell on C #, and since relatively recently I have been transferring (or rather already transferring and finishing with a file) the latest version 0.3, periodically unsubscribing on thematic forums and replenishing my notes . In the end, I want to say that the same JASS, which my father called pampering, taught me the basics of programming and allowed me to go deeper from Delphi to Sharp, which cannot but please me. I think that's enough, thank you all for your attention.

Oh yes, for the sake of interest, the spell in all three JASS dialects in total:
scope FreezingShoot
{
    #define
    {
        ;
        private isEnemy(t, u) = IsUnitEnemy(t, GetOwningPlayer(u)) && GetWidgetLife(u) > .405;
    }
    #include "cj_types_priv.j";
    private struct FS
    {
        unit caster;
        unit array dummy[3];
        static constant int count = 3;
        real dist = 0.;
        static void Timer()
        {
            var t = GetExpiredTimer();
            FS s = LoadInteger(hash, GetHandleId(t), 0);
            real x, y;
            if (s.dist <= 750.)
            {
                for (int i = 0; i < s.count; i++)
                {
                    var angle = GetUnitFacing(s.dummy[i]) * .0174532;
                    x = GetWidgetX(s.dummy[i]) + 25. * Cos(angle);
                    y = GetWidgetY(s.dummy[i]) + 25. * Sin(angle);
                    SetUnitPosition(s.dummy[i], x, y);
                    for (unit target; UnitsInRange(x, y, 80.) use temp)
                    {
                        if (isEnemy(s.caster, target))
                        {
                            UnitDamageTarget(s.caster, target, 100., true, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_NORMAL, WEAPON_TYPE_WHOKNOWS);
                            delete AddSpecialEffect("Abilities\\Weapons\\FrostWyrmMissile\\FrostWyrmMissile.mdl", x, y);
                            DummycastToTarget(s.caster, target, 'A001', 852075);
                            RemoveDummy(s.dummy[i]);
                        }
                    }
                }
                s.dist += 25.;
            } elseif (s.dist > 750. || s.count <= 0) {
                for (int i = 0; i < s.count; i++)
                {
                    if (s.dummy[i] != null)
                    {
                        x = GetWidgetX(s.dummy[i]);
                        y = GetWidgetY(s.dummy[i]);
                        delete AddSpecialEffect("Abilities\\Weapons\\FrostWyrmMissile\\FrostWyrmMissile.mdl", x, y);
                        RemoveDummy(s.dummy[i]);
                    }
                }
                FlushChildHashtable(hash, GetHandleId(t));
                PauseTimer(t);
                delete t, s;
            }
            flush t;
        }
        static void Init(unit caster, real tX, real tY)
        {
            new FS s, timer t;
            s.caster = GetTriggerUnit();
            var angle = Atan2(tY - GetWidgetY(s.caster), tX - GetWidgetX(s.caster)) * 57.295;
            var x = GetWidgetX(s.caster);
            var y = GetWidgetY(s.caster);
            for (int i = 0; i < s.count; i++)
            {
                s.dummy[i] = CreateDummy(GetOwningPlayer(caster), "Abilities\\Weapons\\ColdArrow\\ColdArrowMissile.mdl", .7, x, y, 100., angle);
                angle -= 20.;
            }
            SaveInteger(hash, GetHandleId(t), 0, s);
            TimerStart(t, .04, true, function thistype.Timer);
            flush t;
        }
    }
    callback onUnitSpellEffect('A000')
    {
        FS.Init(GetTriggerUnit(), GetSpellTargetX(), GetSpellTargetY());
    }
}

Also popular now: