Перейти к контенту
Dennis_Chikin

Прозекторская

Рекомендуемые сообщения

"Вскрытие показало, что больной умер от вскрытия."

Тема для "крупной формы", то есть, на уровне скриптов целиком или больших частей оных скриптов. "Что у него внутри, зачем оно там, и что с этим можно сделать ?"

Изменено пользователем Dennis_Chikin
Ссылка на комментарий

модераторское:

 

дискуссия слегка переместилась в эмоциональную сферу, а предложения оппонентов, на сколько я вижу, читаются невнимательно. Ну и сами предложения эти несколько неконкретны.

 

По крайней мере лично я понял предлагаемое совершенно иначе, чем остальные.

Предлагаю внимательно перечитать хотя бы СОБСТВЕННЫЕ тексты, и попробовать сформулировать более четко и доходчиво. Я через некоторое время напишу, как именно понял.

 

2 Murarius: не совсем так. В некоторых случаях код не нужен. Или его еще нет. А вот описание в этих случаях желательно бы как можно более однозначное.

Изменено пользователем Dennis_Chikin
Ссылка на комментарий

 

 

попробуй приведи код того что ты предлагаешь, а то я себе по своему вижу, ты по своему, а там может че и порешим

Вот именно. А то вы тонете в общих рассуждениях. Я вообще представлял себе посты в этой теме так: Утверждение -> Теоретическое обоснование (если требуется) -> Код.

Уверен, Денис тоже хотел что-то подобное наблюдать.

Самодисциплинируйтесь, пожалуйста.

Ссылка на комментарий

Вроде, 20 минут выкроил, выполняю обещанное.

 

Итак, мне вот тоже не нравятся работы с состояниями. Не нравятся тем, что получается слишком много букв, и очень трудно контролировать все это глазами. Буквально пару дней назад описка с 0 вместо 1 - и пол дня на то, чтоб ее найти.

Простыни получаются преразвесейшистые.

 

Накладные расходы по получению/сортировке/переключению работ со стейтами - тоже не маленькие. Но в данном случае как раз имеем повод отбросить хакерские замашки в пользу читаемости, и даже не задумываться особо про то, какой же из вариантов будет быстрее на сотую микросекунды .

 

Из собственно же методов борьбы с развесистыми простынями вижу два простых (в смысле, скриптовых, не дожидаясь, пока с неба свалится экзешник, чтоб сам кофе варил, и за пивом бегал):

 

1. Развернуть часть текущего ужаса и кошмара в плоские таблицы (все равно xr_gulag в итоге именно их хочет, и формирует). То есть, не вот вставка в переданную таблицу, и не проверка на каждый чих "подходящести", а отдать готовые. При некотором усилии можно эти работы со стейтами записывать так, что просто скользя глазом замечаешь отличия. И руками можно посчитать. А потом валидатор напустить, в сомнительных моментах. Этот код я вкладывал в более специализированной теме, ссылку давал, примеры давал, повторять смысла не вижу. Кому надо - найдет/посмотрит.

 

2. Перейти, вот как я понял прозвучавшие здесь предложения, к системе один смарт - несколько гулагов в нем.

Преимущество - простыни становятся гораздо менее обширными, общие параметры из работ выносятся в параметры гулага, можно даже банально эти работы наследовать, подставляя отличия.

То есть, для каждого стейта - один гулаг, в смарте - по гулагу для каждого стэйта.

 

С точки зрения кода, навскидку, переключение между гулагами - будет проще-изящнее-быстрее. На самом деле даже "освобождать/переназначать/и т.д." ни кого не надо. Переключили гулаг, переинициализировали логику, и все.

При покидании смарта - запустили "сборку мусора".

 

В обоих случаях, заметим, НЕ требуется срочно переделывать все готовое. Оба варианта вполне дополняют стандартный. Собственно, в моем варианте с плоскими таблицами есть вариант такого вот одностейтового гулага, и осталось только "когда-нибудь" дополнить до "более одного гулага в смарте". Работа вот с этим одностейтовым - по факту проще и по факту, оно быстрее. Проверено.

 

То есть, если коротко, то оно вот как-то так в итоге выглядит:

local g_comms = {

["atp_brigada"] = "stalker", -- 14.08, Калинин

["atp_fabrika_bandit"] = "bandit",

-- ["atp_stalk"] = "stalker", -- допа 2011

...

 

local g_jobs = {

 

["atp_fabrika_bandit"] = { -- Бандиты на АТП

{ section = "logic@atp_fabrika_bandit_walker1",

idle = 0, prior = 10, state = {0}, in_rest = "", out_rest = "" },

{ section = "logic@atp_fabrika_bandit_walker2",

idle = 0, prior = 10, state = {0}, in_rest = "", out_rest = "" },

...

 

local t_states = {

["esc_blokpost"] = esc_blokpost,

["esc_lager"] = esc_lager,

["esc_bridge"] = esc_bridge,

["esc_fabrika_bandit"] = esc_fabrika_bandit,

["esc_dogs_to_fox"] = esc_dogs_to_fox,

["esc_specnaz"] = esc_specnaz,

["esc_boars_dogs"] = esc_boars_dogs,

["esc_killers"] = esc_killers,

["esc_dogs_swarm"] = esc_dogs_swarm,

["esc_stalker_camp"] = esc_stalker_camp,

["esc_corps"] = esc_corps,

["esc_assault"] = esc_assault }

 

function load_states( gname, type ) -- стэйта нет - значит, всегда 0

return t_states[type]

end

 

function checkStalker( npc_community, gulag_type, npc_rank, obj )

local c = g_comms[gulag_type]

if c then return c == npc_community end

return ( obj["profile_name"] and obj:profile_name() == g_names[gulag_type] ) or false

end

 

function checkMonster( npc_community, gulag_type )

local c = g_comms[gulag_type]

if c then return c == npc_community end

if gulag_type == "esc_boars_dogs" then

return npc_community == "dog" or npc_community == "boar"

end

return false

end

 

Ну вот как-то так, да. Это "дополнительный", альтернативный формат записи. Но все еще один смарт - один гулаг. С несколькими - в 2 раза сокращается количество строк, и сами строки упрощаются (от них в основном только секции логики и нужны)

 

 

Вот что я не понял в звучавших предложениях - это заворачивать КАЖДУЮ работу в "псевдообъект". Подозреваю, что имелось в виду нечто иное.

Изменено пользователем Dennis_Chikin
Ссылка на комментарий
сейчас-то что мешает стейты внутрь логики засунуть (пусть даже по вашему человекопонятному)? кондлист доступен абсолютно для всего, для чего не доступен - сделать доступным. профит, не?

Так я об этом и пишу. Если специально не создавать на каждый чих новый gulag type с собственным condlist'ом (вместо использования логики там, где это возможно), то большой простыни из кучи секций и длинных condlist'ов не будет. И как раз получится, что вместо простыней из load_states станет достуен condlist.

 

не реализацию а просто синтаксис, то есть конечный вид желательно во всех красках вроде "до"/"после", и красно-жирным выделить где упрощения для таких как я.

В смысле, показать как должны выглядеть конфиги и описание работ?

local t = {

section = "logic@walker_1_logic",

in_restr = "level_prefix_in_restictor1", out_restr = "level_prefix_out_restictor1", 

squad = squad, group = groups[1],

predicate = function(...) return true end,

prior = 5, -- вот это руки чешутся убрать, но пока не знаю, как лучше это сделать

position_threshold = 50, -- от этого со временем тоже надо избавиться

state = {0, 1}  -- оставить обработку стейтов для совместимости, но в описании работ их стараться не использовать

}

 

 

[smart_terrain]

type = general_lager

squad = 0

groups = 1,2,3,4

capacity = 5 -- Не нужно. Ёмкость определяется количеством работ

cond = {+info1}

communities = dolg, freedom, monolith --Можно записать в виде condlist'а

 

 

[smart_terrain]

type = general_lager_normal, general_lager_alarm

 

[general_lager_normal]

squad = 0

groups = 1,2,3,4

cond = {+info1 !gulag_has_alarm}

accept_npc_cond = {=npc_community(dolg:freedom:monolith)} --вместо checkStalker/checkMonster

 

[general_lager_alarm]

squad = 0

groups = 1,2,3,4

cond = {+info1 !gulag_has_alarm}

accept_npc_cond = {=npc_community(dolg:freedom:monolith)}

 

 

Это пока набросок, тут ещё есть куда стремиться и что исправлять. В частности, возможности этих самых condlist'ов используются не оптимально, хотя и лучше, чем было.

 

То есть, не вот вставка в переданную таблицу, и не проверка на каждый чих "подходящести", а отдать готовые.

Это подойдёт только туда, где список работ неизменен и заранее известен.

В том же gulag_general подобное не прокатит.

Изменено пользователем Полтергейст
Ссылка на комментарий

prior = 5 - это нужно, когда есть работы, на которых должен быть кто-то конкретный, или когда нужно, чтобы из всех возможных заняты были именно эти.

 

У меня работы с условиями всегда проверяются первыми, так что здесь уже задумываться слишком сильно не надо.

Вообще, опять же, в мультигулаговый смарт такие отдельным гулагом имеет смысл оформлять.

 

Избавились.

 

сквады - имеет смысл менять динамически, раз пошла такая пьянка.

группы - как выяснили, нужны там, где задействованы в путях с сигналами.

 

position_threshold - это интересная такая штука... Смысл - надо ли в офлайне бежать к начальной точке пути.

 

capacity - нужно для текущего формата, если используешь условия в работах. И для генералов. Плюс, если они у тебя прописаны для всех - можешь исправить разные косяки, дописав "запасные работы" (классика жанра - волк/фанат/шустрый, и наймы на кордоне, где при неудачном стечении обстоятельств получаещь сбежавшего непися или висяк.)

 

 

Кондлисты - мне не нравятся. Медленные, и читаются плохо. Лучше иметь возможность задавать явно.

Ссылка на комментарий

 

 

Вот что я не понял в звучавших предложениях - это заворачивать КАЖДУЮ работу в "псевдообъект". Подозреваю, что имелось в виду нечто иное.

Не заворачивать, а преобразовывать. Все данные из таблицы работ перекинуть в объект, потом получить имя пути и сам путь, и сохранить в объект.

В класс можно перенести целую кучу методов, отвечающих за всякие проверки и назначения работ. Для человекочитаемости это точно пойдёт на пользу.

 

 

 

position_threshold - это интересная такая штука... Смысл - надо ли в офлайне бежать к начальной точке пути.

Разве? По-моему смысл другой. В оригинале это расстояние, ближе которого в онлайне персонажу устанавливается логика (setup_logic_что-то-там). Дальше этого расстояния логика не работает. Полезность - сомнительна. Некоторые схемы могут подглючивать, если они активируются далеко от первой точки пути. Но это проблема или реализации этих схем, или криво написанной логики.

То, что отметка о начале работы (beginJob) устанавливается, можно не принимать во внимание. Просто устанавливать её при достижении первой точке пути и не заморачиваться.

 

Запретить NPC идти к месту "работы" можно или установкой object_flags, или вызовом can_choose_alife_tasks(false) (но не абы-как и абы-где), или установкой ему нулевой скорости передвижения в оффлайне. Position_treshold не влияет ни на что из этого.

 

 

 

capacity - нужно для текущего формата, если используешь условия в работах.

Условия - это predicate что ли? Ну разве что для тех случаев, когда надо вытеснять кого-то из смарта, когда кто-то другой занял работы "с условиями"... но всё равно не вижу в этом смысла. Такой параметр больше подходит для самих работ, чтобы можно было назначить нескольким NPC одну и ту же логику, не создавая для этого несколько работ (это одна из причин для хранения работ в виде объектов, а не таблиц).

 

 

 

Кондлисты - мне не нравятся. Медленные, и читаются плохо. Лучше иметь возможность задавать явно.

Что читаются плохо - это дело привычки. Да и всё равно от них не уйти уже, используются везде.

Задавать явно возможность остаётся - написать {=вызов_функции} и в самой функции уже расписывать все подробности.

Ссылка на комментарий

Ох, похоже тут опять мифы обсуждают. job_position_threshold - это расстояние, при котором считается, что моб в оффлайне пришел к месту работы и ему можно назначать логику. Если это расстояние сделать слишком маленьким, то логика мобу не будет назначена. В качестве примеру приведу Барьер на Складах и значение 120 из ОП-2 (из Солянки, полагаю, тоже). К этому нужно заметить, и это, похоже, все то-ли не знают, то-ли упускают из вида. Мобы в оффлайне про логику и пути понятия не имеют. Это все только в онлайне работает. А в оффлайне моб всегда идет на точку смарт террейна. Его туда движок гонит. Вот для этого и используется упомянутое выше расстояние. Что бы xr_gulag мог определить, что моб дошел. Так вот, про Барьер и ОП-2 (вероятно и про Солянку). Идя на Барьер мобы прекращают свое движение на расстоянии большем, чем 120 метров от смарта. Это приводит к тому, что соотв. логика мобам не назначается и когда игрок подходит к свободовцам, что там стоят, все мутанты вываливаются в онлайн на этом месте. На самом же деле, мутанты должны быть около перехода на Радар и атаковать свободовцев оттуда, а не сваливаться им на голову.

 

Далее, can_choose_alife_task() не запрещает мобу идти к месту работы. Оно вообще к работам и логике прямого отношения не имеет. Эта функция управляет тем, будет-ли движок пытаться определить данного моба в какой-нибудь смарт террейн или нет. Если разрешено, то движок пойдет в цикле по всем смартам и каждый будет спрашивать: этого возьмешь? На самом деле не так прямо, но в данном случае это не важно. И вот когда движок закрепит моба за каким-то смартом, моб пойдет на точку этого смарта. И только дойдя до туда и выйдя в онлайн, ему xr_logic назначит онлайновую работу. Как только моб уйдет в оффлайн, движок опять погонит его на точку смарта и т.д.

Ссылка на комментарий

Этот "миф" дан вполне в ощущениях.

 

Вот так оно блин там сделано: да, когда дошел - считается заступившим, назначается логика и т.д.

 

А вот пока НЕ дошел - регулярно вызывается self:free_obj_and_reinit(), и вот только тогда моб каким-то загадочным образом может сдвинуться с места.

Ссылка на комментарий
расстояние, при котором считается, что моб в оффлайне
Не обязательно "в оффлайне". Просто проверяется, дошёл ли. В онлайне это тоже можно наблюдать - сначала идут медленно (работает action_alife_planner), а потом с определённого расстояния немного меняет маршрут и идёт быстрее. Потому что в этот момент задействуется логика, скрипты, состояния в state_mgr.На запрет идти к месту работы в оффлайне параметр job_position_treshold вообще никак не влияет.Насчёт can_choose_alife_tasks надо смотреть исходники движка.

 

в оффлайне про логику и пути понятия не имеют
Тоже не совсем верно. В оригинальном ТЧ идут к первой точке пути, от неё же и считается расстояние, из которого делается вывод - дошёл или не дошёл. Хотя при определённых переделках скрипта можно посылать их не в первую точку, а последовательно в 1, 2, 3 и т.д.
Ссылка на комментарий

Закомментите освобождение с работы для недошедших, и посмотрите на результат. В оффлайне.

Изменено пользователем Dennis_Chikin
Ссылка на комментарий

Продолжаем разговор про xr_logic:

 

 

try_sw_time1, try_sw_time2 = 0, 0

function try_switch_to_another_section( npc, st, actor )
	if _G.watchdog then return false end
	_G.watchdog = "try_switch"
	if not actor then abort( "try_switch_to_another_section, scheme: %s, no actor", st.scheme or "n/a" ) end

	local l = st.logic or abort( "try_switch_to_another_section, invalid logic, scheme: [%s] (%s)",
		st.active_scheme or "none", ( npc and npc:name() ) or "script" )

	local npc_id = npc:id()
	local sw, sw1, f

	local chk = {
		["on_actor_dist_le"] = function ( c )
			if npc.alive and npc:alive() and npc:see( actor )
			  and c.v1 >= distance_between( actor, npc ) then
				return true
		end	end,

		["on_actor_dist_le_nvis"] = function ( c )
			if c.v1 >= distance_between( actor, npc ) then
				return true
		end	end,

		["on_actor_dist_ge"] = function ( c )	-- составляет пару с on_actor_dist_le, где >=
			if npc.alive and npc:alive() and npc:see( actor )
			  and c.v1 < distance_between( actor, npc ) then
				return true
		end	end,

		["on_actor_dist_ge_nvis"] = function ( c )	-- составляет пару с on_actor_dist_le_nvis, где >=
			if c.v1 < distance_between( actor, npc ) then
				return true
		end	end,

		["on_signal"] = function ( c )
			if st.signals and st.signals[c.v1] then
				return true
		end	end,

		-- FIXME: не дублировать тут имена, оставить один on_info,
		-- но добавлять несколько его экземпляров в список

		["on_info"] = function ( c )
			return true
		end,

		["on_timer"] = function ( c )
			if global_time_ms >= db.storage[npc:id()].activation_time + c.v1 then
				return true
		end	end,

		["on_game_timer"] = function ( c )	-- GAMETIME added by Stohe.
			if game_time_time:diffSec( db.storage[npc:id()].activation_game_time ) >= c.v1 then
				return true
		end	end,

		["on_actor_in_zone"] = function ( c )
			if utils.npc_in_zone(actor, db.zone_by_name[c.v1]) then
				return true
		end	end,
		["on_actor_not_in_zone"] = function ( c )
			if not utils.npc_in_zone( actor, db.zone_by_name[c.v1] ) then
				return true
		end	end,

		["on_npc_in_zone"] = function ( c )
			if utils.npc_in_zone( level.object_by_id( c.npc_id ), db.zone_by_name[c.v2] ) then
				return true
		end	end,

		["on_npc_not_in_zone"] = function ( c )
			if not utils.npc_in_zone( level.object_by_id( c.npc_id ), db.zone_by_name[c.v2] ) then
				return true
		end	end,

		["on_actor_inside"] = function ( c )
			if utils.npc_in_zone( actor, npc ) then
				return true
		end	end,

		["on_actor_outside"] = function ( c )
			if not utils.npc_in_zone( actor, npc ) then
				return true
		end	end
	}


	for n, c in pairs( l ) do
local p = profile_timer()
p:start()
for i = 1, 100 do
		if cond_name( c.name, "on_actor_dist_le" ) then
			if npc.alive and npc:alive() and npc:see( actor )
			  and c.v1 >= distance_between( actor, npc ) then
				sw = true
			end
		elseif cond_name( c.name, "on_actor_dist_le_nvis" ) then
			if c.v1 >= distance_between( actor, npc ) then
				sw = true
			end
		elseif cond_name( c.name, "on_actor_dist_ge") then	-- составляет пару с on_actor_dist_le, где >=
			if npc.alive and npc:alive() and npc:see( actor )
			  and c.v1 < distance_between( actor, npc ) then
				sw = true
			end
		elseif cond_name( c.name, "on_actor_dist_ge_nvis" ) then	-- составляет пару с on_actor_dist_le_nvis, где >=
			if c.v1 < distance_between( actor, npc ) then
				sw = true
			end
		elseif cond_name( c.name, "on_signal" ) then
			if st.signals and st.signals[c.v1] then
				sw = true
			end

		-- FIXME: не дублировать тут имена, оставить один on_info,
		-- но добавлять несколько его экземпляров в список

		elseif cond_name( c.name, "on_info" ) then
			sw = true
		elseif cond_name( c.name, "on_timer" ) then
			if global_time_ms >= db.storage[npc_id].activation_time + c.v1 then
				sw = true
			end
		elseif cond_name( c.name, "on_game_timer" ) then	-- GAMETIME added by Stohe.
			if game_time_time:diffSec( db.storage[npc_id].activation_game_time ) >= c.v1 then
				sw = true
			end
		elseif cond_name( c.name, "on_actor_in_zone" ) then
			if utils.npc_in_zone(actor, db.zone_by_name[c.v1]) then
				sw = true
			end
		elseif cond_name( c.name, "on_actor_not_in_zone" ) then
			if not utils.npc_in_zone( actor, db.zone_by_name[c.v1] ) then
				sw = true
			end
		elseif cond_name( c.name, "on_npc_in_zone" ) then
			if utils.npc_in_zone( level.object_by_id( c.npc_id ), db.zone_by_name[c.v2] ) then
				sw = true
			end
		elseif cond_name( c.name, "on_npc_not_in_zone" ) then
			if not utils.npc_in_zone( level.object_by_id( c.npc_id ), db.zone_by_name[c.v2] ) then
				sw = true
			end
		elseif cond_name( c.name, "on_actor_inside" ) then
			if utils.npc_in_zone( actor, npc ) then
				sw = true
			end
		elseif cond_name( c.name, "on_actor_outside" ) then
			if not utils.npc_in_zone( actor, npc ) then
				sw = true
			end
		else abort( "try_switch_to_another_section: invalid condition: [%s] (%s)",
			c.name, npc:name() )
		end
end
p:stop()
try_sw_time2 = try_sw_time2 + p:time()


local p = profile_timer()
p:start()
for i = 1, 100 do
		f = chk[string_match( c.name, "^([%D]+)" )]
		if f then
			sw1 = f( c )
		end
end
p:stop()
try_sw_time1 = try_sw_time1 + p:time()





		if sw ~= sw1 then
		log( "error", "%s ~= %s (%s, %s, %s)",
			tostring( sw ), tostring( sw1 ), tostring( n ), tostring( c.name ), to_str( npc ) )
		end

		if sw then
			sw = switch_to_section( npc, st, pick_section_from_condlist( actor, npc, c.condlist ) )
			if sw then _G.watchdog = false; return sw end
		end
		sw, sw1 = nil, nil
	end
	_G.watchdog = false
	return false


end

 

Сорри за неряшливый вид. Однако: sw1: 2691772.75 sw2: 7585235

 

Есть в этом нечто удивительное, правда ?

И, кстати, оно таки ЖРЕТ. Реально жрет. Пара десятков рестрикторов и десяток неписей - очень даже ой.

И, кстати, здесь можно этот самый аппетит еще поурезать вполне.

Изменено пользователем Dennis_Chikin
Ссылка на комментарий

Дабы меня не закидали овощами в соседней теме, поделюсь-ка я в очередной раз своим сырым кодом.

Просто что меня на эту мысль навело... функционал как бы востребованный до жути давным давно и настолько, что я нисколько не сомневаюсь в том что с десяток мододелов уже себе такое писали. Но никто на публику не выложил - начинающим взяться не за что, только самим писать.

Я про съемку координат речь веду, если что. В моей подписи как раз есть ссылка на тему где можно посмотреть видео про "Пушку мододела" - инструмент для снятия координат в игре. Координат для чего? Ну в данном варианте для путей работ в гулагах, а вообще-то для чего угодно.

Как оно работает: на стороне игры через всякие там интерфейсы задаем настройки, что мы хотим поставить, потом отлавливается выстрел, и в момент выстрела берутся координаты актора и с этими всеми настройками записываются эдаким пакетом информации в лог. И собственно все, на стороне игры работа инструмента закончилась.

Потом на стороне Windows, рядом с логами игры лежит одна программа которую я сам для себя написал. Она открывает файл логов, находит там все эти пакеты данных с координатами, оставленные скриптом, обрабатывает и создает "текст" который можно уже вставлять в файлы распакованного аллспавна и компилировать в игру с помощью acdc.

т.е. на стороне windows все что я делаю - открываю свою программу, тыкаю в ней кнопку, открываю созданный ею файл, нажимаю Ctrl+C, открываю файл распакованного спавна - Ctrl+V. запускаю батник компиляции спавна. все.

Т.е. все просто на самом деле. Но в открытом доступе я таких инструментов не видел, почему-то. Наверное у всех под свои нужды заточены. У меня тоже. Скриптовую часть на стороне игры - ее в любом случае каждый под себя напишет, тут у всех предпочтения разные, и не так давно доказывали что больше одного стейта у гулагов быть не должно... в общем, мелочи это, несущественные. Поэтому игровую-скриптовую часть выладывать не буду. Выложу код программы которая на стороне виндовса выковыривает данные из логов и собирает из них то что можно копипастить прямо в аллспавн. Писал я ее в Делфи.

Визуально программа простейшая, там одно текстовое поле, куда однажды надо ввести имя лог-файла (разные же бывают), и кнопка "конвертировать". собственно все.

Кому надо и интересно - можно взять и заточить под свои нужды.

 

{ *****************************************************
PathGenerator - программа для извлечения и обработки данных в лог-файле игры С.Т.А.Л.К.Е.Р. ТЧ.
сканирует лог-файл, находит пакеты данных, оставленные специальным скриптом.
читает эти данные и формирует на их основе, массивы данных готовые для вставки в файлы аллспавна
и последущей компиляции.

Автор:       Zander (skype zander700) г.Курск
Copyright:   Zander
Последнее обновление: 3 марта 2016 г.
***************************************************** }

unit PathGenerator;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ExtCtrls, StdCtrls;

type
  TPointXR = record
      lv: integer;
      lvn: integer;
      gv: integer;
      px: string;
      py: string;
      pz: string;
      dx: string;
      dy: string;
      dz: string;
      mode: integer;
      gulag_name: string;
      param_line: string;
      Res1: string;
      Res2: string;
  end;
  TForm1 = class(TForm)
    Button1: TButton;
    Label1: TLabel;
    Edit1: TEdit;
    Button2: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Edit1Change(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
  Paths: TStringList;
  Alife: TStringList;
  Scrpt: TStringList;
  NextCommand: integer;
  ArXr: array of TPointXR;
  gulag: integer;
  logfilename: string;
 

implementation

{$R *.dfm}



function StF(S: string): extended;
var
  S1: string;
  S2: string;
  L1: integer;
  L2: integer;
  P: integer;
  R: extended;
  a: integer;
  sl: TStringList;
begin
a:= 0;
P:= -1;
while (a < Length(S)) do
begin
    If (S[a] = '.') then begin
        P:= a;
        a:= Length(S);
    end;
a:= a + 1;
end;
S1:= Copy(S,1,P - 1);
S2:= Copy(S, P + 1, Length(S) - P);
L2:= Length(S2);
a:= 0;
L1:= 1;
while (a < L2) do begin
L1:= L1 * 10;
a:= a + 1;
end;
S2:= Copy(S2, 1, 4);
R:= Strtoint(S1) + (Strtoint(S2) / L1);
   sl:= TStringList.Create;
   sl.Append(S);
   sl.Append(S1);
   sl.Append(S2);
   sl.SaveToFile('proglog.txt');
   Result:= R;
end;



procedure TForm1.Button1Click(Sender: TObject); // конвертация
var
kamp_n: integer;
walk_n: integer;
guard_n: integer;
patrol_n: integer;
sniper_n: integer;
sleep_n: integer;
lead_n: integer;
stalker_n: integer;
monster_n: integer;
anomaly_n: integer;
rest_n: integer;
smart_n: integer;
item_n: integer;
a: integer;
b: integer;
c: integer;
points_label: string;
alife_number: integer;
Dist: extended;
begin
//SetDecimalSeparator('.');
    a:= 0;
    b:= 0;
    kamp_n:= 1;
    walk_n:= 1;
    guard_n:= 1;
    patrol_n:= 1;
    sniper_n:= 1;
    sleep_n:= 1;
    lead_n:= 1;
    stalker_n:= 1;
    monster_n:= 1;
    anomaly_n:= 1;
    rest_n:= 1;
    smart_n:= 1;
    item_n:= 1;
    alife_number:= 50000;
    while (a < Length(ArXr)) do begin
        Case (ArXr[a].mode) of
    0: begin
        Paths.Append('');
        Paths.Append('[' + ArXr[a].gulag_name + '_walker_' + inttostr(walk_n) + '_walk]');
      //  walk_n := walk_n + 1;
        Paths.Append('points = p0');
        Paths.Append('p0:name = name00' + ArXr[a].param_line);
        Paths.Append('p0:flags = 0x400');
        Paths.Append('p0:position = ' + ArXr[a].px + ',' + ArXr[a].py + ',' + ArXr[a].pz );
        Paths.Append('p0:game_vertex_id = ' + inttostr(ArXr[a].gv));
        Paths.Append('p0:level_vertex_id = ' + inttostr(ArXr[a].lv));  
        Paths.Append('');
        Paths.Append(ArXr[a].gulag_name + '_walker_' + inttostr(walk_n) + '_look]');
        walk_n := walk_n + 1;
        Paths.Append('points = p0');
        Paths.Append('p0:name = name00');
        Paths.Append('p0:flags = 0x400');
        Paths.Append('p0:position = ' + ArXr[a].dx + ',' + ArXr[a].dy + ',' + ArXr[a].dz );
        Paths.Append('p0:game_vertex_id = ' + inttostr(ArXr[a].gv));
        Paths.Append('p0:level_vertex_id = ' + inttostr(ArXr[a].lvn));         
    end;
    1: begin

        Paths.Append('');
        Paths.Append('[' + ArXr[a].gulag_name + '_kamp_' + inttostr(kamp_n) + ']');
        kamp_n := kamp_n + 1;
        Paths.Append('points = p0');
        Paths.Append('p0:name = name00' + ArXr[a].param_line);
        Paths.Append('p0:flags = 0x400');
        Paths.Append('p0:position = ' + ArXr[a].px + ',' + ArXr[a].py + ',' + ArXr[a].pz );
        Paths.Append('p0:game_vertex_id = ' + inttostr(ArXr[a].gv));
        Paths.Append('p0:level_vertex_id = ' + inttostr(ArXr[a].lv));
    end;
    2: begin
        Paths.Append('');
        Paths.Append('[' + ArXr[a].gulag_name + '_guard_' + inttostr(guard_n) + '_walk]');
      //  walk_n := walk_n + 1;
        Paths.Append('points = p0');
        Paths.Append('p0:name = name00' + ArXr[a].param_line);
        Paths.Append('p0:flags = 0x400');
        Paths.Append('p0:position = ' + ArXr[a].px + ',' + ArXr[a].py + ',' + ArXr[a].pz );
        Paths.Append('p0:game_vertex_id = ' + inttostr(ArXr[a].gv));
        Paths.Append('p0:level_vertex_id = ' + inttostr(ArXr[a].lv));  
        Paths.Append('');
        Paths.Append('[' + ArXr[a].gulag_name + '_guard_' + inttostr(guard_n) + '_look]');
        guard_n := guard_n + 1;
        Paths.Append('points = p0');
        Paths.Append('p0:name = name00');
        Paths.Append('p0:flags = 0x400');
        Paths.Append('p0:position = ' + ArXr[a].dx + ',' + ArXr[a].dy + ',' + ArXr[a].dz );
        Paths.Append('p0:game_vertex_id = ' + inttostr(ArXr[a].gv));
        Paths.Append('p0:level_vertex_id = ' + inttostr(ArXr[a].lvn));
    end;
    3: begin

        // установить число точек в патрульном пути
        b:= 1;
        while not (ArXr[a + b].mode = 4) do begin
        b:= b + 1;
        end;
        /// a + b - последняя точка
        Paths.Append('');
        Paths.Append('[' + ArXr[a].gulag_name + '_patrol_' + inttostr(patrol_n) + '_walk]');
        patrol_n:= patrol_n + 1;
        points_label:= 'p0';
        c:= 0;
        while (c <  do begin
        c:= c + 1;
        points_label:= points_label + ',p' + inttostr(c);
        end;
        Paths.Append('points = ' + points_label);
        c:= 0;
        while (c < (b + 1)) do begin
      if (c = 0) then begin
        Paths.Append('p0:name = name00' + ArXr[a].param_line);
      end else begin
        Paths.Append('p' + inttostr(c) + ':name = name0' + inttostr(c));
      end;
        Paths.Append('p' + inttostr(c) + ':flags = 0x400');
        Paths.Append('p' + inttostr(c) + ':position = ' + ArXr[a + c].px + ',' + ArXr[a + c].py + ',' + ArXr[a + c].pz );
        Paths.Append('p' + inttostr(c) + ':game_vertex_id = ' + inttostr(ArXr[a + c].gv));
        Paths.Append('p' + inttostr(c) + ':level_vertex_id = ' + inttostr(ArXr[a + c].lv));
        If (c =  then begin
        Paths.Append('p' + inttostr(c) + ':links = p0(1)');    // автозамыкание патрульного пути    
        end else begin
        Paths.Append('p' + inttostr(c) + ':links = p' + inttostr(c + 1) + '(1)');
        end;
        Paths.Append('');
        c:= c + 1;
        end;
        a:= a + b;
    end;
    4: begin
    // empty
    end;
    5: begin

        Paths.Append('');
        Paths.Append('[' + ArXr[a].gulag_name + '_sniper_' + inttostr(sniper_n) + '_walk]');
      //  walk_n := walk_n + 1;
        Paths.Append('points = p0');
        Paths.Append('p0:name = name00' + ArXr[a].param_line);
        Paths.Append('p0:flags = 0x400');
        Paths.Append('p0:position = ' + ArXr[a].px + ',' + ArXr[a].py + ',' + ArXr[a].pz );
        Paths.Append('p0:game_vertex_id = ' + inttostr(ArXr[a].gv));
        Paths.Append('p0:level_vertex_id = ' + inttostr(ArXr[a].lv));  
        Paths.Append('');
        Paths.Append('[' + ArXr[a].gulag_name + '_sniper_' + inttostr(sniper_n) + '_look]');
        sniper_n:= sniper_n + 1;
        Paths.Append('points = p0,p1,p2,p3');
        Paths.Append('p0:name = name00');
        Paths.Append('p0:flags = 0x400');
        Paths.Append('p0:position = ' + ArXr[a + 1].px + ',' + ArXr[a + 1].py + ',' + ArXr[a + 1].pz );
        Paths.Append('p0:game_vertex_id = ' + inttostr(ArXr[a + 1].gv));
        Paths.Append('p0:level_vertex_id = ' + inttostr(ArXr[a + 1].lv));
        Paths.Append('p0:links = p1(1)');
        Paths.Append('');
        Paths.Append('p1:name = name00');
        Paths.Append('p1:flags = 0x400');
        Paths.Append('p1:position = ' + ArXr[a + 2].px + ',' + ArXr[a + 2].py + ',' + ArXr[a + 2].pz );
        Paths.Append('p1:game_vertex_id = ' + inttostr(ArXr[a + 2].gv));
        Paths.Append('p1:level_vertex_id = ' + inttostr(ArXr[a + 2].lv));
        Paths.Append('p1:links = p2(1)');
        Paths.Append('');
        Paths.Append('p2:name = name00');
        Paths.Append('p2:flags = 0x400');
        Paths.Append('p2:position = ' + ArXr[a + 3].px + ',' + ArXr[a + 3].py + ',' + ArXr[a + 3].pz );
        Paths.Append('p2:game_vertex_id = ' + inttostr(ArXr[a + 3].gv));
        Paths.Append('p2:level_vertex_id = ' + inttostr(ArXr[a + 3].lv));
        Paths.Append('p2:links = p3(1)');
        Paths.Append('');    
        Paths.Append('p3:name = name00');
        Paths.Append('p3:flags = 0x400');
        Paths.Append('p3:position = ' + ArXr[a + 4].px + ',' + ArXr[a + 4].py + ',' + ArXr[a + 4].pz );
        Paths.Append('p3:game_vertex_id = ' + inttostr(ArXr[a + 4].gv));
        Paths.Append('p3:level_vertex_id = ' + inttostr(ArXr[a + 4].lv));
        Paths.Append('p3:links = p0(1)');    
        a:= a + 4;
    end;
    6: begin
                // установить число точек в патрульном пути
        b:= 1;
        while not (ArXr[a + b].mode = 7) do begin
        b:= b + 1;
        end;
        /// a + b - последняя точка
        Paths.Append('');
        Paths.Append('[' + ArXr[a].gulag_name + '_walker_' + inttostr(walk_n) + '_walk]');

        points_label:= 'p0';
        c:= 0;
        while (c <  do begin
        c:= c + 1;
        points_label:= points_label + ',p' + inttostr(c);
        end;
        Paths.Append('points = ' + points_label);
        c:= 0;
        while (c < (b + 1)) do begin
      if (c = 0) then begin
        Paths.Append('p0:name = name00' + ArXr[a].param_line);
      end else begin
        Paths.Append('p' + inttostr(c) + ':name = name0' + inttostr(c));
      end;
        Paths.Append('p' + inttostr(c) + ':flags = 0x400');
        Paths.Append('p' + inttostr(c) + ':position = ' + ArXr[a + c].px + ',' + ArXr[a + c].py + ',' + ArXr[a + c].pz );
        Paths.Append('p' + inttostr(c) + ':game_vertex_id = ' + inttostr(ArXr[a + c].gv));
        Paths.Append('p' + inttostr(c) + ':level_vertex_id = ' + inttostr(ArXr[a + c].lv));
        If (c =  then begin
        Paths.Append('p' + inttostr(c) + ':links = p0(1)');    // автозамыкание патрульного пути    
        end else begin
        Paths.Append('p' + inttostr(c) + ':links = p' + inttostr(c + 1) + '(1)');
        end;
        Paths.Append('');
        c:= c + 1;
        end;
        
        b:= 1;
        while not (ArXr[a + b].mode = 7) do begin
        b:= b + 1;
        end;
        /// a + b - последняя точка
        Paths.Append('');
        Paths.Append('[' + ArXr[a].gulag_name + '_walker_' + inttostr(walk_n) + '_look]');

        points_label:= 'p0';
        c:= 0;
        while (c <  do begin
        c:= c + 1;
        points_label:= points_label + ',p' + inttostr(c);
        end;
        Paths.Append('points = ' + points_label);
        c:= 0;
        while (c < (b + 1)) do begin
        Paths.Append('p' + inttostr(c) + ':name = name0' + inttostr(c));
        Paths.Append('p' + inttostr(c) + ':flags = 0x400');
        Paths.Append('p' + inttostr(c) + ':position = ' + ArXr[a + c].dx + ',' + ArXr[a + c].dy + ',' + ArXr[a + c].dz );
        Paths.Append('p' + inttostr(c) + ':game_vertex_id = ' + inttostr(ArXr[a + c].gv));
        Paths.Append('p' + inttostr(c) + ':level_vertex_id = ' + inttostr(ArXr[a + c].lvn));
        If (c =  then begin
        Paths.Append('p' + inttostr(c) + ':links = p0(1)');    // автозамыкание патрульного пути    
        end else begin
        Paths.Append('p' + inttostr(c) + ':links = p' + inttostr(c + 1) + '(1)');
        end;
        Paths.Append('');
        c:= c + 1;
        end;
    walk_n:= walk_n + 1;
        a:= a + b;
    end;
    7: begin
    // empty
    end;
    8: begin // rudiment
        gulag:= gulag + 1;
        kamp_n:= 1;
        walk_n:= 1;
        guard_n:= 1;
        patrol_n:= 1;
        sniper_n:= 1;
        sleep_n:= 1;
        lead_n:= 1;
    // sleep
    end;
    9: begin
        Paths.Append('');
        Paths.Append('[' + ArXr[a].gulag_name + '_sleep_' + inttostr(sleep_n) + ']');
        sleep_n := sleep_n + 1;
        Paths.Append('points = p0');
        Paths.Append('p0:name = name00' + ArXr[a].param_line);
        Paths.Append('p0:flags = 0x400');
        Paths.Append('p0:position = ' + ArXr[a].px + ',' + ArXr[a].py + ',' + ArXr[a].pz );
        Paths.Append('p0:game_vertex_id = ' + inttostr(ArXr[a].gv));
        Paths.Append('p0:level_vertex_id = ' + inttostr(ArXr[a].lv));
    end;
    10: begin
        Paths.Append('');
        Paths.Append('[' + ArXr[a].gulag_name + '_lead_' + inttostr(lead_n) + '_walk]');
      //  walk_n := walk_n + 1;
        Paths.Append('points = p0');
        Paths.Append('p0:name = name00' + ArXr[a].param_line);
        Paths.Append('p0:flags = 0x400');
        Paths.Append('p0:position = ' + ArXr[a].px + ',' + ArXr[a].py + ',' + ArXr[a].pz );
        Paths.Append('p0:game_vertex_id = ' + inttostr(ArXr[a].gv));
        Paths.Append('p0:level_vertex_id = ' + inttostr(ArXr[a].lv));  
        Paths.Append('');
        Paths.Append('[' + ArXr[a].gulag_name + '_lead_' + inttostr(lead_n) + '_look]');
        lead_n := lead_n + 1;
        Paths.Append('points = p0');
        Paths.Append('p0:name = name00');
        Paths.Append('p0:flags = 0x400');
        Paths.Append('p0:position = ' + ArXr[a].dx + ',' + ArXr[a].dy + ',' + ArXr[a].dz );
        Paths.Append('p0:game_vertex_id = ' + inttostr(ArXr[a].gv));
        Paths.Append('p0:level_vertex_id = ' + inttostr(ArXr[a].lvn));
    end;
    20: begin
    
            Alife.Append('');
            Alife.Append('[' + inttostr(alife_number) + ']');
            Alife.Append('; cse_abstract properties');
            Alife.Append('section_name = stalker');
            Alife.Append('name = uniqstalkername');// + inttostr(stalker_n));
            Alife.Append('position = ' + ArXr[a].px + ',' + ArXr[a].py + ',' + ArXr[a].pz);
            Alife.Append('direction = 0,0,0');
            Alife.Append('');
            Alife.Append('; cse_alife_trader_abstract properties');
            Alife.Append('money = 5000');
            Alife.Append('character_profile = uniqstalkerprofile');// + inttostr(stalker_n));
            Alife.Append('');
            Alife.Append('; cse_alife_object properties');
            Alife.Append('game_vertex_id = ' + inttostr(ArXr[a].gv));
            Alife.Append('distance = 0');
            Alife.Append('level_vertex_id = ' + inttostr(ArXr[a].lv));
            Alife.Append('object_flags = 0xffffffbf');
            Alife.Append('custom_data = <<END');
            Alife.Append('');
         //    Alife.Append('[logic]');
            //Alife.Append('cfg = uniqstalkerlogic' + inttostr(stalker_n) + '.ltx');
         //    Alife.Append('');
            Alife.Append('; cse');
            Alife.Append('[smart_terrains]');
            Alife.Append('none = true');
            Alife.Append('END');
            Alife.Append(';story_id = ' + inttostr(stalker_n));
            Alife.Append('');
            Alife.Append('; cse_visual properties');
            Alife.Append('visual_name = actors\neytral\stalker_neytral_balon_1');
            Alife.Append('');
            Alife.Append('; cse_alife_creature_abstract properties');
            Alife.Append('g_team = 0');
            Alife.Append('g_squad = 1');
            Alife.Append('g_group = 2');
            Alife.Append('health = 1');
            Alife.Append('dynamic_out_restrictions = ');
            Alife.Append('dynamic_in_restrictions = ');
            Alife.Append('');
            Alife.Append('upd:health = 1');
            Alife.Append('upd:timestamp = 0');
            Alife.Append('upd:creature_flags = 0');
            Alife.Append('upd:position = ' + ArXr[a].px + ',' + ArXr[a].py + ',' + ArXr[a].pz);
            Alife.Append('upd:o_model = 0');
            Alife.Append('upd:o_torso = 0.0280130300670862,0,0.999607563018799');
            Alife.Append('upd:g_team = 0');
            Alife.Append('upd:g_squad = 1');
            Alife.Append('upd:g_group = 2');
            Alife.Append('');
            Alife.Append('; cse_alife_monster_abstract properties');
            Alife.Append('');
            Alife.Append('upd:next_game_vertex_id = 65535');
            Alife.Append('upd:prev_game_vertex_id = 65535');
            Alife.Append('upd:distance_from_point = 0');
            Alife.Append('upd:distance_to_point = 0');
            Alife.Append('');
            Alife.Append('; cse_alife_human_abstract properties');
            Alife.Append('predicate5 = 1,2,2,1,2');
            Alife.Append('predicate4 = 0,1,1,1');
            Alife.Append('');
            Alife.Append('; cse_ph_skeleton properties');
            Alife.Append('');
            Alife.Append('upd:start_dialog = ');
            Alife.Append('');
            Alife.Append('; se_stalker properties');
            stalker_n:= stalker_n + 1;
            alife_number:= alife_number + 1;
    end;
    21: begin
    
            Alife.Append('');
            Alife.Append('[' + inttostr(alife_number) + ']');
            Alife.Append('; cse_abstract properties');
            Alife.Append('section_name = stalker');
            Alife.Append('name = uniqstalkername' + inttostr(stalker_n));
            Alife.Append('position = ' + ArXr[a].px + ',' + ArXr[a].py + ',' + ArXr[a].pz);
            Alife.Append('direction = 0,0,0');
            Alife.Append('');
            Alife.Append('; cse_alife_trader_abstract properties');
            Alife.Append('money = 5000');
            Alife.Append('character_profile = uniqstalkerprofile' + inttostr(stalker_n));
            Alife.Append('');
            Alife.Append('; cse_alife_object properties');
            Alife.Append('game_vertex_id = ' + inttostr(ArXr[a].gv));
            Alife.Append('distance = 0');
            Alife.Append('level_vertex_id = ' + inttostr(ArXr[a].lv));
            Alife.Append('object_flags = 0xffffffbf');
            Alife.Append('custom_data = <<END');
            Alife.Append('');
            Alife.Append('[logic]');
            Alife.Append('cfg = uniqstalkerlogic' + inttostr(stalker_n) + '.ltx');
            Alife.Append('');
            Alife.Append('; cse');
            Alife.Append('[smart_terrains]');
            Alife.Append('none = true');
            Alife.Append('END');
            Alife.Append(';story_id = ' + inttostr(stalker_n));
            Alife.Append('');
            Alife.Append('; cse_visual properties');
            Alife.Append('visual_name = actors\neytral\stalker_neytral_balon_1');
            Alife.Append('');
            Alife.Append('; cse_alife_creature_abstract properties');
            Alife.Append('g_team = 0');
            Alife.Append('g_squad = 1');
            Alife.Append('g_group = 2');
            Alife.Append('health = 1');
            Alife.Append('dynamic_out_restrictions = ');
            Alife.Append('dynamic_in_restrictions = ');
            Alife.Append('');
            Alife.Append('upd:health = 1');
            Alife.Append('upd:timestamp = 0');
            Alife.Append('upd:creature_flags = 0');
            Alife.Append('upd:position = ' + ArXr[a].px + ',' + ArXr[a].py + ',' + ArXr[a].pz);
            Alife.Append('upd:o_model = 0');
            Alife.Append('upd:o_torso = 0.0280130300670862,0,0.999607563018799');
            Alife.Append('upd:g_team = 0');
            Alife.Append('upd:g_squad = 1');
            Alife.Append('upd:g_group = 2');
            Alife.Append('');
            Alife.Append('; cse_alife_monster_abstract properties');
            Alife.Append('');
            Alife.Append('upd:next_game_vertex_id = 65535');
            Alife.Append('upd:prev_game_vertex_id = 65535');
            Alife.Append('upd:distance_from_point = 0');
            Alife.Append('upd:distance_to_point = 0');
            Alife.Append('');
            Alife.Append('; cse_alife_human_abstract properties');
            Alife.Append('predicate5 = 1,2,2,1,2');
            Alife.Append('predicate4 = 0,1,1,1');
            Alife.Append('');
            Alife.Append('; cse_ph_skeleton properties');
            Alife.Append('');
            Alife.Append('upd:start_dialog = ');
            Alife.Append('');
            Alife.Append('; se_stalker properties');
        Paths.Append('');
        Paths.Append('[uniqstalker' + inttostr(stalker_n) + '_walker_walk]');
      //  walk_n := walk_n + 1;
        Paths.Append('points = p0');
        Paths.Append('p0:name = name00');
        Paths.Append('p0:flags = 0x400');
        Paths.Append('p0:position = ' + ArXr[a].px + ',' + ArXr[a].py + ',' + ArXr[a].pz );
        Paths.Append('p0:game_vertex_id = ' + inttostr(ArXr[a].gv));
        Paths.Append('p0:level_vertex_id = ' + inttostr(ArXr[a].lv));  
        Paths.Append('');
        Paths.Append('[uniqstalker' + inttostr(stalker_n) + '_walker_look]');
       // walk_n := walk_n + 1;
        Paths.Append('points = p0');
        Paths.Append('p0:name = name00');
        Paths.Append('p0:flags = 0x400');
        Paths.Append('p0:position = ' + ArXr[a].dx + ',' + ArXr[a].dy + ',' + ArXr[a].dz );
        Paths.Append('p0:game_vertex_id = ' + inttostr(ArXr[a].gv));
        Paths.Append('p0:level_vertex_id = ' + inttostr(ArXr[a].lvn));
            stalker_n:= stalker_n + 1;    
            alife_number:= alife_number + 1;
    end;
    22: begin
            Alife.Append('');
            Alife.Append('[' + inttostr(alife_number) + ']');
            Alife.Append('; cse_abstract properties');
            Alife.Append('section_name = monster_section');
            Alife.Append('name = uniqmonstername' + inttostr(monster_n));
            Alife.Append('position = ' + ArXr[a].px + ',' + ArXr[a].py + ',' + ArXr[a].pz);
            Alife.Append('direction = 0,0,0');
            Alife.Append('');
            Alife.Append('; cse_alife_object properties');
            Alife.Append('game_vertex_id = ' + inttostr(ArXr[a].gv));
            Alife.Append('distance = 36.3999977111816');
            Alife.Append('level_vertex_id = ' + inttostr(ArXr[a].lv));
            Alife.Append('object_flags = 0xffffffbf');
            Alife.Append('');
            Alife.Append('; cse_visual properties');
            Alife.Append('visual_name = monsters\mutant_boar\mutant_boar_strong');
            Alife.Append('');
            Alife.Append('; cse_alife_creature_abstract properties');
            Alife.Append('g_team = 0');
            Alife.Append('g_squad = 0');
            Alife.Append('g_group = 0');
            Alife.Append('health = 1');
            Alife.Append('dynamic_out_restrictions = ');
            Alife.Append('dynamic_in_restrictions = ');
            Alife.Append('');
            Alife.Append('upd:health = 1');
            Alife.Append('upd:timestamp = 0');
            Alife.Append('upd:creature_flags = 0');
            Alife.Append('upd:position = ' + ArXr[a].px + ',' + ArXr[a].py + ',' + ArXr[a].pz);
            Alife.Append('upd:o_model = 0');
            Alife.Append('upd:o_torso = 0,0,0');
            Alife.Append('upd:g_team = 0');
            Alife.Append('upd:g_squad = 0');
            Alife.Append('upd:g_group = 0');
            Alife.Append('');
            Alife.Append('; cse_alife_monster_abstract properties');
            Alife.Append('');
            Alife.Append('upd:next_game_vertex_id = 65535');
            Alife.Append('upd:prev_game_vertex_id = 65535');
            Alife.Append('upd:distance_from_point = 0');
            Alife.Append('upd:distance_to_point = 0');
            Alife.Append('');
            Alife.Append('; cse_ph_skeleton properties');
            Alife.Append('');
            Alife.Append('; cse_alife_monster_base properties');
            Alife.Append('');
            Alife.Append('; se_monster properties');
            monster_n:= monster_n + 1;
            alife_number:= alife_number + 1;
    end;
    23: begin
            
            Alife.Append('');
            Alife.Append('[' + inttostr(alife_number) + ']');
            Alife.Append('; cse_abstract properties');
            Alife.Append('section_name = zone_mosquito_bald_weak');
            Alife.Append('name = uniqanomalyname' + inttostr(anomaly_n));
            Alife.Append('position = ' + ArXr[a].px + ',' + ArXr[a].py + ',' + ArXr[a].pz);
            Alife.Append('direction = -0.367405563592911,0.0629953369498253,0.17383885383606');
            Alife.Append('');
            Alife.Append('; cse_alife_object properties');
            Alife.Append('game_vertex_id = ' + inttostr(ArXr[a].gv));
            Alife.Append('distance = 36.3999977111816');
            Alife.Append('level_vertex_id = ' + inttostr(ArXr[a].lv));
            Alife.Append('object_flags = 0xffffff3e');
            Alife.Append('');
            Alife.Append('; cse_shape properties');
            Alife.Append('shapes = shape0');
            Alife.Append('shape0:type = sphere');
            Alife.Append('shape0:offset = 0,0,0');

          Dist:= sqrt((sqr(StF(ArXr[a].px) + StF(ArXr[a + 1].px))) +
          (sqr(StF(ArXr[a].py) + StF(ArXr[a + 1].py))) +
          (sqr(StF(ArXr[a].pz) + StF(ArXr[a + 1].pz))));

            Alife.Append('shape0:radius = ' + Floattostr(Dist));
            Alife.Append('');
            Alife.Append('; cse_alife_space_restrictor properties');
            Alife.Append('restrictor_type = 0');
            Alife.Append('');
            Alife.Append('; cse_alife_custom_zone properties');
            Alife.Append('max_power = 0');
            Alife.Append('');
            Alife.Append('; cse_alife_anomalous_zone properties');
            Alife.Append('offline_interactive_radius = 30');
            Alife.Append('artefact_spawn_count = 32');
            Alife.Append('');
            Alife.Append('; se_zone_anom properties');
            anomaly_n:= anomaly_n + 1;
            a:= a + 1; // вторая точка для определения радиуса шейпа
            alife_number:= alife_number + 1;
    end;
    24: begin
            Alife.Append('');
            Alife.Append('[' + inttostr(alife_number) + ']');
            Alife.Append('; cse_abstract properties');
            Alife.Append('section_name = space_restrictor');
            Alife.Append('name = uniq_restrictor' + inttostr(rest_n));
            Alife.Append('position = ' + ArXr[a].px + ',' + ArXr[a].py + ',' + ArXr[a].pz);
            Alife.Append('direction = 0,0,0');
            Alife.Append('');
            Alife.Append('; cse_alife_object properties');
            Alife.Append('game_vertex_id = ' + inttostr(ArXr[a].gv));
            Alife.Append('distance = 0');
            Alife.Append('level_vertex_id = ' + inttostr(ArXr[a].lv));
            Alife.Append('object_flags = 0xffffff3e');
            Alife.Append('custom_data = <<END');
            Alife.Append('[logic]');
            Alife.Append('active = sr_idle');
            Alife.Append('');
            Alife.Append('[sr_idle]');
            Alife.Append('on_actor_inside = %+esc_close_door%');
            Alife.Append('END');
            Alife.Append('');
            Alife.Append('; cse_shape properties');
            Alife.Append('shapes = shape0');
            Alife.Append('shape0:type = sphere');
            Alife.Append('shape0:offset = 0,0,0');

          Dist:= sqrt((sqr(StrtoFloat(ArXr[a].px) + StrtoFloat(ArXr[a + 1].px))) +
          (sqr(StrtoFloat(ArXr[a].py) + StrtoFloat(ArXr[a + 1].py))) +
          (sqr(StrtoFloat(ArXr[a].pz) + StrtoFloat(ArXr[a + 1].pz))));

            Alife.Append('shape0:radius = ' + Floattostr(Dist));
            Alife.Append('');
            Alife.Append('; cse_alife_space_restrictor properties ');
            Alife.Append('restrictor_type = 3');
            rest_n:= rest_n + 1;
            a:= a + 1;
            alife_number:= alife_number + 1;
    end;
    25: begin
            Alife.Append('');
            Alife.Append('[' + inttostr(alife_number) + ']');
            Alife.Append('; cse_abstract properties');
            Alife.Append('section_name = smart_terrain');
            Alife.Append('name = ' + ArXr[a].gulag_name);
            Alife.Append('position = ' + ArXr[a].px + ',' + ArXr[a].py + ',' + ArXr[a].pz);
            Alife.Append('direction = 0.062321275472641,0.00316426996141672,0.0140644172206521');
            Alife.Append('');
            Alife.Append('; cse_alife_object properties');
            Alife.Append('game_vertex_id = ' + inttostr(ArXr[a].gv));
            Alife.Append('distance = 4');
            Alife.Append('level_vertex_id = ' + inttostr(ArXr[a].lv));
            Alife.Append('object_flags = 0xffffffbe');
            Alife.Append('custom_data = <<END');
            Alife.Append('[smart_terrain]');
            Alife.Append('type = general_lager');
            Alife.Append('capacity = ' + inttostr(ArXr[a].lvn));
            Alife.Append('communities = ' + ArXr[a].param_line);
            Alife.Append('stay = medium');
            Alife.Append('END');
            Alife.Append('');
            Alife.Append('; cse_shape properties');
            Alife.Append('shapes = shape0');
            Alife.Append('shape0:type = sphere');
            Alife.Append('shape0:offset = 0,0,0');
            Alife.Append('shape0:radius = 1');
            Alife.Append('');
            Alife.Append('; cse_alife_space_restrictor properties');
            Alife.Append('restrictor_type = 3');
            Alife.Append('');
            Alife.Append('; se_smart_terrain properties');
            smart_n:= smart_n + 1;
            alife_number:= alife_number + 1;
    end;
    26: begin
            Alife.Append('');
            Alife.Append('[' + inttostr(alife_number) + ']');
            Alife.Append('; cse_abstract properties');
            Alife.Append('section_name = wpn_ak74u');
            Alife.Append('name = item' + inttostr(item_n));
            Alife.Append('position = ' + ArXr[a].px + ',' + ArXr[a].py + ',' + ArXr[a].pz);
            Alife.Append('direction = 0,-1.63260018825531,-1.58220040798187');
            Alife.Append('');
            Alife.Append('; cse_alife_object properties');
            Alife.Append('game_vertex_id = ' + inttostr(ArXr[a].gv));
            Alife.Append('distance = 0');
            Alife.Append('level_vertex_id = ' + inttostr(ArXr[a].lv));
            Alife.Append('object_flags = 0xffffff07');
            Alife.Append('custom_data = cond = 0.2');
            Alife.Append('');
            Alife.Append('; cse_visual properties');
            Alife.Append('visual_name = weapons\ak-74u\ak74u');
            Alife.Append('');
            Alife.Append('; cse_alife_item properties');
            Alife.Append('condition = 1');
            Alife.Append('');
            Alife.Append('upd:num_items = 0');
            Alife.Append('');
            Alife.Append('; cse_alife_item_weapon properties');
            Alife.Append('ammo_current = 90');
            Alife.Append('');
            Alife.Append('upd:condition = 1');
            Alife.Append('upd:weapon_flags = 0');
            Alife.Append('upd:ammo_elapsed = 0');
            Alife.Append('upd:addon_flags = 0');
            Alife.Append('upd:ammo_type = 0');
            Alife.Append('upd:weapon_state = 0');
            Alife.Append('upd:weapon_zoom = 0');
            Alife.Append('');
            Alife.Append('upd:current_fire_mode = 0');
                        item_n:= item_n + 1;
            alife_number:= alife_number + 1;
    end;
    27: begin
            Scrpt.Append(ArXr[a].px + ',' + ArXr[a].py + ',' + ArXr[a].pz + ',' + Inttostr(ArXr[a].lv) + ',' + Inttostr(ArXr[a].gv));
            
    end;
  28: begin
      Scrpt.Append('treasure' + inttostr(alife_number) + ' = ' + ArXr[a].px + ',' + ArXr[a].py + ',' + ArXr[a].pz + ',' + inttostr(ArXr[a].lv) + ',' + inttostr(ArXr[a].gv));
              alife_number:= alife_number + 1;
  end;
    end;
    a:= a + 1;
    end;
 // Form1.Memo1.Text:= Paths.Text;
    Paths.SavetoFile('Way_Generated.ltx');
    Alife.SavetoFile('Alife_Generated.ltx');
    Scrpt.SavetoFile('Script_Generated.ltx');
end;

procedure TForm1.Edit1Change(Sender: TObject);
begin
logfilename:= Form1.Edit1.Text;
end;

procedure TForm1.Button2Click(Sender: TObject); // прочитать лог-файл
var
DLog: TStringList;
a: integer;
s: string;
Command: string;
P: TPointXR;
begin
NextCommand:= 0;
gulag:= 1;
Paths:= TStringList.Create;
Alife:= TStringList.Create;
Scrpt:= TStringList.Create;
DLog:= TStringList.Create;
DLog.LoadFromFile(logfilename);
a:= 0;
  while (a < DLog.Count) do
  begin
      s:= DLog.Strings[a];
      Command:= s; //copy(s,12,Length(s) - 11);
      If (Command = 'Command_create_point_way') then begin
           s:= DLog.Strings[a + 1];
           Command:= s; //copy(s,12,Length(s) - 11);
           If (NextCommand = strtoint(Command)) then begin
           // BEGIN WORK
               //scan mode
               s:= DLog.Strings[a + 2];
               Command:= s; //copy(s,12,Length(s) - 11);
               P.mode:= strtoint(Command);
               //game vertex
               s:= DLog.Strings[a + 3];
               Command:= s; //copy(s,12,Length(s) - 11);
               P.gv:= strtoint(Command);
               //level vertex
               s:= DLog.Strings[a + 4];
               Command:= s; //copy(s,12,Length(s) - 11);
               P.lv:= strtoint(Command);
                     // level vertex look
               s:= DLog.Strings[a + 5];
               Command:= s; //copy(s,12,Length(s) - 11);
               P.lvn:= strtoint(Command);
               //position
               s:= DLog.Strings[a + 6];
               Command:= s; //copy(s,12,Length(s) - 11);
               P.px:= Command;
               s:= DLog.Strings[a + 7];
               Command:= s; //copy(s,12,Length(s) - 11);
               P.py:= Command;
               s:= DLog.Strings[a + 8];
               Command:= s; //copy(s,12,Length(s) - 11);
               P.pz:= Command;
               //direction
               s:= DLog.Strings[a + 9];
               Command:= s; //copy(s,12,Length(s) - 11);
               P.dx:= Command;
               s:= DLog.Strings[a + 10];
               Command:= s; //copy(s,12,Length(s) - 11);
               P.dy:= Command;
               s:= DLog.Strings[a + 11];
               Command:= s; //copy(s,12,Length(s) - 11);
               P.dz:= Command;
               // gulag_name
               s:= DLog.Strings[a + 12];
               Command:= s; //copy(s,12,Length(s) - 11);
               P.gulag_name:= Command;
               // param_line
               s:= DLog.Strings[a + 13];
               Command:= s; //copy(s,12,Length(s) - 11);
               P.param_line:= Command;
               // reserved 1 param_line
               s:= DLog.Strings[a + 14];
               Command:= s; //copy(s,12,Length(s) - 11);
               P.Res1:= Command;
               // reserved 2 param_line
               s:= DLog.Strings[a + 15];
               Command:= s; //copy(s,12,Length(s) - 11);
               P.Res2:= Command;

               SetLength(ArXr,Length(ArXr) + 1);
               ArXr[NextCommand]:= P;
               NextCommand:= NextCommand + 1;
           end;
      end;
      a:= a + 1;
  end;
  Form1.Label1.Caption:= 'Точек найдено: ' + inttostr(Length(ArXr));
  if (Length(ArXr) > 0) then
  begin
      Form1.Button1.Enabled:= true;
  end;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
    logfilename:= 'xray_user.log';
end;

end.

 

 

  • Нравится 2

Мод, где не бывает одинаковых путей - Судьба Зоны. (Лучшее, что у меня получилось на X-Ray) На базе модифицированного движка OGSR Engine.

Бывший мододел на X-Ray / Начинающий игродел на Unreal Engine. Программист.

AMD Ryzen 9 7950X (16 ядер, 5.7ГГц); RTX 3080; 128 ГБ DDR5; Arctic Liquid Freezer II-420; 3 ТБ SSD PCIe 4.0; 4ТБ HDD.

Ссылка на комментарий

@Zander_driver, гайд по выкладыванию чего-либо :)

Ведь не сложно же было выложить еще и dpr и dfm, чтобы дельфевый проект можно было собрать без приседаний.

И скрипты/конфиги к нему приложить, чтобы не приходилось гадать, что же нужно писать в лог, чтобы программа работала.

 

В общем возвращаясь к гайду по ссылке - "надо так давать, чтобы можно было взять".

  • Нравится 1
  • Согласен 1
Ссылка на комментарий

 

 

дельфевый проект

Я же говорил что там минимум :)

program PathGeneratorProject1;

uses
  Forms,
  PathGenerator in 'PathGenerator.pas' {Form1};

{$R *.res}

begin
  Application.Initialize;
  Application.CreateForm(TForm1, Form1);
  Application.Run;
end.

 

object Form1: TForm1
  Left = 200
  Top = 126
  Width = 275
  Height = 143
  Caption = #1043#1077#1085#1077#1088#1072#1090#1086#1088' '#1087#1091#1090#1077#1081' '#1089#1090#1072#1083#1082#1077#1088#1072
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'MS Sans Serif'
  Font.Style = []
  OldCreateOrder = False
  OnCreate = FormCreate
  PixelsPerInch = 96
  TextHeight = 13
  object Label1: TLabel
    Left = 8
    Top = 8
    Width = 3
    Height = 13
  end
  object Button1: TButton
    Left = 8
    Top = 72
    Width = 249
    Height = 25
    Caption = 'Save'
    Enabled = False
    TabOrder = 0
    OnClick = Button1Click
  end
  object Edit1: TEdit
    Left = 8
    Top = 32
    Width = 169
    Height = 21
    TabOrder = 1
    Text = 'xray_user.log'
    OnChange = Edit1Change
  end
  object Button2: TButton
    Left = 184
    Top = 32
    Width = 75
    Height = 25
    Caption = 'Open'
    TabOrder = 2
    OnClick = Button2Click
  end
end

 

    log("Command_create_point_way") --- ключевое слово, по которому программа опознает что начался пакет данных предназначенный для нее
    log(tostring(point_number))     --- номер пакета - нужен чтобы программа могла контролировать, что ничего не перепуталось
    point_number = point_number + 1 --- прибавляем при каждой записи
    log("8")                        --- число - номер исполняемой команды. указание что делать программе
    log(tostring(gv))               --- геймвертекс актора
    log(tostring(lv))               --- левел-вертекс актора
    log(tostring(lvn))              --- левел-вертекс куда смотрит актор
    log(tostring(pos.x))            --- позиция актора
    log(tostring(pos.y))
    log(tostring(pos.z))
    log(tostring(pos2.x))           --- позиция куда смотрит актор
    log(tostring(pos2.y))
    log(tostring(pos2.z))           --- фрагменты вектора передаются и читаются на той стороне как строки. если где-то понадобится, это можно использовать.
    log(R_param_1)                  --- дополнительные строковые параметры.
    log(R_param_2)                  --- для разных команд, их назначение различно.

 

 

  • Нравится 1

Мод, где не бывает одинаковых путей - Судьба Зоны. (Лучшее, что у меня получилось на X-Ray) На базе модифицированного движка OGSR Engine.

Бывший мододел на X-Ray / Начинающий игродел на Unreal Engine. Программист.

AMD Ryzen 9 7950X (16 ядер, 5.7ГГц); RTX 3080; 128 ГБ DDR5; Arctic Liquid Freezer II-420; 3 ТБ SSD PCIe 4.0; 4ТБ HDD.

Ссылка на комментарий

:offtopic:Zander_driver,

очень нужная и полезная работа. К сожалению, ввиду все возрастающей производительности домашних компьютеров, оптимизации не уделяется должного внимания: "ракета" все переварит.

Однако, у подавляющего большинства людей компьютер далеко не "ракета" и некоторые моды идут с заметными фризами из-за кривых /не оптимизированных скриптов. А ведь, чем менее требователен мод к железу- тем больше людей будут в него играть. А чем больше людей играет в мод, тем приятнее автору: старался ведь не только для себя.

Такую полезную штуку все же лучше в "Сборочный цех".

Изменено пользователем aromatizer
  • Нравится 1

Отношения между людьми- главная ценность в человеческом обществе.
Любая полученная информация- это только повод для размышлений, а не побуждение к действию.
Это должен знать каждый: уроки боевой подготовки Дяди Саши https://yadi.sk/d/60Ec2B06goLAE
Накопано и накнопано:https://yadi.sk/d/mzVY5jQEspwpt

Ссылка на комментарий

 

 

очень нужная и полезная работа.

Я тоже так считаю.

 

 

 

... "ракета" все переварит. Однако, у подавляющего большинства людей компьютер далеко не "ракета" ...

Ну я видел несколько жалоб от людей с очень хорошими и дорогими компьютерами на фризы/лаги именно в этих же ситуациях в различных модификациях. Так что предпологаю, что и "ракета" - не поможет. А вот Zander_driver - очень помог этой своей работой.

 

 

 

Такую полезную штуку все же лучше в "Сборочный цех".

И я тоже так считаю, а то тут в Прозекторской на неё не многие наткнуться, как мне кажется.

Перенести свои изменения в оптимизированный файл - совсем не трудно, а польза то - большая. Хорошо бы, чтоб все модмейкеры использовали эту наработку; особенно, если в их моде есть толпы похожих/идентичных нпс, находящихся рядом в одном гулаге и т.п..

Ссылка на комментарий

А я все же думаю пока оставить это дело тут. В "Сборочном цехе" есть свои правила, которые я сам же писал, и нарушать их не намерен. А эта работа в те правила не вписывается.

  • Полезно 1

Мод, где не бывает одинаковых путей - Судьба Зоны. (Лучшее, что у меня получилось на X-Ray) На базе модифицированного движка OGSR Engine.

Бывший мододел на X-Ray / Начинающий игродел на Unreal Engine. Программист.

AMD Ryzen 9 7950X (16 ядер, 5.7ГГц); RTX 3080; 128 ГБ DDR5; Arctic Liquid Freezer II-420; 3 ТБ SSD PCIe 4.0; 4ТБ HDD.

Ссылка на комментарий

Тогда, пожалуйста, добавь эту революционную наработку себе в подпись. Я уже адаптировал ее к ТТ2: полет нормальный.

Изменено пользователем aromatizer
  • Спасибо 1
  • Нравится 1

Отношения между людьми- главная ценность в человеческом обществе.
Любая полученная информация- это только повод для размышлений, а не побуждение к действию.
Это должен знать каждый: уроки боевой подготовки Дяди Саши https://yadi.sk/d/60Ec2B06goLAE
Накопано и накнопано:https://yadi.sk/d/mzVY5jQEspwpt

Ссылка на комментарий

Вы мне так подпись взорвете :( она же не резиновая.

Мод, где не бывает одинаковых путей - Судьба Зоны. (Лучшее, что у меня получилось на X-Ray) На базе модифицированного движка OGSR Engine.

Бывший мододел на X-Ray / Начинающий игродел на Unreal Engine. Программист.

AMD Ryzen 9 7950X (16 ядер, 5.7ГГц); RTX 3080; 128 ГБ DDR5; Arctic Liquid Freezer II-420; 3 ТБ SSD PCIe 4.0; 4ТБ HDD.

Ссылка на комментарий

Создайте аккаунт или авторизуйтесь, чтобы оставить комментарий

Комментарии могут оставлять только зарегистрированные пользователи

Создать аккаунт

Зарегистрировать новый аккаунт в нашем сообществе. Это несложно!

Зарегистрировать новый аккаунт

Войти

Есть аккаунт? Войти.

Войти
  • Недавно просматривали   0 пользователей

    Ни один зарегистрированный пользователь не просматривает эту страницу.

AMK-Team.ru

×
×
  • Создать...