Serge! 127 Опубликовано 25 Ноября 2014 Поделиться Опубликовано 25 Ноября 2014 В классе FS используются 2 таинственных класса "reader" и "IWriter". Кто может что-нибудь сказать про них? Ссылка на комментарий
Struck 61 Опубликовано 25 Ноября 2014 Поделиться Опубликовано 25 Ноября 2014 @Serge!, чем они таинственные? w_open - IWriter; r_open - reader. Но о них лучше забыть, разве что на чтение, но для этого полно других штатных методов. Касаемо записи, файл создать можно, но записать вроде более 300 байт нельзя, если память не изменяет. Давным-давно с этим разбирался. Ссылка на комментарий
Romann 623 Опубликовано 29 Ноября 2014 Поделиться Опубликовано 29 Ноября 2014 Всем доброго времени суток, появился такой вопрос: возможно ли скриптово реализовать тепловизор? Ну вот к примеру обычный пнв("белая ночь") , а скрипт таким классам как нпс и монстр присваивает эффект другого цвета, ну или что-то типа того? Мать: ASRock X470 Master SLI. Процессор: AMD Ryzen 9 3900X 12-Core(4200 MHz). Память: Patriot Memory 3200 C16 Series. DDR4-3200(1600МГц), 16Гбх2(32Гб). Видео: GeForce GTX 1060 6GB. Блок питания: CoolerMaster 750 Вт. Корпус: Zalman i3 Edge. Химера конечно сильный хищник, а все держится дома. Чего же ты пришел к ней домой и пытаешься её убить? © Болотный Доктор Ссылка на комментарий
Dennis_Chikin 3 658 Опубликовано 29 Ноября 2014 Поделиться Опубликовано 29 Ноября 2014 (изменено) 2 groks, про кровососа: Во-первых, Артосокод и сам по себе громоздкий, а ьбез форматирования это вообще не читается, с форматированием же сразу все более-менее понятно: --/#+# 'засос кровососа боксёра' -------------------------------------------------- if self.object:clsid() == clsid.bloodsucker_s and self.object.health > 0.25 then local oTarget = self.object:get_enemy() if oTarget and IsStalker(oTarget) and self.object:see(oTarget) then --/ если у кровососа есть враг/цель и кровосос его видит то ... local iDist = self.object:position():distance_to(oTarget:position()) if iDist <= 2 then --/ дистанция для анимации 'засоса' local iTime = time_global() --/ таймер для анимации и хита ... if (self.timer_anim or 0) < iTime then self.timer_anim = iTime + 500 --/ таймер анимации ~ 0.5 сек if self.object:animation_count() > 0 then self.object:clear_animations() end self.object:add_animation("wounded_2_out") --/ варианты: "vampire_0" | "idle" --/ озвучка 'засоса' local oSnd = sound_object("material\\dead-body\\collide\\hithard06hl") oSnd:play_no_feedback(oTarget, sound_object.s2d, 0, vector(), 5.0) end --/ хит жертве (притягиваем) if (self.timer_hit or 0) < iTime and (self.timer_anim and self.timer_anim + 200 >= iTime) then self.timer_hit = iTime + 10 --/ таймер хита ~ 0.1 сек local vDir = self.object:direction() --/ вектор кровососа local vDirHit = vector_rotate_y(vDir,179.0) local h = hit() h.draftsman = self.object h.direction = vDirHit --/ направление хита h:bone("bip01_spine") --/ для учета 'брони' h.power = 0.02 level.add_cam_effector("camera_effects\\fusker.anm",959,false,"") h.impulse = 50/iDist --/ чем ближе - тем сильнее 'засос' h.type = hit.wound --hit.strike oTarget:hit(h) --/ наносим хит жертве --/ разворот жертвы на кровососа. TODO: требует доработки/замены! if oTarget:id() == db.actor:id() then --/ жертва == актор? (а нужно?) oTarget:set_actor_direction(vDirHit:getH()) end end end end end Во-вторых, в данном случае оно меня сильно разочаровало. Ну да ладно. if (self.timer_anim or 0) < iTime then -- то есть, если меньше, то начинает притягивать и озвучивать. self.timer_anim = iTime + 500 -- а к self.timer_anim добавляет пол секунды. Мало это, или много - тут на усмотрение. Но через пол-секунды повторит. if (self.timer_hit or 0) < iTime and (self.timer_anim and self.timer_anim + 200 >= iTime) then если 10 миллисекунд хит ни кому не наносился, и 200 ms (чуть меньше половины времени от начала засасывания НЕ прошло, то наносит. self.timer_hit = iTime + 10 --/ таймер хита ~ 0.1 сек и еще 10ms добавляет. То есть, аки пионэр, снова будет готов. Мдя, видал я разные варианты кровососов извращенцев, но этот - вообще какой-то озабоченный. Ну а дальше он собственно и занимается извращениями всякими нехорошими. Вообще, конечно, все это извращение следует переписать, но, хотя-бы... гм... Да уж... В общем вот здесь: if self.object:clsid() == clsid.bloodsucker_s and self.object.health > 0.25 then не хватает чего-то вроде and ( self.tmer_attack or 0 ) < time_global() then а после self.timer_hit = iTime + 10 --/ таймер хита ~ 0.1 сек еще self.timer_attack = iTime + сколько надо. -- я бы что-то типа 2000 или даже 5000 поставил. Тогда один раз анимку запустит, и один раз хит нанесет. Впрочем, все равно уродство редкостное, поскольку вообще не здесь надо править, а здесь все проще закрасить, чем отскребать. upd: if (self.timer_hit or 0) < iTime and (self.timer_anim and self.timer_anim + 200 >= iTime) then -- нет, я вообще не понял, как оно должно работать. Оно ж всегда больше. Пулеметная очередь какая-то. И нафига тогда вообще проверять ? Изменено 29 Ноября 2014 пользователем Dennis_Chikin Солянка обезжиренная, диетическая, полезные советы по "солянке", текущий тестовый патч Ссылка на комментарий
Карлан 1 049 Опубликовано 29 Ноября 2014 Поделиться Опубликовано 29 Ноября 2014 @Dennis_Chikin, оно и не работает (как нужно), функцию нужно заново писать. Хотя выглядит красиво и заманчиво. и каждый незадачливый солянщик считает должным себе это взять, хотя на деле это выглядит/работает весьма... не корректно. Ссылка на комментарий
groks 439 Опубликовано 29 Ноября 2014 Поделиться Опубликовано 29 Ноября 2014 Но оно работает. И совершенно без сбоев. Действительно как из пулемёта ... эээ ... присасывается. Теперь хоть понял, что за паузу отвечает. Цель привести к состоянию, когда у ГГ хоть с небольшой защитой есть шанс выжить. А то ж будут сплошные сейф-лоады, которые надоедят и геймер бросит мод. @Dennis_Chikin, Спасибо. @Карлан, Предложи вариант. Может проще будет не вертеть ГГ и просто прилепить анимацию опьянения например? Ссылка на комментарий
Dennis_Chikin 3 658 Опубликовано 29 Ноября 2014 Поделиться Опубликовано 29 Ноября 2014 (изменено) Ну вот как-то так уж, что-ли. Не проверял, ибо где я в такую погоду найду вам кровососа, да еще и извращенца ? local tg = time_global() -- должно быть сразу после function что-то_там( что_попало ) local mob = self.object -- и дальше заменяем все self.object на mob до конца функции --/#+# 'засос кровососа боксёра' -------------------------------------------------- if mob:clsid() == clsid.bloodsucker_s and mob.health > 0.25 then if self.attack_time and tg < self.attack_time -- атака пошла local enemy = mob:get_enemy() if enemy and enemy:id() == 0 and mob:see( enemy ) -- видит актора and enemy:position():distance_to_sqr( mob() ) < 4.3 then -- близко if self.timer_hit then if self.timer_hit < tg then -- наносим хит self.timer_hit = tg + 50 -- повторим потом local vDir = mob:direction() --/ вектор кровососа local vDirHit = vector_rotate_y( vDir, 179.0 ) local h = hit() h.draftsman = mob h.direction = vDirHit --/ направление хита h:bone( "bip01_spine" ) --/ для учета 'брони' h.power = 0.02 level.add_cam_effector( "camera_effects\\fusker.anm", 959, false, "" ) h.impulse = 50 / enemy:position():distance_to( mob() ) --/ чем ближе - тем сильнее пинаем h.type = hit.wound enemy:hit(h) --/ наносим хит жертве --/ разворот жертвы на кровососа. TODO: требует доработки/замены! enemy:set_actor_direction( vDirHit:getH() ) end else -- запуск анимации if mob:animation_count() ~= 0 then mob:clear_animations() end -- анимации остановили mob:add_animation( "wounded_2_out" ) --/ варианты: "vampire_0" | "idle" --/ озвучка 'засоса' local snd= sound_object( "material\\dead-body\\collide\\hithard06hl" ) if snd then snd:play_no_feedback( enemy, sound_object.s2d, 0, vector(), 5.0 ) end self.timer_hit = tg + 200 -- отыграет анимку, и нанесет хит end else self.attack_time = false -- атака сорвалась end elseif ( self.check_attack or 0 ) < tg then -- проверяем не постоянно local enemy = mob:get_enemy() if enemy and enemy:id() == 0 and mob:see( enemy ) -- видит актора and enemy:position():distance_to_sqr( mob() ) < 4.3 then -- близко self.attack_time = tg + 500 -- атака пошла, пол секунды на все self.check_attack = tg + 1000 -- ну и повтор через секунду self.timer_hit = false else self.check_attack = tg + 200 -- хотя бы 200ms end end end upd: 22:15 - и еще поправил. Ибо нефиг прямо на форуме код писать. И, блин, нет ничего хуже, чем постоянно что-то править под древние кривые скрипты, когда у тебя давно вменяемые написаны. 8( 2 Zander_driver: на риторический вопрос я могу дать только риторический ответ. Надо ? По тому что про кровососа был пост на форуме, и этого самого кровососа пытаются впихнуть именно в древний кривой скрипит. Upd2: тьфу, блин. if self.attack_time and tg < self.attack_time -- атака пошла вот так надо. И дальше тоже на attack_time поменять, для красивости. Изменено 29 Ноября 2014 пользователем Dennis_Chikin Солянка обезжиренная, диетическая, полезные советы по "солянке", текущий тестовый патч Ссылка на комментарий
Serge! 127 Опубликовано 2 Декабря 2014 Поделиться Опубликовано 2 Декабря 2014 (изменено) Раз началась чистка форума, то хочу завершить нашу подвисшую дискуссию об использовании текстовых файлов в модах на движке ТЧ. Это актуально потому, что все мои посты, кроме самого первого с вопросом, уже убраны, а остались только 2 сумбурных по содержанию ответа от Struck, в которых, к тому же, второй противоречит первому. Это говорит лишь о том, что товарищ не достаточно глубоко разобрался в этом вопросе, но, тем не менее, легко берётся учить других. А вот полезной информацией по этому вопросу, как оказалось, не владеет.Учитывая вышеизложенное, немного предыстории, которую можно и пропустить, т.к. в этом сообщении ни она главная цель. При игре в Сталкера меня всегда утомляла порой бессмысленная и бестолковая беготня ГГ по локациям. Поэтому возникла потребность как-то оптимизировать этот процесс путём быстрого перемещения ГГ по тем точкам, в которых он уже побывал ранее. Этот, казалось бы, простой аспект (только по собственным точкам)на самом деле является очень важным, т.к. перемещение только по пройденному тобой пути, а не по предварительно кем-то оцифрованному, гарантирует выполнение сюжетной линии Авторов. Для этого нужен был «перемещатель». У меня, при разработке скрипта по перемещению ГГ в пределах локации, возникла задача сохранения координат этих точек перемещения. При этом на этот процесс были сформулированы следующие ограничения:1. количество сохранённых точек перемещения должно быть сколь угодно большим;2. минимальное, а лучше полное отсутствие, вмешательство скрипта в штатную архитектуру;3. сохранность информации о координатах перехода в независимости от любых форс-мажоров (внезапные вылеты, перезагрузка с более ранней сохранки и т.п.);4. работа с любыми модами, независимо от их собственных примочек и наворотов;5. стабильность и устойчивость в работе;6. быстрое и простое подключение к любой модификации.Недолгие раздумья привели к выводу, что это задача решается только с использованием внешних файлов, что и было быстро реализовано для модов на движке ЗП. (для ЧН тоже, скорее всего, подойдёт, но в моды ЧН я практически не играю и, поэтому данный аспект не проверял).А вот с ТЧ вышел облом, т.к. этот движок отказался работать с внешними файлами. Только сохранки, картинки и логи. Меня это совершенно не устраивало. Последующий длительный поиск информации в Интернете и по сталкерским сайта показал, что подавляющее число людей, так или иначе связанных с разработками по Сталкеру, почти консолидировано считали – такое не возможно, потому, что не возможно никогда. Однако всё же нашёлся один разработчик, который, видимо, придерживается и моего любимого принципа – «Если это нельзя, но очень хочется, то значит это можно. Просто надо найти какой-то другой путь решения». Этим человеком был Artos, который, судя по описанию, ещё в 2010 году решил эту проблему путём возвращения в пространство имён Lua для Сталкера класса io и исправления глобального пространства для класса FS. Там и ещё много другого важного и интересного сделано, но здесь речь только о работе с файлами. Я пока не стал её реализовывать (даже не смотрел ничего кроме описания, хотя скачал), т.к., в моём мелком случае, она несколько «тяжеловата». Однако взял на заметку для возможного будущего использования. Странно, что профи мододелы, так важно и авторитетно говорящие всякие красивые слова на форумах того же сайта, где эта разработка описана и опубликована, про это не подозревают или молчат(?), а я, дилетант в этих вопросах по сути дела – знаю и говорю.Однако вернёмся к нашим проблемам.Основных, да и единственных, предложений в ответах оппонентов было два. Т.к. эти посты уже тоже вычищены, то напомню: 1 - использовать статические таблицы точек перехода (такие действительно применяются во многих поделках) и 2 - использовать нет-пакеты. Я начал возражать, мне, не очень аргументировано, продолжали доказывать свою правоту. Всея эта «плодотворная дискуссия» завершилась моим «баном» и последующей чисткой. Сильный аргумент ничего не скажешь.Приведу свои доводы против обоих предложений.Статические таблицы. Чтобы их заполнить самому, надо долго побегать/полетать по всем локациям, собрать координаты в не понятно каких точках (в игру я же ещё не играл, а если уже играл, то зачем мне это?) и проделать большую работу по заполнению таблиц. Можно воспользоваться таблицами других авторов (если они найдутся), поковыряться в скриптах, а потом бегать, как собачка на поводке по меткам кем-то для тебя приготовленными. Фу… Это было явно не для меня и отпало сразу.Нет-пакеты. Их можно было бы и использовать, но они не соответствовали моим ограничениям по следующим соображениям:1. Нет-пакеты привязаны к объектам. К какому объекту мог бы их привязать я? Выбор не большой – а) ГГ, б) локация, в) созданное для этих целей новое устройство. Всё это не реально и нарочито появлением непонятных вылетов в процессе игры.2. Системные ограничения по размеру нет-пакетов ещё никто не отменял.3. Они сохраняются и восстанавливаются для реперных точек игры. И, если я восстановлюсь с более ранней сохранки, то мне придётся обновлять свою базу переходов.4. Требуется серьёзная правка исходных кодов игры, причём для каждого нового мода своя.С историей на этом всё, переходим к практике.Перед тем, как перейти к непосредственной реализации, немного теории, которую лучше посмотреть, чтобы было понятнее остальное. Спросим себя – что такое файл? По определению Википедии - файл это «именованная область данных на носителе информации». Такая область данных может содержать информацию в любом виде, обязательным требованием для которого является только однотипность единицы множества этой информации и наличия описания их параметров. В качестве носителя информации может выступать что угодно, например: книжная полка (единица информации – книга), книга (единица информации – лист), папка для документов (единица информации – документ). Не зря же все иностранцы называют привычные для нас пластиковые папочки с бумажками - файлами. Кто не верит, поверьте мне на слово, т.к. я долго в этом варился. В нашем же случае, носителем информации на вернем уровне является диск, а некой единицей информации на нём - файл. Всё, дальше в это углубляться не будем. Всё остальное все желающие могут найти сами, а нам для дальнейших рассуждений этого вполне хватит.Что такое текстовый файл? Это область данных, которая хранит информацию в виде набора строк символов. Вся информация о структуре этих строк является служебной и хранится в отдельной области. Нас эта область сейчас ну ни разу не интересует. Нас интересуют только сами строки.Что такое каталог/папка с файлами? Это область данных, которая хранит информацию в виде набора отдельных файлов, которые для самого каталога представляется только как набор строк с именами этих файлов. Вся служебная информация об этих файлах/строках также хранится в отдельной области. И здесь эта область нас не интересует. Главное мы выяснили – имя файла это строка символов, на которые, правда, накладываются определённые ограничения и то, что каталог это тоже файл.Разумеется, это не строгое описание, но, чтобы двигаться дальше, этого достаточно.Итак, договорились, что под обычным «файлом» мы будем понимать каталог, а под «строкой» такого псевдо файла собственно сам физический файл, имя которого и будет являться для нас привычной строкой.Теперь перейдём к Сталкеру. Что нам в «открытом доступе» оставили Разработчики ТЧ для работы с файлами? Да, собственно говоря, почти ничего полезного для практического использования. Да и это, я думаю, осталось только из-за обычного дефицита времени на подчистку «хвостов» и борьбы за размер дистрибутива. Однако всегда у всех что-то случается, дело до конца не доводится, ну а мы попробуем извлечь из этого выгоду для себя.И так мы имеем полные возможности читать каталоги с файлами и сохранять их в памяти в виде списков. Замечательно, т.к. половина проблемы решена. С записью хуже. Записать мы можем только определенные структуры данных (сохранки, картинки, логи). Но, поскольку продукт делали наши ребята, то, как часто случается, «хлопнули ушами» и оставили нам дырочку в своём заборе. Я имею в виду метод copy в классе FS. Отлично, значит, мы имеем возможность переименовать любой файл, присвоить ему любое имя и поместить его в любое место. Вам уже понятно, какой был у меня ход мысли?Тогда вперёд, к реализации наших теоретических изысканий. Опишу словами то, что потом покажу в коде. Раз под файлом будем понимать папку, то нам надо её иметь. Для простоты её можно создать в каталоге самой игры, а можно и в любом другом месте. Я создал её там же, где хранятся сохранки, логи и картинки (у меня это папка users в корневой папке игры). В этой папке создается наша рабочая папка (псевдо файл), которую я назвал "scroll", а в ней любым способом создаем файл шаблон нулевой длины с простым коротким именем и без расширения. Я ему дал имя «01» и установил атрибут «только для чтения», чтобы случайно не удалить. Этот файл будет использоваться в скрипте для сохранения наших точек перехода.При запуске скрипта он будут читать эту папку формировать список имеющихся точек перехода, т.е. имеющихся в ней файлов. На старте же будет фиксироваться текущая позиция ГГ. Эти координаты также будут показаны. Имя выбранной в списке или новой точки перехода выводится в редактируемом поле, которое может быть очищено нажатием соответствующей кнопки. Если в этом поле имеется имя точки, то можно перейти на неё, сохранитьили удалить. При сохранении наш файл шаблон стандартным методом копируется в новый с присвоением ему в качестве имени строки содержащей следующие поля (в качестве разделителя случит запятая):имя точки, координата X, координата Y, координата Z, угол доворота камеры.имя локацииЗаметили, что в качестве имени файла применяется имя локации. Это позволяет нам при формировании списка на старте сразу отфильтровывать и загружать только те точки перехода, которые относятся к текущей локации.Выход обычным способом или по Esc, или по отдельной кнопке «Выход» Поскольку я раньше ничем подобным не занимался, то мне было интересно «пощупать», что же это такое текстуры и окна Сталкера. Но можно вполне обойтись и штатными текстурами и диалоговыми окнами.Как это получилось можно посмотреть И наконец, сама реализация -- перемещение по уровню для ТЧ (2014)local tnam = {"nm","px","py","pz","ag"}local fs = getFS() -- класс FSlocal is_fs = fs:exist("$scroll$","01") -- проверка на начичие шаблонаlocal full_path = is_fs.name -- запомним абсолютный путь файла-шаблонаlocal tf = {point} -- внутренняя таблица файлов-- получаем количество полей и позиции разделителяlocal function GetPosSep(str)if str == "" or str == nil then return {} endlocal t, pos, n = {}, 0, 0while pos ~= nil dopos = string.find(str, '[%|%,]', pos+1)n = n + 1if pos ~= nil then table.insert(t,pos) endendreturn {sp = n, tbl = t}end-- получаем поле по индексуlocal function GetPol(str,num)if str == "" then return str endif num == nil then num = 1 endlocal pol, t = nil, GetPosSep(str).tblif num == 1 then -- первыйpol = string.sub(str,1,t[num]-1)elseif num == GetPosSep(str).sp then -- последнийpol = string.sub(str,t[num-1]+1)elsepol = string.sub(str,t[num-1]+1,t[num]-1)endreturn polendclass "load_item" (CUIListItemEx)function load_item:__init() super()self.text_name = "name"self:SetWndRect(0,0,230,22)self.sn = CUIStatic()self.sn:SetAutoDelete(true)self:AttachChild (self.sn)self.sn:SetWndRect (0,0,200,22)self.sn:SetText("name")self.sn:SetFont(GetFontLetterica18Russian())self.sn:SetTextColor(255,216,186,140)endfunction load_item:__finalize()end-- точка входа из внешних скриптов (ui_scroll_wnd.main())function main()super_dlg = ui_scroll_wnd.scroll()level.start_stop_menu(super_dlg, true)endclass "scroll" (CUIScriptWnd)function scroll:__init() super()self:InitControls()self:InitCallBacks()endfunction scroll:__finalize()end-- заполняем список точек перехода на текущей локацииfunction scroll:FillList()local flist_ex = fs:file_list_open_ex("$scroll$",FS.FS_ListFiles ,"*."..self.lev)local f_cnt = flist_ex:Size()local str, namif f_cnt > 0 thenfor it = 0, f_cnt-1 dostr = flist_ex:GetAt(it):NameFull()nam = GetPol(str,1)self:AddItemToList(nam)local vp = vector():set(tonumber(GetPol(str,2)),tonumber(GetPol(str,3)),tonumber(GetPol(str,4)))local age = tonumber(GetPol(string.gsub (str, "."..self.lev, ''),5))local t = {}; t.fn = str; t.pos = vp; t.dir = agetf['point'] = nam; tf[nam] = tendendendfunction scroll:InitControls()self:Init(350,100,296,561) -- задаем позицию на экранеlocal xml = CScriptXmlInit() -- создаем класс для файла описанияxml:ParseFile("ui_scroll_wnd.xml") -- подключаем файл описания элементов окнаxml:InitStatic("scr_background", self) -- устанавливаем статик фона-- регистрируем элементы окна-- поле ввода позицииself.scr_fr_name = xml:InitEditBox("scr_fr_name", self)self.scr_fr_name:SetFont (GetFontLetterica18Russian())-- self.scr_fr_name:SetTextColor(255,0,0,0)self:Register(self.scr_fr_name ,"scr_fr_name")-- кнопкиself:Register(xml:Init3tButton("scr_btn_1", self),"scr_btn_1") -- перенестиself:Register(xml:Init3tButton("scr_btn_2", self),"scr_btn_2") -- сохранитьself:Register(xml:Init3tButton("scr_btn_3", self),"scr_btn_3") -- удалитьself:Register(xml:Init3tButton("scr_btn_4", self),"scr_btn_4") -- очистить поле вводаself:Register(xml:Init3tButton("scr_btn_5", self),"scr_btn_5") -- выход-- получение текущей позиции и направленияself.st = xml:InitStatic("scr_pos", self)self.lv = xml:InitStatic("scr_lev", self)self.lev = level.name()self.pos = db.actor:position() -- позиция ГГself.age = -db.actor:direction():getH() -- угол доворота камеры от нулевой точки локацииself.lv:SetFont (GetFontLetterica16Russian())-- self.lv:SetText(string.format("Локация: %s", ))self.lv:SetTextST(string.format("Локация: %s", self.lev))self.st:SetText(string.format("X=%-7.2f Y=%-7.2f Z=%-7.2f", self.pos.x, self.pos.y, self.pos.z))-- поле списка точек переходаlocal ctrl = CUIWindow()xml:InitWindow ("scr_item:main",0,ctrl)-- сам списокxml:InitFrame("list_frame",self)self.list_box = xml:InitList("list",self)self.list_box:ShowSelectedItem(true)self:Register(self.list_box, "scr_list")self:FillList() -- заполняем списокendfunction scroll:InitCallBacks()self:AddCallback("scr_list", ui_events.LIST_ITEM_CLICKED, self.OnListItem_clicked, self)self:AddCallback("scr_list", ui_events.WINDOW_LBUTTON_DB_CLICK, self.OnListItemDb_clicked, self)self:AddCallback("scr_btn_1", ui_events.BUTTON_CLICKED, self.OnButton_scroll_clicked, self)self:AddCallback("scr_btn_2", ui_events.BUTTON_CLICKED, self.OnButton_save_clicked, self)self:AddCallback("scr_btn_3", ui_events.BUTTON_CLICKED, self.OnButton_del_clicked, self)self:AddCallback("scr_btn_4", ui_events.BUTTON_CLICKED, self.OnButton_CLEAR_clicked, self)self:AddCallback("scr_btn_5", ui_events.BUTTON_CLICKED, self.OnButton_CANCEL_clicked, self)end-- очистить поле ввода имениfunction scroll:OnButton_CLEAR_clicked()self.scr_fr_name:SetText("")end-- Перейтиfunction scroll:OnButton_scroll_clicked()local sc_name = self.scr_fr_name:GetText()if sc_name ~= "" thendb.actor:set_actor_position(tf[sc_name].pos)db.actor:set_actor_direction(tf[sc_name].dir)level.start_stop_menu(self)endend-- Сохранитьfunction scroll:OnButton_save_clicked()local sc_name = self.scr_fr_name:GetText()if sc_name == "" then return endlocal abs_path = string.gsub(full_path, '01', '') -- получаем абсолютный путь для нового файлаlocal new_path = abs_path..sc_name..','..tostring(self.pos.x)..','..tostring(self.pos.y)..','..tostring(self.pos.z)..','..tostring(self.age)..'.'..self.levfs:file_copy(full_path, new_path) -- создаём новый файл точки переходаlevel.start_stop_menu(self)end-- Удалитьfunction scroll:OnButton_del_clicked()local sc_name = self.scr_fr_name:GetText()if sc_name == "" then return endfs:file_delete("$scroll$",tf[sc_name].fn)level.start_stop_menu(self)end-- Выйтиfunction scroll:OnButton_CANCEL_clicked()level.start_stop_menu(self)end-- Выбор (щелчок в списке)function scroll:OnListItem_clicked()local list_box = self:GetListWnd("scr_list")if list_box:GetSize() == 0 then return endlocal item_id = list_box:GetFocusedItem()local _itm = list_box:GetItem(item_id)if _itm == nil then return endlocal item_text = _itm.sn:GetText()self.scr_fr_name:SetText(item_text)end-- Двойной щелчокfunction scroll:OnListItemDb_clicked()self:OnListItem_clicked()self:OnButton_scroll_clicked()level.start_stop_menu(self)end-- клавишыfunction scroll:OnKeyboard(dik, keyboard_action)CUIScriptWnd.OnKeyboard(self,dik,keyboard_action)local bind = dik_to_bind(dik)local console = get_console()if keyboard_action == ui_events.WINDOW_KEY_PRESSED thenif dik == DIK_keys.DIK_ESCAPE thenlevel.start_stop_menu(self)endendreturn trueend-- добавляем строку в списокfunction scroll:AddItemToList(text)local _itm = load_item()_itm.sn:SetText(text)local list_box = self:GetListWnd("scr_list")list_box:AddItem(_itm)end Замечу, что это никак не тянет на готовый программный продукт, т.к. делалось исключительно для собственного использования и поэтому здесь отсутствуют все проверки на ошибочные или неосторожные действия пользователя. А без такой обвязки тиражироваться, конечно же, не может.Получилось конечно же длинновато, однако Бог видимо не дал мне таланта излагать свои мысли коротко и доходчиво. Хотя, на такую мою особенность, жалуются не часто, но бывает.Если данный опус не соответствует тематике форума, то можно и удалить, как и предыдущие мои посты. Однако хотелось бы, чтобы его прочитали два самых активных моих оппонента. Может в следующий раз они будут относиться к людям, которые не обладают их опытом в модостроении, но тоже хотят что-то попробовать сделать. Хотя бы для собственного интереса. Изменено 2 Декабря 2014 пользователем Serge! Добавлено Dennis_Chikin, 2 Декабря 2014 Не убраны, а перемещены. Можно взять, отредактировать, и оставив нужное вернуть сюда. Или пусть лежат там, где лежат, в неизменном виде. Очевидно, обсуждение пользователя все же к теме не относится. Ссылка на комментарий
Dennis_Chikin 3 658 Опубликовано 2 Декабря 2014 Поделиться Опубликовано 2 Декабря 2014 (изменено) Ну и вообще, если я правильно понял смысл поста, то это давно делают примерно так: local t_opt = { ["p"] = { "game_pause", "radio_amk_pause", 1 }, ["r"] = { "show_rad", "radio_amk_rad", 1, bind_stalker.rdet_enable }, ["h"] = { "suit_hud", "radio_amk_hud", 0 }, ["m"] = { "din_music", "radio_amk_mus", 0 }, ["a"] = { "keep_anoms", "radio_amk_anoms", 0 }, ["d"] = { "ch_difficulty", nil, 0 }, ["t"] = { "treasure_type", "radio_amk_treasure", 2 } } function save_options() local fs = getFS() local flist = fs:file_list_open_ex("$game_saves$", bit_or(FS.FS_ListFiles, FS.FS_RootOnly), "game_options_*.sta" ) local s = flist:GetAt( 0 ):NameFull() local opt = "" local n, fn for k, v in pairs( t_opt ) do n = v[3] if n == 0 then game_options[ v[1] ] = false fn = v[4] if fn then fn( false ) end else game_options[ v[1] ] = n fn = v[4] if fn then fn( n ) end end opt = opt .. k .. tostring( n ) end n = "game_options_" .. opt .. ".sta" if s ~= n then fs:file_rename( fs:update_path("$game_saves$", s ), fs:update_path("$game_saves$", n ), true) end end -- здесь, в частности, чтобы сохранить опции игры независимо от сэйвов. Изменено 2 Декабря 2014 пользователем Dennis_Chikin Солянка обезжиренная, диетическая, полезные советы по "солянке", текущий тестовый патч Ссылка на комментарий
Карлан 1 049 Опубликовано 2 Декабря 2014 Поделиться Опубликовано 2 Декабря 2014 (изменено) @Serge!, тебе все по делу написали. А это извращение было открыто в 2010. Все об это знают я думаю. io в ТЧ нет и не было. К чему ты тут развел это все я не понимаю. Даже сам Artos такое не использовал, а написал se_stor. Подобное нужно лишь в редких случаях (и то - не уверен), например вот как Денис описал. Обновленная система ивентов: m_events (031214) [~2.5Kb] P.S.: не трактую свою систему как хорошую и безупречно работающую, но может кому и сгодится Изменено 2 Декабря 2014 пользователем Карлан 1 Ссылка на комментарий
Serge! 127 Опубликовано 2 Декабря 2014 Поделиться Опубликовано 2 Декабря 2014 Принцип тот же, имеем какой-то шаблон, который или переименовываем (как в Вашем примере), или копируем под другим именем (как у меня). Только я тогда не знал (я ж любитель), как создать исходный файл-шаблон определенной структуры и поэтому сделал, как мог - просто создал пустой файл и работал с ним. Сейчас я понял, что могу прогнать такую схему в ЗП и, если всё получится, то работать по ней в ТЧ. Буду пробовать Где ж Вы раньше были, когда вдвоём уговаривали меня использовать не подходящие средства, а не рассказали про это? Ссылка на комментарий
Dennis_Chikin 3 658 Опубликовано 3 Декабря 2014 Поделиться Опубликовано 3 Декабря 2014 Просто метод более ограничен, чем другие. Например, вместе со всеми путями здесь не может быть более 250 символов. На сами символы тоже есть ограничения. То есть, это гораздо ХУЖЕ нетпакета. И хуже внешнего конвертера лога в ltx. Солянка обезжиренная, диетическая, полезные советы по "солянке", текущий тестовый патч Ссылка на комментарий
k01jan 816 Опубликовано 3 Декабря 2014 Поделиться Опубликовано 3 Декабря 2014 @Zander_driver, почему "был"?Его lua_helper, lua_extension, m_netpk, m_timers, se_stor (соответственно, изменённый _g), ты не поверишь, давно и успешно использую. Каким боком m_events? Что это? Зачем это (=как использовать)? 2 Ссылка на комментарий
Barmolini 1 Опубликовано 5 Декабря 2014 Поделиться Опубликовано 5 Декабря 2014 А скажите пожалуйста, что такого уродского в этом коде: if string.find( obj:section(), "af_" ) then Интересно в познавательных целях и чтобы не писать "по уродски". Ссылка на комментарий
Desertir 202 Опубликовано 5 Декабря 2014 Поделиться Опубликовано 5 Декабря 2014 @Barmolini, в секции можно написать my_cool_art и это будет артефактом, однако условие не пройдет. Пытаться чтото идентифицировать не по тому ключевому полю - глупо. Это как пробовать вычислить кошку среди собак по наличию хвоста и отсутствию крыльев. Смекаешь? Если кошка - изволь мяукать, в данном случае надо брать clsid или что там у нас. ТЧ 1.0004. SAP и Trans mod github Ссылка на комментарий
Карлан 1 049 Опубликовано 5 Декабря 2014 Поделиться Опубликовано 5 Декабря 2014 (изменено) @Barmolini, во-первых да, избавляемся от косяков с секциями, и в некоторых модулях не городим ненужные таблицы напрасно тратя время. А во-вторых проверка t[clsid] работает в ~6-7 раз быстрее чем string.find. На всякий (миллион итераций): strfind 0.022 table 0.003 Ну а ассоциативных массивов ты можешь писать сколь угодно, хоть на каждый итем в отдельности, если конечно сделаешь необходимые для этого действия, но это уже другая степь немного. Изменено 5 Декабря 2014 пользователем Карлан Ссылка на комментарий
Fireball.Stalker 1 Опубликовано 10 Декабря 2014 Поделиться Опубликовано 10 Декабря 2014 (изменено) Ребят, умоляю вас! Пожалуйста, напишите функцию убийства определённого НПС через скрипт.Платформа ТЧ А-ааа !!! npc:kill( npc ) - чем не подходит ? Ну и в поиск это же слово - kill, в смысле. dc Изменено 10 Декабря 2014 пользователем Dennis_Chikin Ссылка на комментарий
Macromelyan 0 Опубликовано 10 Декабря 2014 Поделиться Опубликовано 10 Декабря 2014 (изменено) @Fireball.Stalker, function mochim_five_nps() if has_alife_info("первый_грохнут") and has_alife_info("второй_грохнут") and has_alife_info("третий_грохнут") and has_alife_info("четвертый_грохнут") and has_alife_info("и_пятый_наконец") then return true else return false end end Удали несколько строк не нужных, смотря сколько убить нужно. Если нужно одного, то будет вот так: function mochim_five_nps() if has_alife_info("первый_грохнут") then return true else return false end end Изменено 10 Декабря 2014 пользователем Macromelyan Ссылка на комментарий
Fireball.Stalker 1 Опубликовано 10 Декабря 2014 Поделиться Опубликовано 10 Декабря 2014 @Fireball.Stalker, function mochim_five_nps() if has_alife_info("первый_грохнут") and has_alife_info("второй_грохнут") and has_alife_info("третий_грохнут") and has_alife_info("четвертый_грохнут") and has_alife_info("и_пятый_наконец") then return true else return false end end Удали несколько строк не нужных, смотря сколько убить нужно. Если нужно одного, то будет вот так: function mochim_five_nps() if has_alife_info("первый_грохнут") then return true else return false end end Спасибо, конечно, за ответ, но я имел в виду немного не то. Возможно, я вопрос не так поставил. Как убить НПС через скрипт - я это имел в виду. Ссылка на комментарий
Fireball.Stalker 1 Опубликовано 10 Декабря 2014 Поделиться Опубликовано 10 Декабря 2014 kill() тоже не подходит ? Ну а что тогда надо-то ? То есть, вот так? function kill(actor, npc) npc:kill(esc_paren_npc) end Ссылка на комментарий
Рекомендуемые сообщения
Создайте аккаунт или авторизуйтесь, чтобы оставить комментарий
Комментарии могут оставлять только зарегистрированные пользователи
Создать аккаунт
Зарегистрировать новый аккаунт в нашем сообществе. Это несложно!
Зарегистрировать новый аккаунтВойти
Есть аккаунт? Войти.
Войти