📜 ⬆️ ⬇️

How Warcraft 3 helped me learn a couple of yap

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).

Native worldeditor

JNGP

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:

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 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()); } } 

Source: https://habr.com/ru/post/148580/


All Articles