After reading the
article I decided to talk about how Warcraft helped me. I’ve been mapping for Warcraft 3 for quite a long time. 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” did not give rest to the “bourgeois” mappers, and they released his hack version, which was called the
JNGP (Jass New Gen Pack) : the hack loaded different libraries and added different goodies - highlighting the code, turning off the limit of objects on the map , parsers (about them below).
This language has a rather verbose syntax, as well as an event-oriented structure, so two well-known (in the world of mapping) person have created language prepocessors, which are also written on the wiki. The first one -
vJass (v - from the creator's nickname -
Vexorian ) added all the resulting goodies (encapsulation, etc.) to JASS. After the Russian programmer
ADOLF released its parser, which created a new dialect -
cJass , the parser wrote on MASM. He made JASS'a syntax similar to classic C, and also added preprocessing (enumerations, macros, connecting external scripts,
for handler, increment operator, decrement, reduced calculations (+ =, - =, / =, * =) and much more). Example below:
Codefunction test takes nothing returns integer local integer i = 0 set i = i + 1 return i
')
int test() { int i = 0; return ++i;
Unfortunately, the project was abandoned, and there are very few knowledgeable assemblers in the circle of mappers. But not about that.
Once I had the idea to write my own parser. Since I don't really understand programming, my choice fell on
Delphi . After giving the parser a trivial name (
JASP - Just Another Script Preprocessor), I sat down to write buns. Thus, dynamically-typed variables (as in
C # ), a single declaration of global variables, the destruction of objects, etc., which was so lacking in
vJass & cJass, came to light . Having composed the first two versions of the parser, to which I added all these small but useful buns (they can be studied in the
manual ), I realized that I need to improve. My choice fell on C #, and since relatively recently I have been transferring (or rather already having transferred and finishing with a file) the latest version 0.3, periodically unsubscribing on subject forums and adding to 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 Sharpe, which cannot but please me. I think that's enough, thank you all for your attention.
Oh yeah, for the sake of interest, a spell on all three JASS'a dialects in total: scope FreezingShoot { #define { <trigger gg_trg_Freezing_Shoot = null>; 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()); } }