Как менять скрипты в сталкер
Вот IG-2007 на оф.форуме осенью прошлого года написал такой тутор по гулагам. Здесь показана работа в гулаге для сталкера. Днем он гуляет (walker), а ночью сидит у костра (kamp).
Многие модмейкеры, которые создают апгрейд оружия, да и вообще новое оружие, в особенности улучшенное, сталкиваются с проблемой переполнения количества байт информации в секции файла mp_ranks.ltx. Я также не исключение, при составлении скрипта апгрейда оружия все шло отлично, тест также прошел на 5, но когда апгрейд стал подходить к концу, то есть когда необходимо было прописать все апгрейды оружия в ранги, произошел вылет. А прописал всего апгрейд только для одного оружия. Но из всякой проблемы можно найти логический выход. Предлагаю свой, он был разработан не только мной но и моим коллегой spark95, на базе проекта S.I.P. Этот метод называется «рекрит» (REcreate) работает без вылетов на 99%.
Как менять скрипты в сталкер
Это, что бы проверять наличие НЕСКОЛЬКИХ и РАЗНЫХ предметов в рюкзаке ГГ
Это, что бы отдавать в НУЖНОМ количестве НУЖНЫЕ предметы.
Вставляется в скриптовый файл и оформляется по типу:
Есть ли ДВЕ ammo_gauss - проверка
= false
end
Проверка на количество разных предметов
Отдача "этих" предметов без появления их в "торговле" оппонента - тупое отбирание их у ГГ.
ЗЫ. Ещё раз НАСТОЯТЕЛЬНО - эти "универсалки" должны "лежать" в конкретном скриптовом файле и все ссылки на них должны ТАК-ЖЕ "обзываться" по соответствию.
Вынос какой либо информации в другой файл (в нашем случае, имеем например кучу текстов, которые занимают кучу места в файле, тормозят и мешают ориентироваться в нем):
Создаем новый файл, например all_txt.script и пишем в него таблицу со всеми нужными текстами:Ниже таблицы, пишем незатейливую ф-ию, которая будет возвращать нашу таблицу:
ВАЖНО! Имя функции и имя таблицы в файле, обязательно должны быть разными!
Затем в другом файле, где юзаем наши тексты объявляем нашу таблицу:
Не соглашусь, Саша. Удалять можно хоть стоя рядом, а вот то что я упустил, и что действительно важно: эту функцию нельзя вызывать из диалога с НПС которого пытаемся удалить.
Правильное уточнение, для этого тут и "собрались".
Я же отписал "свои впечатления" от конкретной ситуации с удалением НПС в ходе диалога с ним. Вот и "разобрали" некоторые тонкости. Ну. А про "остальное" как-то упустил, виноватьььь
"1.0" тута уровень громкости. Он не всегда эффективен, так что можно вызывать сразу двойную функцию - сразу будет слышно повышение громкости, хотя пока не известно, как это сказывается на "внутренних процессах", но иногда "спасает", если "общий фон" глушит всё и надо акцентировать некоторые звуки.
Не стоит воспринимать мои же "мысли и знания", как "что-то этакое". Пробуйте, это работает. Я сужу не, как спец и программер, а как "представитель группировки от сохи" А ОНО и в правду, "работает". Есть куча литературы по языку ЛУА, там много полезного, хотя и полно "дезинформации" - я только после года "возни" и отмахиваний от "первоисточников" всё же ОПЯТЬ прихожу к выводу, что УЧИТЬСЯ надо сначала "азбуке", а потом уже "терзать" внешние эффекты. Ну. У нас же всегда - "хочется быстрее и всего". А когда "влезешь", то захочется "ещё больше". А ТАМ, извините, ЗНАТЬ надо и НИкТО не подскажет - "сам плавай".
Ну если перевести НПС сначала в оффлайн, то с ним можно кучу всяких непотребностей сделать
В том числе и удаление. Однако я пока не видел нормальной вменяемой ф-ии на перевод.
ЗЫ: Либо можно поступить как например я делал с телепортами - т.е при спавне ТП пишем его на пстор актора, затем при удалении обращаемся туда же и удаляем. Т.е ТП удаляется в онлайне и ты можешь в это время на него даже смотреть.
ЗЗЫ: На НПС я этот способ не пробовал - не было пока нужды в удалении
Если я правильно помню, то возможность перевода НПС в оффлайн через отдельное поле логики появилась только в ЗП. В логике это выглядит так:
Т.е. здесь видно, что поддерживается кондлист и выполнение "эффектов".
Соответственно в xr_logic.script появилась и часть кода, обрабатывающая это поле:
В ТЧ или ЧН такой поддержки нет, но наверное можно и сделать, я не знаю…. А можно поступить проще, ну например перевести НПС в оффлайн по ранению:
И в конце логики секцию хита:
Чтобы он действительно туда пошел, открываем xr_effects.script и добавляем туда функцию:
Всё. Запускаем игру, получаем от Волка ПМ, стреляем в ногу (главное ранить, а не убить) и Волк исчез, только метка осталась. Таким образом можно переводить НПС в оффлайн с любой секции его логики.
Теперь понятна разгадка из ТТ 2. Когда ты стреляешь в НПС, а из него типа лезут жуки
Спасибо за пример!
Хм, а если по сиду? Без прописки логики?
Надо будет попробовать завтра.
Удаление любого онлайнового/оффлайнового объекта из игры. Во время удаления можно хоть плясать рядом с ним:
Само удаление, например нескольких сталкеров/монстров:
remove_obj - ф-ия в которую передаем данные для удаления.
Если же удаляем кого то одного - цикл и таблица не нужны.
Удаление любого онлайнового/оффлайнового объекта из игры. Во время удаления можно хоть плясать рядом с ним:
Ф-ия которая будет все делать:
Код
function remove_obj(name)
local obj
for a=1,65535 do
obj = alife():object(a)
if obj and string.find(obj:name(),name) then
alife():release(obj, true)
end
end
end
Само удаление, например нескольких сталкеров/монстров:
Код
function remove_freaks()
local tbl_remove = < "bloodsucker_1", "bloodsucker_2">
for _, v in pairs (tbl_remove) do
remove_obj(v)
end
end
Как менять скрипты в сталкер
Начнём уроки.
1)Создадим свой my.scripts и поместим его в папку scrips . Откроем с помощью НотПада и настроим подсветку.
2) Внутри файла-скрипта должны содержаться только КОД скрипта и ваши ЗАКОМЕНТИРОВАННЫе пометки. Если будет лишний текст, т.е какие-то знаки и слова, то будет вылет на этот скрипт. Так как код игры полностью собирает весь скрипт в стек и выбирает только то, что вы задали, но если будет мусор, то игра не воспримет код.
3)Архитектур. Для создания функций нужны лишь знания синтаксиса и игровые методы и глобальные функции(которые записаны в движке) можете почитать lua_help.scrip , но я советую посетить тему на АМК . Там собраны все методы, классы и полное их описание.
4) Функция. Это то, что будет делать игра.
Любая функция начинается со слов
function my_function()
.
end
И заканчивается тегом end . Этот тег означает конец функции, сравнения, он закрывающий и обязателен. Я советую при составлении функций , чтобы не забыть чего-нибудь, писать скелет извне, т.е сначала функция, потом закрывающий тег, и по нарастающей во внутрь.
() -Обязательный элемент. Позже расскажу как передавать переменные через этот тег.Между окончание функции и этим тегом ПРОБЕЛА НЕТ.
Обращаю внимание, что все функции вызываются из других скриптов. Допустим нам из одного скрипта, нужно вызвать(запустить функцию в другом) для этого мы пишем
название скрипта . название функции в скрипте (парметр если есть)
my.my_function()
Глобальные можно объявлять вначале скрипта и она будет сохранятся в коде, в памяти процесса (если я правильно понял)
Переменная объявляется только перед функцией и логическими выражениями, где используется переменная и её использует только та функция, перед которой она объявляется (На пальцах перед строкой с вашей функцией). Т.е елси функция простая без логических решений(if, elseif, for и.т.д) То ставим перед функцией, если же есть переменная, которая находится в теле такого логического решения, то она ставится строго перед этим логическим решением!
local helth = db.actor.helth
function my_function()
.
end
Чтобы сосчитать значение переменной из другого скрипта достаточно в другом скрипте сделать так:
text="Я иду гулять по бродвею"
Теперь в нашем скрипте вызываем этот параметр
local pisanina = название скрипта . text
() - При таком обращении этот тег НЕ СТАВИТСЯ !
if . then
.
end
Перевожу Если что-то то
конец тега .
Пример
if db.actor.psy==0.5 then
db.actor:kill(db.actor)
end
Если пси-здоровье ГГ - половина, то мы его убиваем.
Полная функция:
function my_function()
if db.actor.psy==0.5 then
db.actor:kill(db.actor)
end
end
[/color]
local acter = db.actor
function my_function()
local psy_zdorovie = acter.psy
if psy_zdorovie==0.5 then
acter:kill(acter)
end
end
Что я сделал?
Обозначил кусок db.actor локальной acter .
А acter.psy (db.actor)+.psy равносильно db.actor.psy
ВНИМАНИЕ. Переменные должны объявлятся так, чтобы самое то, к чему обращаются было известно. Допустим.
local psy_zdorovie = acter .psy
Нам нужна эта acter перменная, и мы ДОЛЖНЫ ОБЪЯВИТЬ её перед переменной
local psy_zdorovie = acter .psy .
Мы ее и объявили local acter = db.actor .
Думаю смысл понятен?
if . then
1 действие.
else
2 действие.
end
Перевод: Если подходит условие то
1 действие
иначе (т.е условие не выполняется)
2 действие
конец тега
Пример:
function my_function()
if db.actor.psy==0.5 then
db.actor:kill(db.actor)
else
db.actor.give_info_portion("info")
end
end
Если пси-здоровье актора равно половине, то мы его убиваем, если же значение другое(любое) , то даем ему инфопоршень.
Допустим нам нужно проверить несколько условий:
Чтобы они все выполнялись!
if (db.actor) and (db.actor.helth==1) and (db.actor.psy ==0.5) then
действие
end
Функция сработает если есть актор и здоровье актора полное и псиздоровье половина .
Тег and - означает И . Если один из элементов не выполняется, то функция не срабатывает. Кстати - это ленивый метод, как писал Kamikaze , если не выполняется первый элемент, то другие - уже не просчитывааются. Т.е. не загнружается процесс.
Если подходит хоть один элемент.
if (db.actor) or (db.actor.helth==1) or (db.actor.psy ==0.5) then
действие
end
Тег or обозначает ИЛИ . Или один, или другой. Функция сработает при условии соответствия хоть одного элемента. Так же ленивый метод. Проверяет до получения утвердительного решения, потом проверка не идет.
Данный метод заменяет перебор через таблицу. Отличается простотой и потерей производительности.
if . then
самое основное действие
elseif . then
действие 1
elseif . then
действие 2
elseif . then
действие 3
elseif . then
действие 4
elseif . then
действие 5
end
Здесь представлен перебор elseif иначе если , т.е не подходит первый вариант, мы проверяем второй и так по цепочке , до первого подходящего(где выполняется заданное условие), если же ни одно не подойдет, то ничего не произойдет. Если бы мы просто в йункции написали кучу
function perebor()
if . then
действие
end
if . then
действие
end
if . then
действие
end
if . then
действие
end
if . then
действие
end
if . then
действие
end
end
Тон ничего хорошего не вышло бы. Так как проверялись бы все функции. А в первом варианте до первого попавшегося.
Пременная нил указывает, что объекта , условия, да чего угодно НЕТ, его не существует.
ВСЕГДА проверяйте некоторые объекты на nil
Во первых это актор .
Можно написать
Но правильнее и эстетичнее, сразу писать так.
if (db.actor) then
.
end
Проверкой советую проверять многие элементы, так как в игре они зачастую не существуют в определенные моменты.
При обращении к функция из сторонних скриптов(других скрипт-файлов) я советую проверять на наличие этих скриптов:if имя скрипта then
.
end
if my then
.
end
И делайте всегда, потому как, просто удалите этот скрипт из каталога и не надо будет мучаться с переписыванием других скриптов.
math.random (1,100)
Данная функция рандомно выберет число от 1 до 100.
Сначала ставится наименьшее, потом наибольшее.
Если ставить десятичные , допустим (0.0005, 1), то перебуеруться ВСЕ значения, т.е числа с несколькими знаками, ТАК ДЕЛАТЬ НЕ НУЖНО. вы перегрузите некоторые элементы кода.
Использование
if math.random(0,1) < 1 then
действие
end
Если выбранное число меньше 1, то срабатывает функция.
if math.random(0,1) < 1 then
действие
else
.
end
Добвавляется другое действие.
Советую брать целые числа от 1 до 10 для создания процентного срабатывания, но лучше 0 и 1.
for i =1, 5000 do
действие
end
Это цикл, который прокрутнет ваше действие 5000 раз. Переменная i любая буква, число 5000 обозначает количество циклов(сколько раз пройдет ваше действие).
Допустим мы сделали такую функцию
-- удаляем объект из игры(Взято из АМК )
function remove( remove_item )
if remove_item
=nil then
alife():release(alife():object(remove_item:id()), true)
return true
end
return false
end
remove_item - это наш параметр, в данном случае это секция объекта, которую нужно удалить.
(немного по секция , если это уникальный объект, то это то,ч то в его конфиге, если нет, то нужно искать другим методом)
Нам нужно удалить уникального НПС vasek
Если функция находится в скрипте, где мы хотим удалить объект, то пишем
remove ( vasek )
Если в другом скрипте, то
имя скрипта .remove( vasek )
Вот такой пример передачи параметра, передавать можно что угодно и как угодно. Было бы воображение.
Допустим, идет проверка и если она оканчивается удачно, то функция должна вернуть одну переменную, если нет, то другую.
function my()
if proverka () == true then
.
end
end
function proverka ()
if db.actor then
return true
else
return false
end
Т.е мы хотим проверить наличие актора(можно что угодно). Создаем функцию proverka , она работает так, если актор есть - возвращает( return ) одну переменную, в данном случае true (Может быть любая другая) , если проверка не проходит, то возвращается false , а нашей первой my() стоит условие на то, что проверка вернет true
if proverka () == true then
Вот так, если вернет, то сработает первая функция.
Функции вызваются из других скриптов, нужно лишь найти место. Если она вызывается постоянно. То нужно пихать в колбэк на апдет в bind_stalker.script
function actor_binder:update(delta)
object_binder.update(self, delta)
if string.find(command_line(), "-designer") then
return
end
if self.already_jumped==false and jump_level.need_jump==true and (device().frame > self.spawn_frame+2000) then
jump_level.try_to_jump()
self.already_jumped = true
return
end
-- Вызов апдейта переноса игрока проводником
if travel_func
-- DEBUG slowdown
--slowdown.update()
local time = time_global()
game_stats.update (delta, self.object)
-- апдейт погоды
self.weather_manager:update()
-- Обновление отключения ввода с клавиатуры.
if self.st.disable_input_time
= nil and
game.get_game_time():diffSec(self.st.disable_input_time) >= self.st.disable_input_idle
then
level.enable_input()
self.st.disable_input_time = nil
end
-- Апдейт прятание оружия игрока во время диалога
if self.object:is_talking() then
if self.weapon_hide_in_dialog == false then
self.object:hide_weapon()
printf("hiding weapon. ")
self.weapon_hide_in_dialog = true
end
else
if self.weapon_hide_in_dialog == true then
printf("restoring weapon. ")
self.object:restore_weapon()
self.weapon_hide_in_dialog = false
end
end
-- Апдейт прятание оружия игрока в зоне sr_no_weapon
if check_for_weapon_hide_by_zones() == true then
if self.weapon_hide == false then
printf("hiding weapon. ")
self.object:hide_weapon()
self.weapon_hide = true
end
else
if self.weapon_hide == true then
printf("restoring weapon. ")
self.object:restore_weapon()
self.weapon_hide = false
end
end
if self.bCheckStart then
printf("SET DEFAULT INFOS")
if not has_alife_info("global_dialogs") then
self.object:give_info_portion("global_dialogs")
end
if not has_alife_info("level_changer_icons") then
self.object:give_info_portion("level_changer_icons")
end
self.bCheckStart = false
--if self.actor_weapon_on_start == true then
--db.actor:activate_slot(3)
--self.actor_weapon_on_start = false
--end
end
--device().precache_frame== 0 and
if not self.loaded_slot_applied then
self.object:activate_slot(self.loaded_active_slot)
self.loaded_slot_applied = true
end
xr_s.on_actor_update(delta)
= true) then
self.surge_manager:initialize()
self.f_surge_manager_loaded = true
end
if(self.surge_manager.levels_respawn[level.name()]) then
self.surge_manager:respawn_artefacts_and_replace_anomaly_zone()
end
self.surge_manager:update()
end
-- Апдейт доступности для симуляции.
simulation_objects.get_sim_obj_registry():update_avaliability(alife():actor())
if not self.loaded then
get_console():execute("dump_infos")
self.loaded = true
end
treasure_manager.get_treasure_manager():update()
if not(primary_objects_filled) then
pda.fill_primary_objects()
primary_objects_filled = true
end
pda.fill_sleep_zones()
--СЮДА в САМЫЙ КОНЕЦ
end
В том же скрипте есть колбэки на взятие, потерю, использование предметов. Нужно лишь искать.
Этим вы займетесь сами, или спросите у меня.
Изменение патронов
Параметры патронов хранятся в файле:
Найдем, например, раздел, отвечающий за патроны к тому же G36 (о них мы узнали из параметра ammo_class), и разберем, что означает каждый параметр:
Разбор структуры конфига
Возьмем, для примера, конфиг w_g36.ltx. Он делится на разделы:
Первый раздел
Здесь хранится общая информация о оружии - его класс, тип, ссылки на спавн и т.д. Нас интересуют следующие строки:
- description = enc_weapons1_wpn-g36 - ссылка на string_id, из которого игра подгружает описание этого оружия.
- ef_main_weapon_type = 2 - основной тип, к которому принадлежит оружие
- ef_weapon_type = 6 - подтип, к которому принадлежит оружие
- default_to_ruck = false - значит, если при пустой ячейке под автомат, подобрать автомат он будет помещён в ячейку; если true автомат в ячейку помещён не будет
- sprint_allowed = true - эта строка означает можно ли бегать с данным оружием (true-можно;false-нельзя)
Второй раздел
Содержит модификаторы, которые даются к углу зрения/дальности обзора NPC, держащего это оружие в руках:
- holder_range_modifier = 1.85 - во сколько раз увеличивается eye_range
- holder_fov_modifier = 0.3 - во сколько раз увеличивается eye_fov
Третий раздел
Содержит данные о самом оружии, его некоторых характеристиках:
- cost = 18000 - базовая цена (торговцы умножают её на некоторый коэффициент)
- weapon_class = assault_rifle - класс оружия (здесь - штурмовая винтовка)
- ammo_mag_size = 30 - размер магазина
- ammo_class = ammo_5.56x45_ss190, ammo_5.56x45_ap - типы используемых патронов
- grenade_class = ammo_m209 - тип используемых гранат
- fire_modes = 1, -1 - режимы ведения огня
- hand_dependence = 1 - засивимость о рук (?) - возможно, речь идет о качании ствола
- single_handed = 0 - держится ли только в одной руке
- slot = 2 - слот в инвентаре
- animation_slot = 2 - вид анимации (для пистолета/для винтовки)
- inv_name = wpn-g36 - ссылка на имя, отображаемое в инвентаре, тоже берется из string table, как и описание
- inv_name_short = wpn-g36 - короткое имя; в данном случае используется то же самое
- inv_weight = 3.6 - вес
- inv_grid_width = 5 - длина иконки (кол-во клеток по х)
- inv_grid_height = 2 - высота иконки (кол-во клеток по у)
- inv_grid_x = 0 - координаты первого угла иконки по x
- inv_grid_y = 10 - координаты первого угла иконки по y
Четвертый раздел
В четвертом разделе хранится информация о износе/отдаче оружия. Практически все параметры там снабжены комментариями, поэтому приведу лишь самые интересные:
- cam_relax_speed = 5.7 - скорость возврата в исходное положение
- cam_dispersion = 0.2 - увеличения угла (в градусах) с каждым выстрелом
- fire_dispersion_condition_factor = 5 - увеличение дисперсии в процентах при максимальном износе
- misfire_probability = 0.003 - вероятность осечки при максимальном износе
- misfire_condition_k = 0.05 - порог (в данном случае - 5%), после которого оружие может заклинивать
- condition_shot_dec = 0.0002 - увеличение износа при каждом выстреле
Пятый раздел
Здесь хранится множество параметров, из которых наиболее интересны эти:
- PDM_disp_base = 3.0 - множитель, на который умножается базовая дисперсия оружия, когда ГГ (Главный Герой) стоит на месте в полный рост;
- PDDM_disp_vel_factor = 1.3 - множитель, на который умножается базовая дисперсия оружия, когда ГГ крутит оружием или бежит;
- PDM_disp_accel_factor = 1.3 - множитель, на который умножается базовая дисперсия оружия, когда ГГ бежит в спринте;
- PDM_crouch = 1.0 - множитель, на который умножается базовая дисперсия оружия, когда ГГ идет пригнувшись;
- PDM_crouch_no_acc = 1.0 - множитель, на который умножается базовая дисперсия оружия, когда ГГ стоит на месте, пригнувшись;
- hit_power = 0.50, 0.54, 0.57, 0.60 - сила выстрела
- hit_impulse = 105 - импульс пули (сила, которую летящая пуля передает жертве, влияет на поведение ragdoll-тела)
- hit_type = fire_wound - тип причиняемых повреждений, в данном случае - пулевые ранения (параметр в синглплеере ни на что не влияет)
- fire_distance = 600 - максимальная дистанция для выстрела
- bullet_speed = 925 - начальная скорость пули
- hud = wpn_g36_hud - внешний вид оружия
Шестой раздел
- position = -0.026, -0.132, 0.0 - позиция по отношению к игроку (?)
- orientation = 0, 0, 0 - направление, в которое смотрит ствол (?)
Седьмой раздел
Содержит описания визуальной стороны оружия и некоторые другие параметры:
Редактирование оружия
Сегодня мы разберем то, каким образом можно редактировать оружие в игре - от характеристик до описания. Характеристики оружия хранятся здесь:
Изменение описаний
В нем хранятся строки с названиями и описаниями, на которые ссылаются конфиги оружия. Например, тот же G36 ссылается сюда:
Меняя их содержимое, мы меняем описания/названия данного оружия.
Читайте также: