Предназначение:
Warcraft III Reforged привнес в игру скрипты Lua, но многие разработчики карт для WC3 до сих пор используют JASS, а многие и cJass (просто потому, что правила синтаксиса в стиле C тупо рулят) К сожалению, расширение cJass не поддерживается для Reforged, и кто знает, как это будет, вероятнее всего вряд ли c-подобный синтаксис появится в Reforged. А JASS устаревает, крайне дырявый и имеет громоздкий и неудобный синтаксис.
Lua более эффективен, полезен и прост в разработке игр, он фактически стал стандартом в игровом скриптинге благодаря своему удобству, простоте и быстроте. Но многие проекты все еще находятся на cJass/JASS, и нет возможности конвертировать их в Lua. Редактор без расширения cJass не воспринимает этот код и в результате ваш проект может просто пропасть. А многие у кого проект написан на JASS предпочли бы переписать его на более удобный Lua, который легче и приятнее поддерживать. Переписывание кода вручную для Lua может занять много времени, само собой никто не хочет тратить на это время, чтоб делать свой проект фактически второй раз.
Этот инструмент создан, чтобы решить эту проблему. cJass2Lua может легко конвертировать cJass и JASS в читаемый Lua код, он поможет вам менее болезненно перенести код своей карты с JASS и cJass который находится в тупиковом положении на код в Lua. В большинстве случаев при переносе кода его даже не нужно редактировать, чтобы заставить работать, допустимо даже подавать мешанину из cJass и JASS кода на вход.
Скриншот:
Возможности:
  • Полная поддержка cJass и JASS
  • Возможность комбинировать синтаксис этих двух языков в одном файле
  • Поддержка парсинга структур(классов) в Lua'шные объекты мета-таблиц совместимые с оригинальным кодом, зачастую не требующие даже внесения правок чтобы они работали
  • Примитивный синтаксический анализ (на правильность кода) в процессе парсинга и вывод ошибок в лог
  • Генерация Lua кода на основе вашего cJass/JASS кода
  • Генерация спец-комментариев emmyDoc для Lua, которые помогают IDE ориентироваться в коде
  • Способен конвертировать common.j, blizzard.j и JASS код любой сложности
  • Удобный выбор файла/папки с файлами
  • Конвертация одиночных файлов
  • Массовая конвертация файлов из папки в папку
  • Подробное логгирование всех действий программы в лог файл для анализа проблем
  • Распознавание пост-инкрементов и пре-инкрементов
  • 100% читабельный код на выходе
  • Сохраняет комментарии, их позиции и переносы строк в любых местах
  • Сохраняет совместимость кода и его изначальную планировку (порой достаточно просто конвертировать текст каждого триггера по отдельности и ваша карта уже работает на Lua)
  • Расставляет табуляцию
  • Конфигурационный файл с настройками
  • Минималистичный встроенный графический интерфейс где удобно и подробно можно отслеживать прогресс
  • Интерфейс командной строки
Ограничения:
  • Отсутствует и вряд ли планируется семантический анализатор. За семантику выражений отвечает автор скриптов.
  • Структуры не поддерживают наследование и не понимают разницу между public и private (поддерживаются статические методы, статические переменные переводятся в глобальные)
  • Отсутствие поддержки расширенных фич vJASS как module, library, scope (Они по сути в Lua и не нужны, и просто игнорируются при парсе)
  • Не поддерживаются пре-процессорные директивы (Лишено смысла при переводе в Lua)
  • Макросы ограничены. блоки define распознаются, но только как константы. Избегайте функциональных макросов.
  • В некоторых случаях массивы в Lua индексируются с единицы, в большинстве случаев вам это ничем не грозит, но имейте в виду.
  • Инкременты в выражениях выгдядят так a = (var++) --> a = (var + 1). Но сам var в этом случае не увеличится на 1, нужно фиксить руками.
  • Циклы for из cJass не поддерживаются и вряд ли будут, перед тем как транслировать файл на Lua - сохраните его на диск.
  • Всё на английском языке
Внимание:
Перед преобразованием кода, убедитесь что...
  • Ваш код на 100% правильный и не содержит ошибок
  • Ваши структуры не используют наследование
  • Если в вашей структуре предусмотрен конструктор (статический "создавальщик") то он обязан называться new или create
  • Если у вас в коде используются структуры не объявленные в этом файле, объявите их в начале файла при помощи type StructName, так парсер поймет с чем имеет дело
  • Не используются ключевые слова в качестве идентификаторов. Такие как do, else, while, then и тд.
  • Имейте в виду, что хоть и присутствует умная замена оператора конкатенации строк, строчные идентификаторы и функции объявленные в других файлах не будут распознаны как строки и если + не поменялся на .. - это придется делать вручную.
Приложение оставляет после своей работы рядом с собой лог файл, читайте его если вдруг что-то не так. Когда нормально отрабатывает приложение - там не должно быть ни одного сообщения типа Warning, Critical или Fatal.
Пример преобразования:
//Входящий JASS/cJass код
type Projectile

bool KatonItachiConditions()
{
	if (GetSpellAbilityId() == 'A07Z')
	{
		return true;
	}

	return false;
}

define
	KATON_DUMMY           =  1
	KATON_RADIUS		  =  2
	KATON_DAMAGE		  =  3
	KATON_FINAL_POINT_X   =  4
	KATON_FINAL_POINT_Y   =  5
	KATON_EFFECT          =  6
	KATON_DIRECTION       =  7
	KATON_TRAVELED        =  8
	KATON_DMG_FACTOR      =  9
	
	
	KATON_DISTANCE        =  1100
	KATON_VELOCITY        =  5.35
enddefine

globals 
	unit g_KatonDummy;
	float g_KatonDMG;
	trigger g_TrgKatonPreCast;
endglobals

void KatonItachiActions()
{
	unit u = GetTriggerUnit();
	player p = GetOwningPlayer(u);
	location loc = GetSpellTargetLoc();
	location myLoc = GetUnitLoc(u);
	float facing = GetUnitFacing(u);
	location spawnPoint = PolarProjectionBJ(myLoc, 115.00, facing);
	location finalPoint = PolarProjectionBJ(spawnPoint, KATON_DISTANCE, facing);
	int lvl = GetUnitAbilityLevel(u, GetSpellAbilityId());
	float r = 200 + (25 * (lvl - 1));
	float dmg = 10;//10 + (4 * (lvl - 1)); 
	float travelFactor = 0.006 + (0.002 * (lvl - 1));
	float dummyScale = 2.00 + (0.30 * (lvl - 1));
	
	timer t = CreateTimer();
	InitPeriodicTimer(t, 0.01, 3.5);
	unit dummy =  CreateDummy(p, u, spawnPoint);
	SetUnitPathing(dummy, false);
	effect e = AddSpecialEffectTarget("fireball.mdx", dummy, "origin");
	SetUnitScale(dummy, dummyScale, dummyScale, dummyScale);
	SaveUnitHandle(g_Hashtable, GetHandleId(t), KATON_DUMMY, dummy);
	SaveReal(g_Hashtable, GetHandleId(t), KATON_RADIUS, r);
	SaveReal(g_Hashtable, GetHandleId(t), KATON_DAMAGE, dmg);
	SaveReal(g_Hashtable, GetHandleId(t), KATON_DMG_FACTOR, travelFactor);
	SaveReal(g_Hashtable, GetHandleId(t), KATON_DIRECTION, facing);
	SaveReal(g_Hashtable, GetHandleId(t), KATON_TRAVELED, 0);
	SaveReal(g_Hashtable, GetHandleId(t), KATON_FINAL_POINT_X, GetLocationX(finalPoint));
	SaveReal(g_Hashtable, GetHandleId(t), KATON_FINAL_POINT_Y, GetLocationY(finalPoint));
	SaveEffectHandle(g_Hashtable, GetHandleId(t), KATON_EFFECT, e);
	
	RemoveLocation(spawnPoint);
	RemoveLocation(loc);
	RemoveLocation(myLoc);
	RemoveLocation(finalPoint);
	
	TimerStart(t, 0.01, true, lambda void ()
	{
		timer t = GetExpiredTimer();
		float dur = GetTimerDuration(t);
		unit dummy = LoadUnitHandle(g_Hashtable, GetHandleId(t), KATON_DUMMY);
		location dummyLoc = GetUnitLoc(dummy);
		float r = LoadReal(g_Hashtable, GetHandleId(t), KATON_RADIUS);
		float traveled = LoadReal(g_Hashtable, GetHandleId(t), KATON_TRAVELED);
		float dir = LoadReal(g_Hashtable, GetHandleId(t), KATON_DIRECTION);
		float finalPointX = LoadReal(g_Hashtable, GetHandleId(t), KATON_FINAL_POINT_X);
		float finalPointY = LoadReal(g_Hashtable, GetHandleId(t), KATON_FINAL_POINT_Y);
		location newLoc = PolarProjectionBJ(dummyLoc, KATON_VELOCITY, dir);
		SetUnitPositionLoc(dummy, newLoc);
		RemoveLocation(newLoc);
		RemoveLocation(dummyLoc);
		traveled += KATON_VELOCITY;
		SaveReal(g_Hashtable, GetHandleId(t), KATON_TRAVELED, traveled);
		
		if (ModuloInteger(R2I(dur * 100), 10) == 0)
		{
			group g = CreateGroup();
			float travelFactor = LoadReal(g_Hashtable, GetHandleId(t), KATON_DMG_FACTOR);
			float dmg = LoadReal(g_Hashtable, GetHandleId(t), KATON_DAMAGE) + (traveled * travelFactor);
			g_KatonDummy = dummy;
			g_KatonDMG = dmg;
			boolexpr bexp = Condition(lambda bool ()
			{
				unit u = GetFilterUnit();
				if (!IsPlayerAlly(GetOwningPlayer(u), GetOwningPlayer(g_KatonDummy)) && !IsUnitType(u, UNIT_TYPE_STRUCTURE) && IsUnitAlive(u) && !IsUnitDummy(u))
				{
					return true;
				}
				return false;
			});
			GroupEnumUnitsInRange(g, GetUnitX(dummy), GetUnitY(dummy), r, bexp);
			ForGroup(g, lambda void ()
			{
				 DummyDealDamage(g_KatonDummy, GetEnumUnit(), g_KatonDMG, SCHOOL_MAGIC);
			});
			SaveReal(g_Hashtable, GetHandleId(t), KATON_DAMAGE, dmg);
			DestroyEffect(AddSpecialEffect("Objects\\Spawnmodels\\Other\\NeutralBuildingExplosion\\NeutralBuildingExplosion.mdl", GetUnitX(dummy), GetUnitY(dummy)));
			DestroyBoolExpr(bexp);
			DestroyGroup(g);
		}
		
		
		
		if (!TimerTick(t) || dummy == null || traveled > KATON_DISTANCE)
		{
			DestroyEffect(LoadEffectHandle(g_Hashtable, GetHandleId(t), KATON_EFFECT));
			RemoveUnit_s(dummy, "KatonItachiActions", "KatonItachi");
			DestroyTimer_s(t);
		}
	});
}

void KatonSoundActions()
{
	unit u = GetTriggerUnit();
	AddSoundUnit("katon.mp3", u);
	u = null;
}

void KatonItachiActionsNew()
{
	unit u = GetTriggerUnit();
	location loc = GetSpellTargetLoc();
	int lvl = GetUnitAbilityLevel(u, GetSpellAbilityId());
	float r = 200 + (25 * (lvl - 1));
	float dmg = 100;//100 + (4 * (lvl - 1)); 
	float travelFactor = 0.04 + (0.02 * (lvl - 1));
	float dummyScale = 2.00 + (0.30 * (lvl - 1));
	
	FinishDuel();
	Projectile katonProj = Projectile.create(DEFAULT_DUMMY, "fireball.mdx", dummyScale, u, 110);
	katonProj.SetVelocity(535, 1.0);
	katonProj.DamageOnce(false);
	katonProj.SetDamageData(0.1, dmg, r, 0, 0, travelFactor, SCHOOL_MAGIC);
	katonProj.SetDestLoc(loc);
	katonProj.SetDistance(1100, true);
	katonProj.InstantRemove(true);
	katonProj.SetDamageEffect("Objects\\Spawnmodels\\Other\\NeutralBuildingExplosion\\NeutralBuildingExplosion.mdl");
	katonProj.Launch();
	
	RemoveLocation(loc);
	u = null;
	loc = null;
}

void InitTrig_KatonItachi()
{
    gg_trg_KatonItachi = CreateTrigger();
	g_TrgKatonPreCast = CreateTrigger();
    TriggerRegisterAnyUnitEventBJ(gg_trg_KatonItachi, EVENT_PLAYER_UNIT_SPELL_EFFECT);
	TriggerRegisterAnyUnitEventBJ(g_TrgKatonPreCast, EVENT_PLAYER_UNIT_SPELL_CHANNEL);
    TriggerAddCondition(gg_trg_KatonItachi, Condition(function KatonItachiConditions));
    TriggerAddAction(gg_trg_KatonItachi, function KatonItachiActionsNew);
	TriggerAddCondition(g_TrgKatonPreCast, Condition(function KatonItachiConditions));
    TriggerAddAction(g_TrgKatonPreCast, function KatonSoundActions);
}
-- Lua код на выходе

---@class  Projectile
---@return bool
function KatonItachiConditions()
	if (GetSpellAbilityId() == FourCC('A07Z')) then
		return true
	end
	
	return false
end

KATON_DUMMY = 1	---@type integer	
KATON_RADIUS = 2	---@type integer	
KATON_DAMAGE = 3	---@type integer	
KATON_FINAL_POINT_X = 4	---@type integer	
KATON_FINAL_POINT_Y = 5	---@type integer	
KATON_EFFECT = 6	---@type integer	
KATON_DIRECTION = 7	---@type integer	
KATON_TRAVELED = 8	---@type integer	
KATON_DMG_FACTOR = 9	---@type integer	
KATON_DISTANCE = 1100	---@type integer	
KATON_VELOCITY = 5.35	---@type real	

-- g_KatonDummy	---@type unit	
-- g_KatonDMG	---@type float	
-- g_TrgKatonPreCast	---@type trigger	

---@return void
function KatonItachiActions()
	local u = GetTriggerUnit()
	local p = GetOwningPlayer(u)
	local loc = GetSpellTargetLoc()
	local myLoc = GetUnitLoc(u)
	local facing = GetUnitFacing(u)
	local spawnPoint = PolarProjectionBJ(myLoc, 115.00, facing)
	local finalPoint = PolarProjectionBJ(spawnPoint, KATON_DISTANCE, facing)
	local lvl = GetUnitAbilityLevel(u, GetSpellAbilityId())
	local r = 200 + (25 * (lvl - 1))
	local dmg = 10	-- 10 + (4 * (lvl - 1)); 
	local travelFactor = 0.006 + (0.002 * (lvl - 1))
	local dummyScale = 2.00 + (0.30 * (lvl - 1))
	
	local t = CreateTimer()
	InitPeriodicTimer(t, 0.01, 3.5)
	local dummy = CreateDummy(p, u, spawnPoint)
	SetUnitPathing(dummy, false)
	local e = AddSpecialEffectTarget("fireball.mdx", dummy, "origin")
	SetUnitScale(dummy, dummyScale, dummyScale, dummyScale)
	SaveUnitHandle(g_Hashtable, GetHandleId(t), KATON_DUMMY, dummy)
	SaveReal(g_Hashtable, GetHandleId(t), KATON_RADIUS, r)
	SaveReal(g_Hashtable, GetHandleId(t), KATON_DAMAGE, dmg)
	SaveReal(g_Hashtable, GetHandleId(t), KATON_DMG_FACTOR, travelFactor)
	SaveReal(g_Hashtable, GetHandleId(t), KATON_DIRECTION, facing)
	SaveReal(g_Hashtable, GetHandleId(t), KATON_TRAVELED, 0)
	SaveReal(g_Hashtable, GetHandleId(t), KATON_FINAL_POINT_X, GetLocationX(finalPoint))
	SaveReal(g_Hashtable, GetHandleId(t), KATON_FINAL_POINT_Y, GetLocationY(finalPoint))
	SaveEffectHandle(g_Hashtable, GetHandleId(t), KATON_EFFECT, e)
	
	RemoveLocation(spawnPoint)
	RemoveLocation(loc)
	RemoveLocation(myLoc)
	RemoveLocation(finalPoint)
	
	TimerStart(t, 0.01, true, function ()
		local t = GetExpiredTimer()
		local dur = GetTimerDuration(t)
		local dummy = LoadUnitHandle(g_Hashtable, GetHandleId(t), KATON_DUMMY)
		local dummyLoc = GetUnitLoc(dummy)
		local r = LoadReal(g_Hashtable, GetHandleId(t), KATON_RADIUS)
		local traveled = LoadReal(g_Hashtable, GetHandleId(t), KATON_TRAVELED)
		local dir = LoadReal(g_Hashtable, GetHandleId(t), KATON_DIRECTION)
		local finalPointX = LoadReal(g_Hashtable, GetHandleId(t), KATON_FINAL_POINT_X)
		local finalPointY = LoadReal(g_Hashtable, GetHandleId(t), KATON_FINAL_POINT_Y)
		local newLoc = PolarProjectionBJ(dummyLoc, KATON_VELOCITY, dir)
		SetUnitPositionLoc(dummy, newLoc)
		RemoveLocation(newLoc)
		RemoveLocation(dummyLoc)
		traveled = traveled + KATON_VELOCITY
		SaveReal(g_Hashtable, GetHandleId(t), KATON_TRAVELED, traveled)
		
		if (ModuloInteger(R2I(dur * 100), 10) == 0) then
			local g = CreateGroup()
			local travelFactor = LoadReal(g_Hashtable, GetHandleId(t), KATON_DMG_FACTOR)
			local dmg = LoadReal(g_Hashtable, GetHandleId(t), KATON_DAMAGE) + (traveled * travelFactor)
			g_KatonDummy = dummy
			g_KatonDMG = dmg
			local bexp = Condition(function ()
				local u = GetFilterUnit()
				if ( not IsPlayerAlly(GetOwningPlayer(u), GetOwningPlayer(g_KatonDummy)) and  not IsUnitType(u, UNIT_TYPE_STRUCTURE) and IsUnitAlive(u) and  not IsUnitDummy(u)) then
					return true
				end
				return false
			end)
			GroupEnumUnitsInRange(g, GetUnitX(dummy), GetUnitY(dummy), r, bexp)
			ForGroup(g, function ()
				DummyDealDamage(g_KatonDummy, GetEnumUnit(), g_KatonDMG, SCHOOL_MAGIC)
			end)
			SaveReal(g_Hashtable, GetHandleId(t), KATON_DAMAGE, dmg)
			DestroyEffect(AddSpecialEffect("Objects\\Spawnmodels\\Other\\NeutralBuildingExplosion\\NeutralBuildingExplosion.mdl", GetUnitX(dummy), GetUnitY(dummy)))
			DestroyBoolExpr(bexp)
			DestroyGroup(g)
		end
		
		
		if ( not TimerTick(t) or dummy == nil or traveled > KATON_DISTANCE) then
			DestroyEffect(LoadEffectHandle(g_Hashtable, GetHandleId(t), KATON_EFFECT))
			RemoveUnit_s(dummy, "KatonItachiActions", "KatonItachi")
			DestroyTimer_s(t)
		end
	end)
end

---@return void
function KatonSoundActions()
	local u = GetTriggerUnit()
	AddSoundUnit("katon.mp3", u)
	u = nil
end

---@return void
function KatonItachiActionsNew()
	local u = GetTriggerUnit()
	local loc = GetSpellTargetLoc()
	local lvl = GetUnitAbilityLevel(u, GetSpellAbilityId())
	local r = 200 + (25 * (lvl - 1))
	local dmg = 100	-- 100 + (4 * (lvl - 1)); 
	local travelFactor = 0.04 + (0.02 * (lvl - 1))
	local dummyScale = 2.00 + (0.30 * (lvl - 1))
	
	FinishDuel()
	local katonProj = Projectile:create(DEFAULT_DUMMY, "fireball.mdx", dummyScale, u, 110)
	katonProj.SetVelocity(535, 1.0)
	katonProj.DamageOnce(false)
	katonProj.SetDamageData(0.1, dmg, r, 0, 0, travelFactor, SCHOOL_MAGIC)
	katonProj.SetDestLoc(loc)
	katonProj.SetDistance(1100, true)
	katonProj.InstantRemove(true)
	katonProj.SetDamageEffect("Objects\\Spawnmodels\\Other\\NeutralBuildingExplosion\\NeutralBuildingExplosion.mdl")
	katonProj.Launch()
	
	RemoveLocation(loc)
	u = nil
	loc = nil
end

---@return void
function InitTrig_KatonItachi()
	gg_trg_KatonItachi = CreateTrigger()
	g_TrgKatonPreCast = CreateTrigger()
	TriggerRegisterAnyUnitEventBJ(gg_trg_KatonItachi, EVENT_PLAYER_UNIT_SPELL_EFFECT)
	TriggerRegisterAnyUnitEventBJ(g_TrgKatonPreCast, EVENT_PLAYER_UNIT_SPELL_CHANNEL)
	TriggerAddCondition(gg_trg_KatonItachi, Condition(KatonItachiConditions))
	TriggerAddAction(gg_trg_KatonItachi, KatonItachiActionsNew)
	TriggerAddCondition(g_TrgKatonPreCast, Condition(KatonItachiConditions))
	TriggerAddAction(g_TrgKatonPreCast, KatonSoundActions)
end

Инструкция:
Чтобы пользоваться просто укажите во входящий путь в окне приложения путь к файлу или папке с cjass/jass файлами при помощи кнопки Browse. Чтобы выбрать папку, а не файл - нажмите Browse с зажатым шифтом. Внизу укажите путь к папке в которую запишется готовый Lua файл (или прямой путь к выходному луа файлу), выбор файла или папки через Browse аналогичен. Также имеется и консольный интерфейс (первый аргумент входящий путь, второй - исходящий). Если исходящий путь не указан, то .lua файлик сохранится туда же, где и входящий .j файлик.
СКАЧАТЬ: (версия v1.12 07.12.2019)
x86 сборка: Скачать
x64 сборка: Скачать
Исходный код (и подробности использования):
GitHub: github.com/fullmetal-a/cjass2lua
Изменения v1.12:
  • Исправлены все случаи, когда this. не добавлялся периодически перед членами и методами
  • Исправлен баг, когда иногда оператор ! заменялся на - вместо not
  • Теперь все названия методов корректны и полностью работоспособны, они больше не пишутся через :
  • Добавлена поддержка .deallocate
  • Теперь переменная объекта текущего класса, созданная в методе .create при помощи .allocate удаляется при трансляции кода, а все обращения к ней меняются на this.
  • Исправлено множество багов
Изменения v1.11/1.10:
  • Улучшен парсинг
  • Улучшен консольный интерфейс
  • Исправлены редкие критические баги
  • Исправлен критический баг с трансляцией идентификаторов
  • Теперь поля входящих и выходящих путей в интерфейсе больше не read-only
Изменения v1.09:
  • Добавлена поддержка перевода структур/классов в мета-табличные объекты
  • Добавлена поддержка коротких void лямбда-выражений через оператор ()->
  • Парс теперь прерывается с ошибкой если мы переобъявляем глобальную функцию\переменную
  • Небольшие улучшения и оптимизация
  • Исправления багов
`
ОЖИДАНИЕ РЕКЛАМЫ...
1
Drulia_san:
конечно, везде пишут
всем пофигу на чем работает карта
Doc:
делал несколько карт на сжасс, в тредах этого не упоминал
не везде, а обычно. Однако, если не пишут, то я сам спрашиваю, если заинтересовался картой.
Drulia_san:
не все карты выкладывают в места вроде хгм
да, вот тут мои аргументы хворают, в эту эфемерную карту я ясное дело поиграл ментально, но так как физического доступа у меня к ней нету, то я так и не узнал про неё ничего.
15
ProstoParya:
Drulia_san:
в эту эфемерную карту я ясное дело поиграл ментально
то я сам спрашиваю
Никому нет дела до твоего отношения к cJass и до того, что ты считаешь его невостребованным, к тому, что ты конечно же в курсе про все карты на свете и на чем они там сделаны, успокойся.
Заинтересованным: И да, как было предложено выше - я реализовал распознавание строк и строчных переменных\аргументов\функций. При склеивании их оператор + должен корректно меняться на ..
Осталось добавить парсинг структур и всё.
15
Апдейт
Добавил поддержку обычного JASS, теперь можно конвертировать любые скрипты вообще. Но пока что структуры всё еще не поддерживаются.
1
Drulia_san~:
Никому нет дела до твоего отношения к cJass
что ты считаешь его невостребованным
что ты конечно же в курсе про все карты
успокойся
ай мин, я-то спокоен, непонятно почему ты завёлся. Мне нравится cJass, он интересен, изначальный упрёк в потёртом сообщении был к заявлению о том,
что правила синтаксиса в стиле C тупо рулят
и ремарка к тому, что Lua появился уже давненько, пока рефорж ещё в бету не вышел. Алсо,
Drulia_san~:
Так что давай без поспешных выводов.
камон.
мне интересно знать, что следует, на чём сделана та или иная карта и я написал, что не играл ни в одну карту на cJass, а не то, что никто на нём карты не пишет, особенно где-то в закромах, не выводя на свет. Ясное дело, что до моего мнения никому нет дела, но если бы каждый следовал такой логике и не решал его выражать, то комментарии под твоим тредом были бы пустыми, как и под любым другим.
15
ProstoParya:
что правила синтаксиса в стиле C тупо рулят
Ну да, так как многие их предпочитают за компактность, лаконичность и читабельность. Я сомневаюсь что многим людям нравится писать local перед типом данных, call перед каждым вызовом и set перед каждым присвоением, и конечно же типы данных без сокращений вроде integer и boolean. Писать на JASS имеет смысл только для сохранения совместимости своей карты где бы она ни была редактирована (или еще какие-то конкретные технические нужды). Этим я и обосновываю почему синтаксис С рулит.
И я бы еще раз не делал выводов о том, что "я не играл ни в одну карту на cJass", потому что черт его знает что там внутри той или иной карты. Я так же могу сказать что не играл ни в одну карту на wurst script потому что с первого взгляда я реально их не видел, но его многие используют.
28
А как по мне, синтаксис пайтона 3 куда лучше, чем в С, долой {} скобки!
Имхо, когда я вижу стену кода в С стиле с кучей {} скобок, которая ещё и растёт вширь, мне становится плохо.
15
PT153:
А как по мне, синтаксис пайтона 3 куда лучше, чем в С, долой {} скобки!
Имхо, когда я вижу стену кода в С стиле с кучей {} скобок, которая ещё и растёт вширь, мне становится плохо.
Периодически приходится работать с питоном и честно говоря я его не люблю за его подход построения блоков через отступы, старые добрые фигурные скобочки моё всё, впрочем каждому своё) Ну и как я описал выше, для любителей JASS я добавил его полную поддержку, cJass теперь не обязателен во входящих файлах
28
честно говоря я его не люблю за его подход построения блоков через отступы
Есть небольшой лайфхак: если какой-то блок занимает 1 строчку, можно не делать перенос, а просто пробел после :.
if bad(smth): return
Я в шутку сказал, я нормально отношусь ко всем синтаксисам. В С мне конкретно не нравятся операторы &&, || и !. and, or и not, имхо, делают код более читабельным и не сильно больше места занимают.
15
Периодически приходится работать с питоном и честно говоря я его не люблю за его подход построения блоков через отступы
Каким бы не был способ разделения блоков кода, человеческий глаз в любом случае ориентируется на отступы. При всех прелестях C, на пятый час писанины фигурные скобки начинают в глазах сливаться с фоном. Отступы это обязательный стандарт оформления кода. Что могло быть лучше, чем сделать его частью синтаксиса.
Drulia_san:
Я сомневаюсь что многим людям нравится писать local перед типом данных, call перед каждым вызовом и set перед каждым присвоением, и конечно же типы данных без сокращений вроде integer и boolean.
Зависит от опыта конкретного кодера. На хайве можно найти опросы и вопросы, что лучше, vJass, cJass или ZINC. Мнение за бугром обычно не в пользу сJass, На это приводят набор объективных причин, среди которых отсутствие жесткого требования следовать языку и, как следствие, возможность смешивать JASS и vJass конструкции с cJass. В итоге код превращается в жуткую мешанину из набора разных синтаксисов.
В то же время молодые, неопытные пользователи куда легче воспринимают именно ключевые слова
               endif
            endloop
        endmethod
    endstruct
endlibrary
где они могут сразу понять, о каких именно блоках кода идет речь, чем эквивалентный
                }
            }
        }
    }
}
29
Это продукт для паверюзеров изначально, совершенно нассать как там код воспринимают молодые и неопытные. Закрывающие кейворды, разные для каждого блока, очень мешают при рефакторинге. В цинке есть пара хороших идей, но в сумме это тоже говно, объявлять все локалки в начале функции - треш. В сжассе при этом есть полезные фичи вроде форича по группам.
18
PT153:
А как по мне, синтаксис пайтона 3 куда лучше, чем в С
Да, есть такое, просто они там парятся с обратной совместимостью, язык старенький, хотя и завезли плюшек в 20ом стандарте

GetLocalPlayer, поддерживаю, как-то прогал на ночь, так эти скобки в глазах слипались донельзя
15
поддерживаю, как-то прогал на ночь, так эти скобки в глазах слипались донельзя
Надо просто спать идти в таких случаях =) Если сонным прогать потом с утра охренеешь с той каши что увидишь в редакторе и вопросов самому себе "как мне вообще такое пришло в голову"
А если серьезно поддерживаю вышесказанное от Doc, мусорные слова в духе endloop endfunction endif, call set захламляют видимость и сбивают с умных мыслей, когда скобочка просто закрывает блок и не привлекает к себе внимания, когда глаза скользят по словам, а новичкам нужно просто по-практиковаться и начинать с чего-то простого, например с Lua, у него синтаксис идеален для начинающих
18
Для меня главный интерес представляют макросы. С помощью них можно было устанавливать параметры функции по умолчанию, создавать шаблоны классов, создавать подобие inline функций. А также добавлять недостающие языку возможности вводя новые синт. конструкций
25
Drulia_san, мне интересно, программку сам же написал? С нуля? Что использовал для этого или большая часть ручной работы думая своей головой? Интересно мнение разработчика, каково писать такую программку и сколько это заняло времени/сил (раскрыть секреты производства) ;)
15
konvan5:
Drulia_san, мне интересно, программку сам же написал? С нуля? Что использовал для этого или большая часть ручной работы думая своей головой? Интересно мнение разработчика, каково писать такую программку и сколько это заняло времени/сил (раскрыть секреты производства) ;)
Да, писал с нуля исключительно сам, начал еще летом, потом времени не было и было лень закончить, продолжил в начале ноября. Изначально это был проект для меня, думал напишу кое-как ради того чтоб свою карту конвертировать, которая была под угрозой. Все компоненты написаны мной (обертка для регулярок, логгер и тд), используется лишь stl и немного winapi. Ты сам можешь посмотреть там ссылка на гитхаб висит, можешь поковырять там что угодно. Позже это начало вырастать в нечто большее и решил это выложить. По времени в общей сложности заняло месяц где-то если сложить всё вместе, опять же можешь глянуть календарь активности на гитхабе) Если ты заметил, там класс называется Parser2, потому что был первый парсер и он был ужасен, пришлось переписывать снова.
Я использовал чистый винапи по нескольким причинам:
  1. Никто не будет запускать это на линуксе\маке, весь геймдев по варкрафту был есть и будет на винде
  2. Он быстрый и очень функциональный
  3. Я и любой кто захочет это собрать сможет это сделать сходу ничего не подключая и не скачивая
  4. Хотелось облегчить проект от лишних библиотек вроде Qt, MFC
30
Drulia_san, коли уже есть поддержка jass можно ли научить программу разбирать эти файлы:
чтоб получилось нечто подобное:
а то я для подсветки просто позаменял всё регулярками, что не всегда нормально сработало.
Загруженные файлы
15
NazarPunk:
Drulia_san, коли уже есть поддержка jass можно ли научить программу разбирать эти файлы:
чтоб получилось нечто подобное:
а то я для подсветки просто позаменял всё регулярками, что не всегда нормально сработало.
Окей, сделаю, не обещаю что будет прям как там, но будет парсить нормально
30
Окей, сделаю, не обещаю что будет прям как там, но будет парсить нормально
Будет просто шикарно, особенно если EmmyDoc расставить.
Загруженные файлы
25
Drulia_san:
Да, писал с нуля исключительно сам
Спасибо за развернутый ответ! :)
Проект и правда очень перспективный с выходом reforged'a и может помочь многим картостроителям... ибо боли у нас всех общие)))
15
NazarPunk:
Будет просто шикарно, особенно если EmmyDoc расставить.
В принципе не сложно, но объявления типов я буду игнорировать, луа не типизированный язык и будет глупо добавлять правила парсинга объявления типов..))
konvan5:
Drulia_san:
Да, писал с нуля исключительно сам
Спасибо за развернутый ответ! :)
Проект и правда очень перспективный с выходом reforged'a и может помочь многим картостроителям... ибо боли у нас всех общие)))
Пожалуйста, рад стараться)
30
луа не типизированный язык и будет глупо добавлять правила парсинга объявления типов..))
Тогда IDE не будет подсвечивать типы передаваемых данных в функцию, что не очень удобно.

к тому же придётся каждый return заменить на any.
Загруженные файлы
15
NazarPunk:
луа не типизированный язык и будет глупо добавлять правила парсинга объявления типов..))
Тогда IDE не будет подсвечивать типы передаваемых данных в функцию, что не очень удобно.

к тому же придётся каждый return заменить на any.
Окей в принципе не сложно, я почти закончил
Обновил софтину, кучу всего улучшил, файлы common.j, blizzard.j, common.ai теперь парсятся без ошибок, синтаксический анализатор в выхлопном луа коде тоже проблем не обнаружил, emmyDoc добавляется куда только можно. Можно проверять
Хочу поделиться успешными результатами, это действительно работает, вот пример первой карты полностью конвертированной на Lua с cJass автоматически. Это моя старая карта, там всего около 20 триггеров на cJass + глобальные функции. Из того что я редактировал всего лишь раз поправил 1 оператор и убрал лишние дефайны, весь код сгенерирован этой утилитой и работает) Карту прикрепил, можете сами посмотреть в редакторе если кому интересно.
Мини-гайд как конвертировать карту:
  1. Экспортируйте все триггеры в отдельные файлы, я это делал собственной утилитой которая разбивает скрипт карты по файлам
  2. Конвертируйте их все в Lua (но сначала прочитайте ограничения и предупреждения из статьи выше в главном посте, убедитесь что ваш код не выходит за рамки возможностей программы)
  3. Удалите все триггеры, гуи и джасс скрипты из карты
  1. Откройте настройки карты и на второй вкладке поменяйте JASS на Lua
  2. Сохраните
  3. Создайте по скрипту в триггерах в соответствии с названиями файлов которые вы конвертнули
  4. Копипастить текст триггеров в карту файл за файлом
  5. Создать точку входа (лучше всего перехват InitGlobals), сначала вызвать оттуда все функции InitTrig_ и потом напрямую скрипт инициализации карты
  6. Готово, в лучшем случае всё будет работать, если не работает дорабатываем ищем ошибки
В идеале карта-исходник должна быть в виде папки где на каждый скрипт реальный отдельный файл, который при сборке склеивается в один луа скрипт, но пока сойдет и так. Возможно с релизом рефоржа нам завезут IDE в редактор триггеров или возможность сборки по файлам. Есть еще ceres wc3 для сборки карт который с остервенением советуют все разработчики на хайве и us форумах на батлнете, но это такое г...o, написанное не пойми на чем, запускаемое непонятно как с отвратительной документацией где не описано нормально и кратко как этим пользоваться. Потому использовать его крайне не советую и лучше ждать релиза reforged, где 100% будет адекватное и простое средство для сборки кода или редактирования скриптов.
Загруженные файлы
30
Обновил софтину, кучу всего улучшил, файлы common.j, blizzard.j, common.ai теперь парсятся без ошибок, синтаксический анализатор в выхлопном луа коде тоже проблем не обнаружил, emmyDoc добавляется куда только можно. Можно проверять
Всё отлично работает, обновил файлы в своей статье.
15
NazarPunk:
Обновил софтину, кучу всего улучшил, файлы common.j, blizzard.j, common.ai теперь парсятся без ошибок, синтаксический анализатор в выхлопном луа коде тоже проблем не обнаружил, emmyDoc добавляется куда только можно. Можно проверять
Всё отлично работает, обновил файлы в своей статье.
Ееее, победа) Ну, осталось только поддержку структур добавить думаю, и можно считать проект завершенным
38
Отсутствие поддержки расширенных фич vJASS как module, library, scope
И зачем это тогда?) код без этих фич таких размеров, что его и руками можно перенести
Чтобы оставить комментарий, пожалуйста, войдите на сайт.