Dennis_Chikin 3 663 Опубликовано 21 Августа 2014 (изменено) Гм, критикуя - предлагай, но мне кажется, что как-то оно все задом наперед. Причем, я бы сказал, традиционно задом наперед, что регулярно вводит всех в заблуждение. То, что обычно называют "логикой" - это описание поведения различных игровых объектов (как видимых игроку, так и скрытых от него) в зависимости от каких-либо условий, созданное в некотором якобы человеко-читаемом формате. Храниться это описание может по большому счету совершенно где угодно, или даже содаваться/изменяться динамически. Пример: файл gulag_dark_walley.script (недавно разбирался): gulags.val_escort.job = function(sj, gname, type, squad, groups) -- игнорирование local ltx = "[meet@ignore_abuse]\n" .. и т.д. - динамическое создание логики персонажей для смарта val_escort ... gulags.val_escort.ltx = ltx function load_ltx(gname, type) local g = gulags[type] if g then return g.ltx end -- возвращает сформированный текст. return nil -- "магическая" командаend Это можно переписать например так: ["val_escort"] = { -- Пуля, Любер, бандиты { section = "logic@val_escort_nap1", -- напарник с которым спасаем пленного ... и т.д., где [logic@val_escort_nap1] и прочие определены в файле config\misc\gulag_dark_walley.ltx, который подключен через system.ltx. продолжение следует. Изменено 21 Августа 2014 пользователем Dennis_Chikin 1 Солянка обезжиренная, диетическая, полезные советы по "солянке", текущий тестовый патч Поделиться этим сообщением Ссылка на сообщение
Dennis_Chikin 3 663 Опубликовано 21 Августа 2014 Просто мне кажется, что предложенный формат скорее с толку сбивает, чем разъясняет. Введение надо какое-то более другое. Ну, в общем, я так понимаю, что для того и тема, что если у кого-то есть идеи лучше - напишет. Если нет - придется, видимо, гипертекстом оформлять. 1 Солянка обезжиренная, диетическая, полезные советы по "солянке", текущий тестовый патч Поделиться этим сообщением Ссылка на сообщение
Dennis_Chikin 3 663 Опубликовано 2 Октября 2015 function heli_start_flame( heli ) heli:get_helicopter():StartFlame() db.storage[heli:id()].flame_start_snd:play( heli ) news_heli( heli, "flame" ) end Какая строчка в этой функции непонятна ? Солянка обезжиренная, диетическая, полезные советы по "солянке", текущий тестовый патч Поделиться этим сообщением Ссылка на сообщение
Dennis_Chikin 3 663 Опубликовано 26 Октября 2015 (изменено) Так, поболтали, и забыли... Ну, на счет "мне надо/мне уже не надо" - это как бы на совести автора пусть будет. Просто как ведем разговор - вот так вот и ответы получаем. Функция - в общем, делает одно и то же: включает "горение" вертолета. Что касается того, как вызвать ее из логики, то таки да, для того, чтобы что-то "делать из логики" - надо понимать, как оно работает. Работает же, в общем и целом, вся логика примерно вот как я начал писать во втором посте темы, но не закончил (и не знаю, описано ли это в гугльдоке из первого): Это - некий как бы человекочитаемый язык. Описывающий условия, при которых, внезапно, таки да - вызываются какие-то функции. Часть этих функций УЖЕ замаскировано вот этими всеми черточками, плюсиками, и закорючками, а что не замаскировано - надо указывать явно. Отвечает за разбор этих черточек и закорючек файл xr_logic.script, и если кому-то надо знать, какие ВООБЩЕ есть возможности, как ТОЧНО работает та или иная закорючка, и как добавить что-то свое - вам таки придется разбирать вот этот самый скрипт. А он несет немало открытий весьма чудных, да... Впрочем, основное написано там в самом начале, в комментариях. Из них нам особо интересны function parse_condlist(npc, section, field, src), function pick_section_from_condlist(actor, npc, condlist) и function try_switch_to_another_section(npc, st, actor). Ну и, естественно, комментарии к ним. Первая, parse_condlist - разбирает эти ваши черточки и кракозябры в таблицу условий, Вторая - пытается их проверить. Обычно, вот в каждой схеме (каковой соответствует своя секция в файле логики, и свой собственный скрипт в скриптах), эта функция вызывается с тем или иным намерением, и, соответственно, в список проверок вы можете добавить что-то свое. Или добавить какую-нибудь новую кракозябру и ее обработку вот в эти проверки. То есть, если в логике присутствует кракрозябра вида "=что_то_там" или "!вот_такая_фигня", из файла xr_conditions будет вызвано ваше "что_то_там" или "вот_такая_фигня". Если, конечно, оно есть. Если нет - получите зависание, и, в конце-концов, вылет с любимым всеми сообщением "переполнение стека". Что показательно - не зависимо от количества памяти. Если все-таки есть, в туда будет передан актор, ваш объект, и параметры из прочих черточек и закорючек. Таким образом, если Вам надо что-то принципиально новое, вы должны это новое вписать в xr_conditions.script, или поправить xr_logic.pick_section_from_condlist(), чтобы оно вызывало вашу фигню из более другого места. Да, это вот та самая функция, которая занимается проверкой условий по таблице, созданной parse_condlist(), и тоже вызывается во всех схемах. Ну вот собственно как разобрали - так и начинает проверяться. Если, конечно, вы там уже не поправили все на нечто странное. Оно же, сразу же, содержит возможность ВЫПОЛНИТЬ ВАШУ ФУНКЦИЮ, если проверяемое условие выполнилось. И таки тоже передает туда актора, объект и параметры. То есть, вам осталось только вписать в строку условий нужное, или создать это нужное, и вписать. Ага, например, создать my_kewl_script.script, добавить в туда function podzhetch_vertalot( dummy, obj ) bind_heli.heli_start_flame( obj ) end, вписать в вашу логику что-то типа %=my_kewl_script.podzhetch_vertalot%, и наслаждаться результатом. Наконец, try_switch_to_another_section() - это то, что, опять же, в каждой схеме постоянно проверяет: а не пора ли переключиться на какую-то более другую секцию логики. При этом оно дергает, соответственно, за pick_section_from_condlist, а про нее вы уже все знаете. Но можно, опять же, добавить свои условия типа проверки хита вертолета с одновременным поджиганием. Вот как-то так. p.s. флуд почистил. P.P.S. Но вообще, применительно к вертолету, проще поправить bind_heli.script, чтобы он читал из активной секции хит, с которого надо начинать гореть. И хотя этот параметр будет в файле логики, к собственно рассматриваемому псевдоязыку это не имеет СОВЕРШЕННО НИ КАКОГО отношения. Так же, как, например, параметры danger или ранения, или даже путей, читаемых для неписей из назначенного им ltx. Кстати, даже и не помню, что я правил в ранениях и danger, чтобы оно это читало, что было в "стандартном ТЧ", а где - было, но с ошибками. Но смысл в любом случае примерно такой. Просто записали что-то в конфиг, который потом кому-то как-то скормили. Изменено 26 Октября 2015 пользователем Dennis_Chikin 1 1 Солянка обезжиренная, диетическая, полезные советы по "солянке", текущий тестовый патч Поделиться этим сообщением Ссылка на сообщение
Dennis_Chikin 3 663 Опубликовано 26 Октября 2015 п2 и далее - не верно. Все, что принято называть "логикой" - это реализовано исключительно на скриптах. Измените скрипты - изменится и все, что вы делаете в этой "логике". Это - просто еще один язык поверх другого языка. Который используется в текущем виде просто по принципу "здесь так принято". Очень странный, ограниченный и неудобный язык. Солянка обезжиренная, диетическая, полезные советы по "солянке", текущий тестовый патч Поделиться этим сообщением Ссылка на сообщение
Dennis_Chikin 3 663 Опубликовано 26 Октября 2015 (изменено) В классическом сталкере, в состоянии боя логика не работает вообще. То есть, она работает как раз ровно до боя и после боя. Есть скрипты, которые перехватывают управление неписем до момента проверки "в бою или нет", и заставляют делать что-то свое. Ну, вот, например, я переделал скрипт, отслеживающий ранения, и добавил туда, что если до лежачего состояния еще рано, то с какого-то значения непись бежит в укрытие, и там ест аптечку (если есть). Но это, опять же, "не логика". Еще есть, например, watcher_act.script, например, знаменитый тем, что если на дальнем конце локации бросить какой-то предмет, то непись, наплевав на бой, аномалии, все остальное, полезет за этим предметом. Опять же, отключается проверка состояния "в бою". Ну а небоевое поведение непися определяется выбранными через скрипт, который взял на себя управление, анимацией, state и командами "идти к вертексу n". Изменено 28 Октября 2015 пользователем Dennis_Chikin Солянка обезжиренная, диетическая, полезные советы по "солянке", текущий тестовый патч Поделиться этим сообщением Ссылка на сообщение
Dennis_Chikin 3 663 Опубликовано 28 Октября 2015 (изменено) Обход аномалий зависит от правильно выставленного параметра effective_radius в кофигах аномалий. Опять же, если кто-то не перехватит проверку ( world_property( stalker_ids.property_enemy, false ) ), и не пошлет непися прямо в аномалию (опять же пресловутый watcher_act.script), например. Для мобов - mob:add_restrictions( "", s ), где s - строка с перечислением имен рестрикторов, в которые лезть нельзя. Изменено 28 Октября 2015 пользователем Dennis_Chikin Солянка обезжиренная, диетическая, полезные советы по "солянке", текущий тестовый патч Поделиться этим сообщением Ссылка на сообщение
Dennis_Chikin 3 663 Опубликовано 22 Декабря 2015 (изменено) Забавно однако наблюдать, как "слишком умный" скрипт ведет к умножению бреда в конфигах. Как бы, изначально синтаксис выбора секций должен выглядеть как active = схема@уникальный_модификатор1 [схема@уникальный_модификатор1] on_чегопопало = ... схема@уникальный_модификатор2 и т.д. Но поскольку для названия схем добавили фильтрацию цифр, в количестве имеем [walker3@1] [walker4@1] и т.д. Просто праздник какой-то... А вот новую схему типа walker1 - фиг добавишь. Да здравствуют священные и неприкосновенные конфиги, аффтыри которых имеют право прописать туда любой бред, и потом кто-то должен угадать, что они имели в виду ! Даже если это будет подряд line1 = вот так а еще мы добавим чего попало как нам в голову взбредет line1 = "№%:/"\%?;.$@#$%^&*;%Ё!!\0%&^&;%№:?!?9[=-+~$^{ line1 = ;и вот только попробуйте это не прочитать line1 line1, li ne1 li\0ne1 ~= $_\\\\]% и т.д. А также пачка переходов на секции и строки вообще несуществующие. Изменено 22 Декабря 2015 пользователем Dennis_Chikin Солянка обезжиренная, диетическая, полезные советы по "солянке", текущий тестовый патч Поделиться этим сообщением Ссылка на сообщение
Dennis_Chikin 3 663 Опубликовано 28 Декабря 2015 Сорри за даблпостинг, но мне таки интересно. Люди, скажите, как вы добиваетесь, чтоб у вас работали конструкции вида: [logic] active = sr_idle [sr_idle] on_npc_in_zone = 19029 |soldier_v_piyanux_restrictor| sr_idle@time single = true Солянка обезжиренная, диетическая, полезные советы по "солянке", текущий тестовый патч Поделиться этим сообщением Ссылка на сообщение
Dennis_Chikin 3 663 Опубликовано 29 Декабря 2015 (изменено) 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 switched = switch_to_section(npc, st, pick_section_from_condlist(actor, npc, c.condlist)) 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 switched = switch_to_section(npc, st, pick_section_from_condlist(actor, npc, c.condlist)) endА, в смысле, function cfg_get_npc_and_zone() ?Которая берет по sid, и перекладывает туда id ? Орригинально... Изменено 29 Декабря 2015 пользователем Dennis_Chikin Солянка обезжиренная, диетическая, полезные советы по "солянке", текущий тестовый патч Поделиться этим сообщением Ссылка на сообщение
Dennis_Chikin 3 663 Опубликовано 20 Июня 2016 (изменено) На дворе шел 2016 год. А мододелы так и вызывают из логики функции типа my_function1() local obj = alife():object( "my_object1" ) local actor = db.actor ... end ... my_function100500() local obj = alife():object( "my_object100500" ) особенно замечательно, когда используется не имя, а спавн из скрипта с переписыванием sid, или, еще лучше, сохранение id созданного объекта в pstor к актору. Так вот, кому лень смотреть xr_logic.scritp, просто запомните: вызываемая в 99% скриптов, работающих с логикой xr_logic.try_switch_to_another_section( self.object, self.st, db.actor ) - передает туда, как видно из аргументов, актора, сторейж и свой объект. Далее вызывается pick_section_from_condlist( actor, npc, c.condlist ) или что-то подобное, где actor и npc - внезапно, именно то, что было передано в качестве актора и объекта. И когда ваше условие выполняется, то в вашу =my_script.my_function100500() передаются они же. Так что достаточно написать my_function( v1, v2 ), и в v2 у вас волшебным образом будет искомый объект. Игровой или серверный - зависит от того, откуда вызывалось, но в любом случае достаточно local obj = alife():object( v2:name() ) Если, конечно, у вас в олспавне еще и имена не дублированы, ну а если уж понаплодили дубликатов - вылетов будет в количестве и без этого. Из засад же присутствует то, что когда вы вызываете pick_section_from_condlist() откуда-нибудь из se_zone.script и прочих se_что-попало, то ни какого db.actor во время загрузке этих ваших зон и прочих смартерейнов еще не существует. Так что ни выдавать атору инфо в этой "логике", ни рассчитывать, что кто-то где-то его получит - право, не стоит. Подумайте - не перенести ли такие действия в более другое место. Да, а вообще, в xr_logic заглядывать время от времени полезно. Ну и в смысле читаемости, возможно, кому-то поможет вот такой вариант: https://dl.dropboxusercontent.com/u/27871782/xr_logic.script Изменено 20 Июня 2016 пользователем Dennis_Chikin Солянка обезжиренная, диетическая, полезные советы по "солянке", текущий тестовый патч Поделиться этим сообщением Ссылка на сообщение
Dennis_Chikin 3 663 Опубликовано 23 Июня 2016 Если очень ты не хочешь слушать вредные советы, то тогда тебе не надо 50 сравнений строк делать в каждом из апдейтов... Не знаю, кто и когда успел родить сей шедевр, но вот нашел совершенно замечательное: if self.st.active_section == "sr_idle@nil" then ... elseif self.st.active_section ~= nil then ... Ага, это те самые рестрикторы, апдейт которых вызывается из каждого апдейта актора. А их в среднем на локации где-то вот с полсотни и есть. Так вот, в каждой схеме, в свою очередь, имеется апдейт. Ну или эвалуатор. Или еще какое чудо. В котором, обычно, вызывается xr_logic.try_switch_to_another_section() Так вот, если мы переключаемся на любую другую секцию, или даже схему (все равно секция будет другая), то оно вернет true. И тогда спокойно можно проверить, на какую именно, и сделать, что хотим. Так же, как и в предыдущем примере, но не на каждом апдейте, а именно на переключении. Только сторейж надо брать не схемы, а объекта. 1 Солянка обезжиренная, диетическая, полезные советы по "солянке", текущий тестовый патч Поделиться этим сообщением Ссылка на сообщение
Dennis_Chikin 3 663 Опубликовано 24 Июня 2016 В продолжение о чудесах народного модотворчесва, а также в некоторых местах и собственно оригинала: код типа local ini = xr_logic.get_customdata_or_inifile( блабла ) if ini:section_exist( "logic" ) then что-то делаем else делаем что-то другое end - совершенно бессмысленный, поскольку если в олспавне не прописана секция logic - она будет подставлена из config\scripts\dummy.ltx И это идет с оригинала. Поскольку там поле active = nil - все дальнейшие сравнения в апдейте с какими либо иными строками - столь же бессмысленны. Проверяйте нужную вам секцию после xr_logic.initialize_obj(), а далее - как описано в посте выше - из схем при получении true из xr_logic.try_switch_to_another_section() 1 Солянка обезжиренная, диетическая, полезные советы по "солянке", текущий тестовый патч Поделиться этим сообщением Ссылка на сообщение
Dennis_Chikin 3 663 Опубликовано 24 Июня 2016 (изменено) Вообще, что касается функций, проверяющих какие-либо условия, стоит доработать xr_logic.script по аналогии с выполнением функций xr_effects по-умолчанию либо из явно заданного модуля. Просто перенести 1:1. А вот что касается размножения time_test7, ...8, 9.6.6.666 и т.д. - аргументы прекрасно передаются, так что вполне достаточно одну time_test(), поскольку parse_infop() совершенно все равно, что разбирать. P.S. Перечитал сейчас свой пост от декабря прошлого года. Вот интересно, зачем я сейчас опять пишу все то же, что очевидно из того первого ? Наверное, по тому, что 8 месяцев отвечал разным людям на все те же вопросы, которые там разобраны, и по тому, что наблюдаемый эффект - скорее отрицательный. Изменено 24 Июня 2016 пользователем Dennis_Chikin Солянка обезжиренная, диетическая, полезные советы по "солянке", текущий тестовый патч Поделиться этим сообщением Ссылка на сообщение
Dennis_Chikin 3 663 Опубликовано 25 Июня 2016 (изменено) function pick_section_from_condlist( actor, npc, condlist ) ... if c then -- ВСЕ условия выполнены; выдаем инфо/вызываем функции, как просили for i, v in ipairs( cond.infop_set ) do if v.func then -- вызываем функции из %=func% c, f = string_match( v.func, "(.+)[.](.+)" ) -- c больше не нужно if f then -- c - скрипт c = _G[c] if c then f = c[f] end else f = xr_effects[v.func] -- f определено в xr_effects endЕсли нужно вызвать функцию, то вот здесь выбирается, откуда ее вызывать.А вот проверка условий: elseif v.func then -- вызывается функция из xr_conditions.script f = xr_conditions[v.func] or abort( что-то там ) - то есть, просто здесь надо доработать аналогично тому, что выше. Передача параметров в вызываемую функцию - типичный пример из оригинала, gulag_escape.ltx: on_info = {=gulag_population_le(esc_lager:6)} walker@esc_lager_defend_new1 Соответственно, функция с проверкой из оригинала же: -- true, если в указанном гулаге народу меньше чем надо. function gulag_population_le(actor, npc, p) return ( not p[1] or not p[2] ) or ( xr_gulag.getGulagPopulation( p[1] ) <= p[2] ) endПроблема с онлайном/офлайном здесь в том, что используется xr_gulag.getGulagPopulation, которая только для онлайна.Для того, чтобы работало и в офлайновом гулаге тоже, надо что-то типа function get_population( name ) local strn = name and alife():object( name ) local g = strn and strn.gulag return ( g and g.population_comed ) or 0 end- но это уже отношения к логике не имеет. Изменено 25 Июня 2016 пользователем Dennis_Chikin Солянка обезжиренная, диетическая, полезные советы по "солянке", текущий тестовый патч Поделиться этим сообщением Ссылка на сообщение
Dennis_Chikin 3 663 Опубликовано 23 Сентября 2016 (изменено) override и condlist - это просто такие строчки. override - указание на отдельную секцию. Там вбито несколько строчек для чтения: function cfg_get_overrides( ini, sect ) if not ( sect and ini:section_exist( sect ) ) then return {} end local t = {} if ini:line_exist( sect, "heli_hunter" ) then t.heli_hunter = parse_condlist1( ini:r_string( sect, "heli_hunter" ) ) end if ini:line_exist( sect, "combat_ignore_cond" ) then -- как бычно, здесь и далее закладываемся на то, что в священных и неприкосновенных -- конфигах может быть любой бред, по-этому чистим прочитанное от вертикальных палок local s = string_match( ini:r_string( sect, "combat_ignore_cond" ), "([^|]+)" ) if s then t.combat_ignore = { ["name"] = "combat_ignore_cond", ["condlist"] = parse_condlist1( s ) } end end if ini:line_exist( sect, "combat_ignore_keep_when_attacked" ) then t.combat_ignore_keep_when_attacked = ini:r_bool( sect, "combat_ignore_keep_when_attacked" ) end if ini:line_exist( sect, "combat_type" ) then local s = string_match( ini:r_string( sect, "combat_type" ), "([^|]+)" ) if s then t.combat_type = { ["name"] = "combat_type", ["condlist"] = parse_condlist1( s ) } end end if ini:line_exist( sect, "on_combat" ) then local s = string_match( ini:r_string( sect, "on_combat" ), "([^|]+)" ) if s then t.on_combat = { ["name"] = "on_combat", ["condlist"] = parse_condlist1( s ) } end end if ini:line_exist( sect, "companion_enabled" ) then t.companion_enabled = ini:r_bool( sect, "companion_enabled" ) end if string_match( sect, "kamp" ) then if ini:line_exist( sect, "center_point" ) then local s = ini:r_string( sect, "center_point" ) if s then t.soundgroup = s end end elseif ini:line_exist( sect, "soundgroup" ) then local s = ini:r_string( sect, "soundgroup" ) if s then t.soundgroup = s end end return t end - как говорится, делайте с ними, что хотите. condlist - это вообще просто такая строка, в которой может быть что угодно. Вообще все, что угодно. Еще так называется часть любой строки, в которой есть набор значков типа %{}+-=~! Изменено 23 Сентября 2016 пользователем Dennis_Chikin Солянка обезжиренная, диетическая, полезные советы по "солянке", текущий тестовый патч Поделиться этим сообщением Ссылка на сообщение
Dennis_Chikin 3 663 Опубликовано 11 Марта 2017 И вот кстати что делать с этой страницей с "категориями", я сколько ни пытался, так и не понял. Вообще ни о чем. Солянка обезжиренная, диетическая, полезные советы по "солянке", текущий тестовый патч Поделиться этим сообщением Ссылка на сообщение
Dennis_Chikin 3 663 Опубликовано 23 Марта 2017 state_mgr.set_state() же. Нужные стэйты смотреть в state_lib.script, при необходимости - добавить. Солянка обезжиренная, диетическая, полезные советы по "солянке", текущий тестовый патч Поделиться этим сообщением Ссылка на сообщение
Dennis_Chikin 3 663 Опубликовано 25 Марта 2017 "Не помогает" - это вообще не работает, или бежит не так, как надо ? Солянка обезжиренная, диетическая, полезные советы по "солянке", текущий тестовый патч Поделиться этим сообщением Ссылка на сообщение
Dennis_Chikin 3 663 Опубликовано 31 Марта 2017 Урок называется xr_camper.script Смотрим action_patrol:execute(), и выбираем: что именно надо. Солянка обезжиренная, диетическая, полезные советы по "солянке", текущий тестовый патч Поделиться этим сообщением Ссылка на сообщение