Garry_Galler 7 Опубликовано 23 Января 2010 malandrinus отсюда - тема по ООП. Там еще одна такая же тема есть. _http://mydc.ru/topic1429.html Поделиться этим сообщением Ссылка на сообщение
Garry_Galler 7 Опубликовано 23 Января 2010 (изменено) _Призрак_ Насчет трупа - obj:kill(obj) сработает только если сделать паузу между креате и килл - я так делал - таймер на 1 секунду. И готово - труп есть. Но это слишком громоздко. Все проще. Есть специальный метод для этого - в общем дарю способ: local sobj = alife():create("stalker", position, level_vertex_id, game_vertex_id) sobj:on_death() Vano_Santuri для твоей таблицы - вот пример сохранения одномерной таблицы из моих скриптов - сохраняется таблица такого же вида как у тебя. --сохранение данных function morg_save(p) local i = 0 --подсчитаем кол-во ключей for k,v in pairs(morg) do i = i + 1 end --запишем кол-во p:w_u8(i) --сохраняет целые числа до 256 for k, v in pairs(morg) do p:w_u16(k) --сохраняет числа до 65536 --вообще сохранять здесь ключи необязательно так как они идут в математическом порядке p:w_u16(v) --достаточно только значения сохранить end end --загрузка данных function morg_load(r) --загрузим кол-во ключей local i = r:r_u8() --запустим цикл for k = 1, i do --присвоим значения local id = r:r_u16() --соотвественно это тоже лишнее, но пусть для примера останется - если ключи будут идти не математическом порядке - вот тогда надо их точно сохранять morg[id] = r:r_u16() --здесь заполняем таблицу ключ=значение end end обе функции нужно вписать в бинд сталкер в функции function actor_binder:save(packet) и function actor_binder:load(reader) - каждую вписывать в одно и тоже место - чтобы они располагались в одинаковых местах каждой функции. для спавна разных аномалий добавляешь в функцию - в тело оператора for do - эту строчку local section = #anom[math.random(#anom)] - а к ней пишешь табличку anom с именами секций аномалий типа так local anom ={'zone_gravi_zone','zone_mincer', 'zone_witches_galantine','zone_mosquito_bald', 'zone_monolith','zone_zhar','zone_radioactive', 'zone_emi','zone_no_gravity','zone_zharka_static'} в креате соотвественно вместо имени пишешь section - и получаешь рандомный набор аномалий на любой вкус. Изменено 23 Января 2010 пользователем Garry_Galler Поделиться этим сообщением Ссылка на сообщение
Garry_Galler 7 Опубликовано 24 Января 2010 Vano_Santuri первая функция запишет айди аномалий в таблицу по принципу ключ=значение так как таблица у тебя индексируется по умолчанию - то будет так [1] = айди [2] = айди [3] = айди и т.д. вторая функция сохранит все данные из таблицы (при нажатии квиксейва, записи сохранения или перезагрузке) в объект "actor" средствами нет пакета. третья функция загрузит данные таблицы из объекта "actor" и заполнит таблицу заново. четвертая функция проитерировав табличку удалит аномалии по их айди из таблицы. если в конце функции удаления (перед последним end) написать local имя таблицы ={} -- то таблица будет объявлена как пустая - то есть очищена от всех данных. И теперь при новой генерации аномалии она будет заполнена новыми айди. объявление переменных без идентификатора local означает их автоматическое объявление как глобальных - то есть с областью видимости за пределами файла\функции где они объявлены. Чревато ошибками если имена глобальных переменных пересекутся. Поделиться этим сообщением Ссылка на сообщение
Garry_Galler 7 Опубликовано 24 Января 2010 Vano_Santuri Что именно то вылетает? какой скрипт? в предыдущем посте чуток ошибся - таблицу для очистки надо надо объявлять без local так как она уже объявлена - local нужно при первом объявлении писать. и все прочие переменные изначально задавай всегда как local и следи чтобы переменные не пересекались по именам там где не надо. в общем - все должно работать если все правильно сделать. так что ищи ошибки у себя. Поделиться этим сообщением Ссылка на сообщение
Garry_Galler 7 Опубликовано 24 Января 2010 (изменено) _Призрак_ А мозги включить? должно быть так local sobj = alife():create("apple",vector():set(73.594467,-0.016475,460.822327),365980,199) sobj:on_death() end Vano_Santuri адресатом ошибся :ny_ph34r_1: это я у _Призрак_ хотел спросить насчет вылета. Заполняться таблицы могут из разных скриптов - только надо знать как правильно заполнять - в какие поля таблицы что писать. Для сохранения нужно будет отдельные функции писать - для каждой таблицы свою - если конечно надо чтобы данные сохранялись. вообще можно заполнять только одну таблицу совершенннно разными данными (пример тому таблица db.storage в сталкере куда пишется огромное кол-во данных об онлайн объектах) - сделать например двумерную или трехмерную таблицу. И писать в нее из разных скриптов разные данные. Я вот сейчас использую трехмерные для большого кол-ва данных. Но работа с такими таблицами требует опыта. И сохранять их немного сложнее чем простые одномерные. Изменено 24 Января 2010 пользователем Garry_Galler Поделиться этим сообщением Ссылка на сообщение
Garry_Galler 7 Опубликовано 24 Января 2010 (изменено) Vano_Santuri а подумать? Что сохраняют и загружают функции? ТАБЛИЦУ (или точнее ее данные). Значит как эти функции связаны с таблицей? ЕЕ Именем. У меня таблица называлась morg. А у тебя как? Надо же вписывать имя Своей Таблицы. Ребята ну вы думайте прежде чем что то делать - а то вам даешь рабочие примеры, а вы их тупо копируете без адаптации под своей скрипт. Так же нельзя. На всякий случай правило: функции сохранения и загрузки должны (для удобства) находиться после всех основных функций которые эту таблицу эксплуатируют - то есть нужно следить чтобы таблица была доступна для чтения в функциях сохранения и загрузки. Само объявление таблицы лучше вынести в самый верх файла - по крайней мере она должна находиться на уровне выше функции где она впервые используется. Иначе она не будет читаться в этом скрипте\коде - и мы получаем вылет что значение переменной равно nil Удалять аргументы из скобок - это значит сделать функцию бесполезной. если вызываемая функция ничего не принимает - тогда что собственно она будет сохранять? И что загружать? Неплохо было бы подучить правила lua - почитать руководство по языку на официальном сайте (и вообще основы программирования - при таких знаниях далеко не уедешь). Я не программист - однако прежде чем начать писать какие либо серьезные скрипты для сталкера, вызубрил ВСЕ основные правила которые нужно соблюдать для грамотного написания скриптов - правила объявления переменных, области видимости переменных, области разрушения переменных, типы переменных и т.д. Вписывать вызов нужно туда куда я указал (в функции save и load, а не в update) в таком виде имя_файла.имя_функции_сохранения(packet) - в save имя_файла.имя_функции_загрузки(reader) - в load (в одно и тоже место для синхронизации чтения и сохранения) Обзор методов работы с нет пакетами есть в теме Справочник по функциям и классам. Изменено 24 Января 2010 пользователем Garry_Galler Поделиться этим сообщением Ссылка на сообщение
Garry_Galler 7 Опубликовано 25 Января 2010 (изменено) malandrinus не знал что код именно так загружается. Но все таки важность порядка мне кажется от этого не уменьшается - не видел пока ни один код, где бы переменные объявлялись где попало в файле - это ж потом черт ногу сломит в 1000 строчном файле если их где попало насовать. ...Стал разбираться с абстрактными типами данных и их конкретными воплощениями – и пришел к выводу что таблицы lua (как с числовыми, так и со строковыми ключами) как АТД это ассоциативный массив (главный признак хранение пар key=value) , а как структура данных – хэш-таблица. И если она индексируется целочисленными ключами в математическом порядке – то в таком случае ее можно называть хэш-таблицей с прямой адресацией? (для которой невозможны коллизии). Впрочем интересно мне следующее: что из себя представляют файлы конфигов с секциями? По АТД вроде как списки – но списки делятся на разные виды – односвязные (однонаправленные), двусвязные(двунаправленные), кольцевые, развернутые и т.д. В общем как вообще правильно называть структуру данных типа такой [name_list] ammo_9x18_fmj = 0.9 ammo_9x18_pmm = 0.9 ammo_9x19_pbp = 0.9 ammo_9x19_fmj = 0.9 ammo_11.43x23_hydro = 0.9 которая парсится по имени секции (в последовательности от 0 и до n-1), а нужные элементы ищутся по оверрайду(ключу)), либо номеру(индексу) строки(линии). Изменено 25 Января 2010 пользователем Garry_Galler Поделиться этим сообщением Ссылка на сообщение
Garry_Galler 7 Опубликовано 26 Января 2010 (изменено) malandrinus Отследить отдельный выстрел можно. Точнее говоря я могу отследить хит от определенного боеприпаса либо просто использование определенного боеприпаса. (не через callback.use_object - он походу только для NPC и ящиков работает - отследить скажем использование аптечки через коллбек на юзание объекта в биндере аптечки у меня не получилось, хотя может сделал че не так). А вот через две маленькие функции которые у меня есть можно отследить использование чего угодно. вчера тоже решил побаловаться методом управления физической оболочкой взял просто пример из скрипта зомби на аэс в xr_effects. local force = vector():set(0, 0, 0.02) local pshell = npc:get_physics_shell() -- вот в этом месте получаю вылет что pshell равно nil - непись определяется как онлайн объект по сиду Попробовал убить непися строчкой выше - тож самое. В скриптах игры этот метод вообще только к дверям применяется почему то. а npc:set_const_force (dir, 5000, 3) вообще никак не действует на живого NPC. PS: спасибо за ответ по таблицам. Я считаю что знания не относящиеся непосредственно к игре не менее важны для понимания скриптов игры. (и вообще для развития кругозора полезны). так что кому неинтересно пусть не читает. Я же всегда рад когда умный человек делится с другими тем что знает. Изменено 26 Января 2010 пользователем Garry_Galler Поделиться этим сообщением Ссылка на сообщение
Garry_Galler 7 Опубликовано 26 Января 2010 (изменено) malandrinus Вот эти две маленькие функции позволяют мне отслеживать все что уничтожается при использовании вот пример их использования именно для отслеживания использования определенного боеприпаса(ов) local item = nil --функция вызывается из апдейта эктора function use_item() if item and type(item) == "number" then if not level.object_by_id(item) then --hit = true --это я для отыгрыша партикла на NPC флаг включал --news_manager.send_tip(db.actor, "Использована граната", 0, "trader", 5000) --а это для проверки --в общем вот сюда и вставляем любой код для активации на момент использования вещи end item = nil end if item and type(item) == "userdata" then item = item:id() else item = nil end end --функция вызываемая из дропа function drop_item(obj) if obj:section() == 'ammo_vog-25p' or obj:section() == "ammo_vog-25" or obj:section() == "ammo_5.45x39_fmj" then item = obj --\\если наша вещь, то запомнить его userdata end end Функцию написал не я, а один очень умный человек со сталкер портала который меня многому научил - камрад singapur22 В общем мы всем порталом эту функцию дружно юзаем для всех надобностей - скажем меню скриптовые именно через нее активируем. Вопрос: сделал я все таки проверку на размер своей таблицы - вылетов больше нет. Если запись за гранью допустимого - то таблица не перезаписывается в объект. Осталось только выяснить что же в объект пишется помимо моей таблицы. Вот строки из мессиджей которые я вывел для проверки данных на экран: сообщений 57 --это общее кол-во сообщений в таблице места для записи больше нет размер таблицы 7832 --это размер который у меня считается перед сохранением текущая позиция записи 1076 --вот это что за данные записаны? сообщений 58 места для записи больше нет размер таблицы 7982 текущая позиция записи 1491 --и они ведь постоянно меняются - то больше то меньше становятся (то есть как ты понял я плюсую текущий размер таблицы и текущую позицию записи (получаемую через packet:w_tell() ) а потом перед сохранением проверяю не больше ли это чем 8192 байта. ) Насчет storage - она содержит все совокупность данных по NPC которые находятся в онлайне - можно определить все - вплоть до текущей анимации, патрульного пути, секции логики, активной схемы и т.д. А вот скажем артефактов и аномалий (как и по видимому прочих объектов) она не содержит. вот часть кода из моего скрипта который вытаскивает из storage разную инфу function InfoNpc() local aitem, count_inv, count_mag, cond, scheme, sec_logic, act_section local str = "" for k, v in pairs (db.storage) do local obj = level.object_by_id(k) --if (obj and IsStalker(obj) and obj:id()~= 0) then --проверка IsStalker исключает Сидоровича и вероятно вообще всех торговцев -- поэтому используем другую if obj and (get_clsid(obj) == clsid.script_stalker or get_clsid(obj)== clsid.script_trader) then --определяем активную схему - работу if v.active_scheme then scheme = v.active_scheme else scheme ="нет" end --определяем секцию логики if v.section_logic then sec_logic = v.section_logic else sec_logic ="нет" end --определяем активную секцию логики if v.active_section then act_section = v.active_section else act_section ="нет" end Изменено 26 Января 2010 пользователем Garry_Galler Поделиться этим сообщением Ссылка на сообщение
Garry_Galler 7 Опубликовано 26 Января 2010 (изменено) _Призрак_ активация только через диалог - после любой фразы поправленный вариант function set_bandit(obj1, obj2) if obj1:id() == db.actor:id() then obj2:set_character_community("bandit", 0, 0) else obj1:set_character_community("bandit", 0, 0) end end айди у NPC никогда не будет равным другому так как назначается ему в момент спавна автоматически движком. А вот сид задается в произвольном порядке (в файле allspawn) - и регистрируется в файле гейм стори идс - вот там смотри и свободен он или нет. Изменено 27 Января 2010 пользователем Garry_Galler Поделиться этим сообщением Ссылка на сообщение
Garry_Galler 7 Опубликовано 26 Января 2010 (изменено) malandrinus скрипт на использование работает не на дроп вещи - то есть если вещь просто выкинута то скрипт не срабатывает. А вот если ее именно использовать - выстрелить патрон, кинуть гранату(чтобы взовалась), скушать аптечку или антриад - вот тогда и срабатывает. насчет статьи storage - я подумаю. просто у нас один человек уже вроде как пишет на эту тему, но если ему будет некогда - тогда я напишу. Guzerus во первых у тебя для эктора, во вторых у меня как ты мог заметить функция универсальная - не требующая определять на чью фразу ставить ее активацию. а для функций которые активируются через диалог с передачей юзердаты объектов обычно это очень важная вещь. Не на тот тэг поставил и получил вылет или не то действие. Изменено 26 Января 2010 пользователем Garry_Galler Поделиться этим сообщением Ссылка на сообщение
Garry_Galler 7 Опубликовано 26 Января 2010 (изменено) Насчет патронов ошибся - видимо в прошлый раз не до конца все проверил. действительно только на расход пачки срабатывает. НО выход есть: делаем оружие двухзарядным - далее определяем активную вещь у эктора - если наш ствол, то определяем сколько патронов в стволе далее если патрона 2 либо 0, то значит еще не стреляли, если один то стреляли. типа так local activ_item = db.actor:active_item() if activ_item and activ_item:section() =="наш ствол" then --кол-во патронов в магазине активного ствола count_mag = activ_item:get_ammo_in_magazine() if (count_mag==2 or count_mag==0) then одно действие else другое действие и все это дело апдейтим. PS: проверил все отслеживается. правда есть заморочки с флагами для апдейта, чтобы действие только один раз выполнялось но это вполне решаемо. кстати таким макаром можно отследить любую последовательность выстрелов (или нажатий на ЛКМ) - пишем условия: если патронов 30 или 0 то ничего не делаем, также если патронов 29 то одно действие, также если патронов 28 - другое и т.д. malandrinus А где пишет? на stalker_portal max_max_08 рестриктор это такая зона ограниченная определённым периметром- может быть в виде шара(сферы) либо куба - то есть можно задать не только ширину- длину, но и высоту. Соответственно рестриктору обычно пишется логика- состоящая из двух оверрайдов- эктор в зоне и эктор вне зоны (то ж самое есть и для NPC).(читай об этом статьи по логике). В каждую секцию можно поставить активацию любой функции (эффекта) которая произойдет если эктор зайдет\выйдет в зону\из зоны Через скрипт спавнится - но нужен скрипт читающий параметры рестриктора из нетпакета. Если очень нужно - то зайди на stalker-portal вот в эту тему _http://www.stalker-portal.ru/forums.php?m=topics&s=34 и в топике вопросы и ответы найди камрада singapur22 - в его журнале этот скрипт есть. [logic] active = sr_idle [sr_idle] on_actor_inside = sr_idle@1 %=run_postprocess(deadcity_wake:1777:false)% -- на вход в зону запускаем постпроцесс [sr_idle@1] on_actor_outside = sr_idle@nil --на выход из зоны уничтожаем рестриктор [sr_idle@nil] Изменено 27 Января 2010 пользователем Garry_Galler Поделиться этим сообщением Ссылка на сообщение
Garry_Galler 7 Опубликовано 29 Января 2010 _Призрак_ сделать активацию чего угодно - хоть скрипта хоть выдачи поршня - при обыске трупа можно через коллбек на использование объекта. в файле xr_motivator есть такая функция function motivator_binder:use_callback(obj, who) находишь там строчку self.treasure_processed = true - это в самом конце и после нее вписываешь что тебе надо. можно например активацию функции имя_файла.имя_функции() или выдачу поршня db.actor:give_info_portion("info") сделать такой же коллбек на обыска игрового тайника тоже вроде можно, но придется делать проверку на сид тайника. сиды тайников есть в файле game_story_ids - соответственно пишем функцию которая будет перебирать сиды всех тайников и сравнивать их с сидом объекта который юзается игроком при обыске. Точно не уверен но вроде коллбек на юзание должен работать для тайников. кстати вот так можно выдать Меченому сразу все тайники игры. function name_secret() local ini = ini_file("misc\\treasure_manager.ltx") if ini:section_exist("list") then local n = ini:line_count("list") local id, value = "","" for i=0,n-1 do result, id, value= ini:r_line("list",i,"","") treasure_manager.get_treasure_manager():give_treasure(tostring(id)) end end end Поделиться этим сообщением Ссылка на сообщение
Garry_Galler 7 Опубликовано 29 Января 2010 По моему кому то надо статьи по логике перечесть оверрайда combat_ignor не существует есть combat_ignore оверрайда danger ignor = always так же не существует есть combat_ignore_cond = {условие} пишется в той секции логики в которой нужно чтобы NPC игнорировал бой можно так combat_ignore_cond = always ; игнорировать бой всегда далее существует целый комплекс оверрайдов для секции danger=danger_condition которые можно перенастроить и перебить дефолт. [danger_condition] ignore_distance = дистанция игнора опасности ignore_distance_hit = дистанция игнора хита danger_inertion_time = время через которое NPC забудет про опасность и т.д. настройка логики часть 3. Поделиться этим сообщением Ссылка на сообщение
Garry_Galler 7 Опубликовано 29 Января 2010 (изменено) Ray kk строковой ключ = тип патронов - например ammo_9x18 vv - значение = возвращает таблицы второго уровня с именами стволов заходим в таблицы vv получаем k - ключ - индекс от 1 и далее (по умолчанию таблицы в lua индексируются в мат. порядке от единицы) v - значение - имя ствола name это аргумент который принимает функция - то бишь имя ствола соответственно через функцию string.find(name,v) сравнивается имя принятого параметра (ствол x) и значение v которое возвращает имена стволов в порядке итерации таблицы. если true то переменной ammo_type присваивается значение ключа kk - тип патронов который соответствует этому стволу не успел Monnoroch опередил а мне кстати наоборот после легкого lua тяжеловато Си шарп осваивать...точки с запятой ставить после каждой инструкции - это ж скока терпения и внимательности надо иметь SCRIPT файл script_sound в папке misc имена звуков в квадратных скобках - берешь любое которое нужно (что за звук смотри в папке саундс - путь в указывается в самой секции звука) имя звука надо брать без суффикса seq или rnd например есть секция [esc_wolf_radio_1_seq] -имя звука esc_wolf_radio_1 stalker= 0,scenario\escape\wolf_to_rangers_1 --путь до звука в папке саундс брать звуки можно не только отсюда. также можно самому создавать свои секции - но их надо вписывать в файл sound_theme.script - в основную таблицу. Изменено 29 Января 2010 пользователем Garry_Galler Поделиться этим сообщением Ссылка на сообщение
Garry_Galler 7 Опубликовано 30 Января 2010 (изменено) malandrinus А имеет смысл конвертация строк в числовые коды ASCII? может ли тут быть выигрыш по уменьшению размера данных? просто я так прикинул - кол-во символов то (а значит байт) гораздо больше получается...тогда какой резон? function convert_text() local text = "мой дядя самых честных правил, когда не в шутку занемог" local n = string.len(text) local t ={} for i =1, n do t = string.byte(text,i) end print(unpack(t)) print(string.char(unpack(t))) end Изменено 30 Января 2010 пользователем Garry_Galler Поделиться этим сообщением Ссылка на сообщение
Garry_Galler 7 Опубликовано 30 Января 2010 SCRIPT пишешь логику в которой например две секции ремарок- одна базовая - в которой непись будет отыгрывать обычную анимацию - например просто тупо стоять anim = wait в другой ремарке - нужная тебе анимация. Для переключения из одной секции в другую пишешь в первую условие on_info ={+твой инфопоршень} remark@new после получения указанного поршня непись переключится на remark@new а в ней отыграют анимацию которая будет сюда вписана. смотри тему уроки по модостроению - там в посте Gruber'а есть мой урок по стоячим-сидячим анимациям NPC, который я выкладывал на Инсайд вики (под ником erlik) Поделиться этим сообщением Ссылка на сообщение
Garry_Galler 7 Опубликовано 30 Января 2010 malandrinus спасибо за элегантный способ :ny_ph34r_1: но возник вопрос - а какой прок тогда вообще от этой функции - string.byte() ? Поделиться этим сообщением Ссылка на сообщение
Garry_Galler 7 Опубликовано 1 Февраля 2010 (изменено) Kirag Допустим, с 30 патронов дошли до 20, десяток действий сделали. А потом игроку приперло нажать "разрядить оружие", как обычный автомат. И что получим в результате? Обрыв последовательности действий... В результате - простор для глюков... В качестве доказательства что не все так сложно сделал скриптовую газовую шмалялку на основе ПБ (выстрелы само собой холостые). Отслеживаются все выстрелы кроме последнего. Но это на выбор - либо отслеживаем и его, но тогда убираем защиту от сбоя при нештатной разрядке магазина либо наоборот. Защита от дозарядки при неполной разрядке магазина есть. Таймер нужен только в моем случае - так как проверку расстояния надо было как то останавливать, иначе она будет длится бесконечно пока условие не выполнится. Соответственно вместо одного действия на все выстрелы вполне можно расписать серию действий - на каждый выстрел индивидуально. local ch=1 local magazin=10 local time_delay =0 local action = false function weapon() local activ_item = db.actor:active_item() if activ_item and activ_item:section() =="wpn_pb" then local count_mag = activ_item:get_ammo_in_magazine() if (count_mag == 0 or count_mag==10) then ch=1 end if (magazin - count_mag==ch) then action = true ch=ch+1 time_delay = time_global()+3000 end if action then if (time_global()>time_delay) then action = false time_delay= 0 else for k, v in pairs (db.storage) do local obj = level.object_by_id(k) if (obj and get_clsid(obj) == clsid.script_stalker) then if obj:position():distance_to_sqr(db.actor:position()) < 12 then obj:kill(obj) end end end end end end end Изменено 1 Февраля 2010 пользователем Garry_Galler Поделиться этим сообщением Ссылка на сообщение
Garry_Galler 7 Опубликовано 1 Февраля 2010 Monnoroch думаю можно. просто ставим активацию функции спавна телепорта на любой выстрел - а в координатах спавна указываем нужное смещение по вектору x или z относительно ГГ. Либо по радиусу от ГГ. Поделиться этим сообщением Ссылка на сообщение