Jump to content

Recommended Posts

Dennis_Chikin    3,598

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

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

Edited by Dennis_Chikin

Share this post


Link to post
Share on other sites
Dennis_Chikin    3,598

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

 

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

 

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

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

 

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

Edited by Dennis_Chikin

Share this post


Link to post
Share on other sites
 Murarius    6,871

 

 

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

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

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

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

Share this post


Link to post
Share on other sites
Dennis_Chikin    3,598

Вроде, 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 раза сокращается количество строк, и сами строки упрощаются (от них в основном только секции логики и нужны)

 

 

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

Edited by Dennis_Chikin

Share this post


Link to post
Share on other sites
сейчас-то что мешает стейты внутрь логики засунуть (пусть даже по вашему человекопонятному)? кондлист доступен абсолютно для всего, для чего не доступен - сделать доступным. профит, не?

Так я об этом и пишу. Если специально не создавать на каждый чих новый 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 подобное не прокатит.

Edited by Полтергейст

Share this post


Link to post
Share on other sites
Dennis_Chikin    3,598

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

 

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

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

 

Избавились.

 

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

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

 

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

 

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

 

 

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

Share this post


Link to post
Share on other sites

 

 

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

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

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

 

 

 

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

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

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

 

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

 

 

 

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

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

 

 

 

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

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

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

Share this post


Link to post
Share on other sites
dsh    2,472

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

 

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

Share this post


Link to post
Share on other sites
Dennis_Chikin    3,598

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

 

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

 

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

Share this post


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

 

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

Share this post


Link to post
Share on other sites
Dennis_Chikin    3,598

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

Edited by Dennis_Chikin

Share this post


Link to post
Share on other sites
Dennis_Chikin    3,598

Продолжаем разговор про 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

 

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

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

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

Edited by Dennis_Chikin

Share this post


Link to post
Share on other sites
Zander_driver    3,535

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

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

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

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

Потом на стороне 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.

 

 

  • Like 2

Тестеры о "Судьбе Зоны": Все это бегает, орет, гоняется друг за другом, попадает в аномалии. Я не знаю что там можно делать и в какой экипировке туда можно идти...

Не умею играть в "сталкер" как все. Делаю по своему, как умею.

Share this post


Link to post
Share on other sites
abramcumner    860

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

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

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

 

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

  • Like 1
  • Согласен 1

Share this post


Link to post
Share on other sites
Zander_driver    3,535

 

 

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

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

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)                  --- для разных команд, их назначение различно.

 

 

  • Like 1

Тестеры о "Судьбе Зоны": Все это бегает, орет, гоняется друг за другом, попадает в аномалии. Я не знаю что там можно делать и в какой экипировке туда можно идти...

Не умею играть в "сталкер" как все. Делаю по своему, как умею.

Share this post


Link to post
Share on other sites
aromatizer    2,202

:offtopic:Zander_driver,

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

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

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

Edited by aromatizer
  • Like 1

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

Share this post


Link to post
Share on other sites
ddww    67

 

 

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

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

 

 

 

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

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

 

 

 

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

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

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

Share this post


Link to post
Share on other sites
Zander_driver    3,535

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


Тестеры о "Судьбе Зоны": Все это бегает, орет, гоняется друг за другом, попадает в аномалии. Я не знаю что там можно делать и в какой экипировке туда можно идти...

Не умею играть в "сталкер" как все. Делаю по своему, как умею.

Share this post


Link to post
Share on other sites
aromatizer    2,202

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

Edited by aromatizer
  • Thanks 1
  • Like 1

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

Share this post


Link to post
Share on other sites
Zander_driver    3,535

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


Тестеры о "Судьбе Зоны": Все это бегает, орет, гоняется друг за другом, попадает в аномалии. Я не знаю что там можно делать и в какой экипировке туда можно идти...

Не умею играть в "сталкер" как все. Делаю по своему, как умею.

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.


  • Recently Browsing   0 members

    No registered users viewing this page.

AMK-Team.ru

×
×
  • Create New...