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

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

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

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

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

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

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

 

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

 

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

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

 

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

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

 

 

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

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

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

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


Подарки

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

    Вроде, 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

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