Ничем, даже более того - это не правильно. Просто я сейчас на работе над VBScript чахну, а в нём "не равно" пишется именно так "<>". В Lua, конечно же это не прокатит - нужно поставить "~=".
Честно говоря, я не знаю способа, как работать с файлами в тч (про другие ничего сказать не могу) без учёта секций. Можно было бы попробовать "внешним" способом - в любом языке программирования проверять корректность нужных вам данных, а потом запускать сам сталкер (вроде бы, так сделано в NLC). Но тогда надо как-то запретить сам запуск игры напрямую, через XR_3DA.exe. Или позволять запускать, но отрубать все клавиши.
Способ совсем уж бредовый, но если совсем уж очень требуется... Создаём exe-шник, к примеру, на C++, который и проверяет корректность всех нужных вам данных (его и будет запускать пользователь). Этот exe-шник ещё и изменяет какое-то из значений в user.ltx и запускает игру. В главном меню (скрипт ui_main_menu.script) проверяем то самое значение из user.ltx. Если игру запускал exe-шник, а не пользователь, то всё путём, все кнопки работают. А если юзер запустил XR_3DA.exe, т.е. значение в user.ltx не изменилось, то блокировать все кнопки загрузки и пр. В общем, трудностей можно создать для "нехорошего" пользователя очень много, другой вопрос, нужно ли это, и стоит ли потраченного времени. Потому что почти любую защиту можно обойти. Даже здесь - пользователю можно будет просто загружаться через консоль
DukeKAn, напрямую у меня игру и так не запустить. Любой выход в главное меню обернётся полным фейлом. А разберётся там далеко не каждый, сложная система им. камрада Шокера. Но игра уже и так запускается через лаунчер, исходника которого у меня нет, к сожалению. Ладно, хотя бы вес в систем.лтх проверяет без проблем, с актёром только фигня такая.
Спасибо за статью конечно но я почти перестал создавать скрипты Кстати кому надо разборы секций в bind_stalker.scripts смотрите в спойлере
--что делают функции из бинд сталкер function actor_binder:net_spawn(data) --функция запускается при переходе на новую локацию, при загрузке сохранения. end
function actor_binder:update(delta) --функция запускается постоянно, т.е. если вписать какую либо проверку, то проверяться будет постоянно. end
--Общее local npc --создается локальная переменная с именем npc (при обращении к ней, она существует, но равна nil) --пример local active_item = db.actor:item_in_slot(db.actor:active_slot()) -- local active_item (локальная переменная с именем active_item) = db.actor:(у кого проверяем,)item_in_slot(предмет в слоте(в скобках номер слота или условие))(db.actor:active_slot()(активный слот, т.е. если ДЕРЖИМ в руках пистолет то db.actor:active_slot равно 1 если автомат то 2) в итоге локальная active_item равняется обьекту который держим в руках --active_item это обьект, который в онлайне, если нам нужно проверить его секцию то делаем так local active_item = db.actor:item_in_slot(db.actor:active_slot()) if active_item:section() == "wpn_ak74" then --if(если) active_item:section() (секция обьекта active_item) == (равна) "wpn_ak74" (секция калаша) then(то) --деиствие end --у обьекта можно многое проверить, например группировку, имя, цену, состояние и пр.
math.random(120,140) -- принимает рандомное число в даном пределе. -- т.е amk.start_timer("taimer",math.random(120,140)) будет выглядить примерно так amk.start_timer("taimer",120) где число 120 будет выбано рандомно local obj=alife():create("секция_обьекта",vector():set(-81.4560,-0.2423,157.2334),186914,163) --спавнит обьект и приравнивает его к локальной obj --тоесть после спавна с обьектом можно проделать какие либо действия(нанести хит, изменить группировку, заспавнить ему оружие\предмет, изменить состояние(кондицию)
--функция спавна с чтением\записью нэт пакета(требуется АМК) function spawn_burer() local obj = alife():create("burer_normal",vector():set(73.2404251098633,-0.0141735374927521,28.42),10537,2430) --спавним бюррера, и назначаем ему локальную obj local params=amk.read_monster_params(obj) --читаем параметры (обьекта) obj params.custom="[logic]\ncfg = scripts\\new\\burer1.ltx" --указываем путь до логики params.sid=9800 --назначаем сид, что-то типа айди(индивидуальный номер) params.health = 0 --назначаем значение здоровья, 0-мертв, 1-как новенький. amk.write_monster_params(params,obj) --записываем новые параметры (обьекту) obj end --даем предмет, вызывается из диалога function give_scope(first_speaker, second_speaker) --в скобках два обьекта которые ведут диалог, один из них актор другой нпс if db.actor and db.actor:id() == first_speaker:id() then --если айди актора и first_speaker РАВНЫ то.. actor = first_speaker --локальная actor принимает значение first_speaker npc = second_speaker --а локальная npc принимает значение second_speaker else --иначе (если айди актора и first_speaker НЕ РАВНЫ) actor = second_speaker --наоборот локальная actor принимает значение second_speaker npc = first_speaker --а локальная npc принимает значение first_speaker end dialogs.relocate_item_section(actor, "wpn_addon_scope", "in") --даем оптику на калаш актору,(если указать npc до дадим тому с кем говорим) "in" даем, "out" забираем dialogs.relocate_item_section(actor, "wpn_addon_grenade_launcher", "in") dialogs.relocate_item_section(actor, "wpn_ak74", "in") end -- удаляем непися по сиду function del_oleg_1() local sim = alife() local se_obj = sim:story_object(5004) --сид обьекта которого удаляем if se_obj then --если se_obj равно true т.е. существует т.е. не равно nil sim:release(se_obj, true) -- собственно удаление end end
function daem_patroni(first_speaker, second_speaker) if sak.have_item_namber("wpn_abakan", 1) or --если в рюкзаке есть абакан или (sak. это файл, have_item_namber это функция ("wpn_abakan") это строка которая передается в функцию have_item_namber, а функция возвращает true или false ) sak.have_item_namber("wpn_groza_m1", 1) or --гроза или sak.have_item_namber("wpn_ak74", 1) or --ак 74 или sak.have_item_namber("wpn_ak74u", 1) then --ак 74у то... dialogs.relocate_item_section(second_speaker, "ammo_5.45x39_ap", "in") --даем патроны ammo_5.45x39_ap second_speaker-у (тоесть гг) dialogs.relocate_item_section(second_speaker, "ammo_5.45x39_ap", "in") dialogs.relocate_item_section(second_speaker, "ammo_5.45x39_ap", "in") dialogs.relocate_item_section(second_speaker, "ammo_5.45x39_ap", "in") else -- иначе (если перечисленных стволов в юкзаке нет) dialogs.relocate_item_section(second_speaker, "ammo_5.56x45_ss190", "in")--даем патроны ammo_5.56x45_ss190 second_speaker-у (тоесть гг) dialogs.relocate_item_section(second_speaker, "ammo_5.56x45_ss190", "in") dialogs.relocate_item_section(second_speaker, "ammo_5.56x45_ss190", "in") dialogs.relocate_item_section(second_speaker, "ammo_5.56x45_ss190", "in") end -- закрывающий тэг для if (для else end не нужен) end -- закрывающий тэг для function
if has_alife_info("инфо1") and has_alife_info("инфо2") and has_alife_info("инфо3") then --если выданы ВСЕ инфопоршны то... end if has_alife_info("инфо1") or has_alife_info("инфо2") or has_alife_info("инфо3") then --если выдан хоть один инфопоршнен то... end if (has_alife_info("инфо1") or has_alife_info("инфо2")) and not has_alife_info("инфо3") then --если выданы инфо 1 или 2, а инфо 3 отсутствует (в скобках проверяется первым, как в алгебре)... end --проверка для квеста function xabar_in_actor() return db.actor:object("pda_wolf_drug") ~= nil --return(вернуть) true(правда) если pda_wolf_drug не равен nil т.е. находится в рюкзаке end
--различные проверки if level.name()=="l07_military" then --если актор находится на локации l07_military (военные склады) то... --деиствие end
if has_alife_info("имя инфо") then --проверить выдан ли поршен --действие end obj:cost() --цена обьекта --Как использовать? if obj:cost() > 1000 then -- если цена обьекта больше 1000 то.. --действие end --или local cost = obj:cost() --переменная cost принимает значение цены у обьекта(obj)
obj:condition() --состояние обьекта 1.0-новый obj:active_slot() --активный предмет, тот который сейчас держит obj, obj-ом может быть db.actor local rank = ranks.get_obj_rank_name(db.actor) --проверим ранг local dist = obj:position():distance_to(db.actor:position()) -- dist это растояние в метрах между obj и db.actor db.actor:eat(medkit) --использовать(схавать) предмет, medkit это ни секция, а обьект т.е. кастомдата обьекта npc:see(db.actor) --нпс видит актора obj:get_ammo_in_magazine() --кол-во патронов в магазине alife():release(alife():object(obj:id()),true) -- удаляем obj obj:add_animation("анимация") --проиграть анимацию у нпс "udar_0" = Удар кулаком "prisluh_1_idle_1" = одной рукой пушку вверх "prisluh_0_idle_1" = одной рукой на земле "prisluh_3_idle_1" = сидя, двумя руками пушка накрест "wounded_idle_0" = сидя, тошнит "waunded_1_idle_0" = калачик "wounded_2_idle_0" = лежит, раненый "wounded_3_idle_0" = лежит, двумя руками держась за живот local number = tonumber(number_1) --конвертируем number_1 в число number local string = tostring(string) --конвертируем string в строку string --способы получения обьектов local obj = level_object_by_sid(6) -- по сиду из алл спавна. Это сид волка. local obj = alife():create("секция",vector():set(x,y,z)game_vertex,level_vertex) --при спавне скриптом. local obj = db.actor:item_in_slot(number) --по предмету в слоте,number - это номер слота local sobj = alife():object(npc:id()) --получение серверного обьекта по айди --[[ [Слот_1]=[пистолеты] [Слот_2]=[автоматы] [Слот_3]=[гранаты] [Слот_4]=[бинокль] [Слот_5]=[болт] [Слот_6]=[бронекостюм] [Слот_7]=[пда] [Слот_8]=[детектор] [Слот_9]=[фонарик] ]] npc:relation(obj) == game_object.neutral --отношение npc к obj запишем нейтральное или game_object.friend дружеское obj:name() -- имя obj npc:object("medkit") --проверим наличие аптечки у npc npc:character_community() -- групировка npc npc:character_name() npc:character_reputation() npc:character_rank() npc:profile_name() db.actor:set_character_rank(650) --запишем ранг актору -- нанесение хита обьекту local h = hit() h.power = 10000 --сила удара h.impulse = 1 --импульс h.draftsman = obj h.type = hit.fire_wound --тип урона h.direction = db.actor:position():sub(obj:position()) --откуда пришел удар(имеется в виду направление) h:bone("pelvis") -- по какой кости даем пинка obj:hit(h) --собственно сам удар по obj --фиксация обьекта, function name() local obj=alife():create("wpn_ak74",vector():set(268.300,12.157,23.788),543524,138) --спавним калаш и присваеваем ему переменную obj if obj then --если obj существует то... local pshell = obj:get_physics_shell() --получаем оболочку обьекта if pshell then --если получили то... local element = pshell:get_element_by_order(0) --получаем елемент оболочки if element then --если получили то... element:fix() --фиксируем елемент оболочки end end end end --спавн рюкзака и спавн в него предмета local obj = alife():create("section_treasure", vector():set(-347.58, -22.4, 194.8), 8132, 1839) --спавним тайник if obj then alife():create("имя секции", vector():set(-347.58, -22.4, 194.8), 8132, 1839, obj.id) -- спавним (В ОФФЛАЙНЕ) в тайник предмет, ловим по айди end --если в секции есть такая строка то истина if string.find(obj:section(), "boar") then --деиствие end --перебор обьектов for a=1,65534 do --крутим цикл local obj = alife():object(a) --каждый обьект (a) принимает значение obj if obj and IsMonster(obj) then --если обьект монстр(или IsStalker(obj) - сталкер) --действие end end --если пушка в руках - прячем, а то тащить неудобно if npc:weapon_unstrapped() then npc:set_item(object.idle,nil) end -- получим активную схему local actsch=db.storage[npc:id()].active_scheme --если зашли в эти координаты то кирдык local pos = db.actor:position() if pos.z>65 and pos.x>350 and pos.x<410 then db.actor:kill(db.actor) end --взято из OGSE -- Отметка укрытий на карте function mark_hideouts() for k,v in pairs(ogsm_respawn.restrictor_list) do local obj = level.object_by_id(v.id) level.map_add_object_spot(obj:id(), "red_location", obj:name()) end end
-- Удаление укрытий function del_hideouts() for k,v in pairs(ogsm_respawn.restrictor_list) do alife():release(v, true) end end
Скрипты дверей(всё ясно и понятно)
Покажу вам на примере, как открыть дверь в саркофаге без дешифра) мы просто сделаем дверь открытой по умолчанию, этот трюк можно использовать в любом направлении, в том числе и для новых квестов Идём в gamedata\config\scripts и ищем скрипт нужной двери или объекта, нам нужна дверь в саркофаге и это sar_door.ltx Вот вам скрипт с моими комментариями, мои комментарии после символа ;, в вашем скрипте они не нужны, так что удалите их если будете копировать отсюда...
[logic] ;Основное действие active = ph_door@locked ; При нажатии кнопки "Действия" выполняется скрипт [ph_door@locked]
[ph_door@locked] ; То что выполняется сейчас locked = true ; Закрыто на замок, значение правда ("Закрыто", при нажатии на кнопку действия ничего не произойдёт) closed = true ; Прикрыта, правда ("Прикрыта", при нажатии на кнопку действия дверь октроется) tip_open = tip_door_coded ; Всплывающая подсказка "Дверь закодирована" on_info = {=actor_has_decoder} ph_door@coded ; При нажатии на кнопку действия идёт проверка есть ли декодер
[ph_door@coded] ; Если есть декодер то... locked = true ;Закрыто, правда closed = true ;Прикрыто, правда tip_open = tip_door_decode ; Всплывающая подсказка "Декодировать" on_info = {!actor_has_decoder} ph_door@locked on_use = ph_door@decoding %+sar_access_decoding% ; При начале декодирования, пошёл процесс декодирования и выполняется скрипт sar_access_decoding
[ph_door@decoding] ; В процессе декодирования locked = true closed = true tip_open = tip_door_decoding on_info = {+sar_finish_decoding} ph_door@unlocked ; Завершение скрипта sar_finish_decoding и выполнение ph_door@unlocked
[ph_door@unlocked] ; Дверь разкодирована и открыта locked = false closed = false show_tips = false
Если мы хотим увидеть правдивые концовки, но мы уже в саркофаге и у нас нет дешифра, то мы просто можем изменить везде locked = false на true closed = false на true И в зависимости что вам надо и где можете менять и изменять, тут всё предельно просто и понятно...
Скрипт спавна трупа без использования функции AMK
Пишем вот такую простенькую функцию:
function [имя функции] () local obj= alife():create("имя из spawn_sections",vector():set(x,y,z),level_vertex,game_vertex) obj:on_death() end
На примере - Ученый, близ упавшего вертолета, на армейких складах:
function tester() local obj= alife():create("yan_ecolog_respawn_1",vector():set(-38.981,-17.916,355.841),273797,1816) obj:on_death() end
local obj=alife():create("секция_обьекта",vector():set(-81.4560,-0.2423,157.2334),186914,163) --спавнит обьект и приравнивает его к локальной obj --тоесть после спавна с обьектом можно проделать какие либо действия(нанести хит, изменить группировку, заспавнить ему оружие\предмет, изменить состояние(кондицию)
Ну-ну. Интересно посмотреть, как ты будешь серверному объекту изменять состояние или изменять группировку. create возвращает серверный объект, поэтому пример ниже с фиксацией кости работать не будет. Причина таже get_phisycs_shell - это метод клиентского объекта.
ЦитатаPro100The-Best ()
local string = tostring(string) --конвертируем string в строку string
Зачёт! Строку в строку конвертировать...
P.S. Оформление в край отвратительное.
Сообщение отредактировал BozKurt - Вторник, 07.10.2014, 11:53
Я так посмотрел, уроки получились мягко говоря не для новичков. А в стриме можно прямо с основ начать - создание файла скрипта, значение переменных, функций, таблиц в Lua и тут же запускать сталк., показывать. А уж к концу, можно показать, как связаны скрипты с конфигами, с логикой, а то часто бывает непонимание, чем же вообще скриптеры занимаются.
Добавлено (24.12.2014, 15:23) --------------------------------------------- Pro100The-Best, Есть у меня этот файлик-шпаргалка, да ещё и сильно расширенный. Вот только, как заметил BozKurt, ошибок там навалом, и рекомендовать кому-то я его не стал бы, только если знаешь как делать, но забыл самую мелочь - точное имя метода, или порядок аргументов.
Лучше возьмите литературу по Lua, C, C++, почитайте месяц-другой, и разберетесь как и что устроено.
Вообще-то человеку, который хочет разобраться со скриптами, вовсе не нужно лезть в такие дебри, как С и С++. Исключение - необходимость править движок. Но за пару месяцев с этими языками никак не разберёшься до такого уровня. А заходить в тему, чтобы показать, как вы хорошо разбираетесь в языках, и как их надо учить - не надо. Есть чем поделиться - делитесь, нужно спросить - спрашивайте. Нет - проходите мимо.
ЦитатаScriptMaker ()
Если будем спавнить вблизи ГГ, то есть коллбек на выход в онлайн, с помощью него можно без нет пакетов изменить группировку.
Есть - показывайте код. Что за коллбэк, как использовать для смены группировки. Почему этот подход лучше, чем просто (если в онлайне) получить клиентский объект с помощью функции
ScriptMaker, речь шла именно про серверный объект, который возвращает метод create, а не о способе изменить группировку онлайновому объекту, да ещё и нет-пакетами.
DukeKAn, способ хорош тем, что не заставляет выдумывать велосипеды с поимкой онлайнового объекта. Метод create возвращает серверный объект, а клиентский становится доступен только на следующем апдейте. Колбек client_spawn_manager срабатывает как раз тогда, когда клиентский объект становится доступен. Пример очень простой:
local OnObjectExitOnline = function (objectId, gameObject) gameObject:set_condition(0.8) end
Где в функции OnObjectExitOnline, objectId - id переданного объекта, gameObject - уже клиентский объект.
Добавлено (03.01.2015, 15:00) --------------------------------------------- 6poHR777, для чистого Lua 5.1 - вот: https://yadi.sk/d/nkygbzVLdm928 . С вопросами о проблемах установки и запуска - в лс.
Сообщение отредактировал BozKurt - Суббота, 03.01.2015, 15:01
DukeKAn, я в таком случае не вижу смысла вообще человеку лезть в скрипты. Метод тыка - плохой метод. Куда мне заходить, и что мне делать - я решу сам, хорошо? Я тебе пока не мешаю писать статьи по типу 52 поста.
ЦитатаDukeKAn ()
Почему этот подход лучше, чем просто (если в онлайне) получить клиентский объект с помощью функции
Выше читай.
BozKurt, ладно, я подумал, что не помешает указать и на коллбек выхода в онлайн, т.к. видно о нем немногие знают, а применение (даже не повсеместное) я редко где видел.