Скрипты для S.T.A.L.K.E.R.: Call of Pripyat
Скрипты для S.T.A.L.K.E.R.: Call of Pripyat
1. Все файлы скрипты находятся в папке gamedatascrips .
2. Файл скрипта – это текстовый файл имеющий расширение .script .
3. В С.Т.А.Л.К.Е.Р используется немного изменённый скриптовый язык Lua 5.1 .
4. Для редактирования скриптов я советую NotePad c++, данная программа имеет подсветку синтаксиса для многих языков, в том числе и для Lua. Чтобы активировать подсветку нажмите клините Стиль – Lua .
5. Чтобы закоментировать строку (код игры не будет ёё читать) , необходимо перед строкой поставить — .
Если вы хотите закоментировать кусок (много строк) то –[[ . ]] , ваш текст будет закоментирован.
Начнём уроки.
1)Создадим свой my.scripts и поместим его в папку scrips . Откроем с помощью НотПада и настроим подсветку.
2) Внутри файла-скрипта должны содержаться только КОД скрипта и ваши ЗАКОМЕНТИРОВАННЫе пометки. Если будет лишний текст, т.е какие-то знаки и слова, то будет вылет на этот скрипт. Так как код игры полностью собирает весь скрипт в стек и выбирает только то, что вы задали, но если будет мусор, то игра не воспримет код.
3)Архитектур. Для создания функций нужны лишь знания синтаксиса и игровые методы и глобальные функции(которые записаны в движке) можете почитать lua_help.scrip , но я советую посетить тему на АМК . Там собраны все методы, классы и полное их описание.
4) Функция. Это то, что будет делать игра.
Любая функция начинается со слов
И заканчивается тегом end . Этот тег означает конец функции, сравнения, он закрывающий и обязателен. Я советую при составлении функций , чтобы не забыть чего-нибудь, писать скелет извне, т.е сначала функция, потом закрывающий тег, и по нарастающей во внутрь.
() -Обязательный элемент. Позже расскажу как передавать переменные через этот тег.Между окончание функции и этим тегом ПРОБЕЛА НЕТ.
Обращаю внимание, что все функции вызываются из других скриптов. Допустим нам из одного скрипта, нужно вызвать(запустить функцию в другом) для этого мы пишем
название скрипта . название функции в скрипте (парметр если есть)
my.my_function()
Чтобы объявить какой-либо элемент для функции локальным используется тег local
local helth = db.actor.helth
Т.е мы расшифровали helth , и показали , что это значение db.actor.helth.
Если вы хотите вставить слово или свой текст нужно заключить слово в кавычки.
local helth = “Уровень здоровья.”
Если вы хотите вставить слово с кавычками или свой текст нужно сделать так:
local helth = “”Уровень здоровья.””
Чтобы объявить глобальну нужно всего лишь сделать так
helth = db.actor.helth
Глобальные можно объявлять вначале скрипта и она будет сохранятся в коде, в памяти процесса (если я правильно понял)
Переменная объявляется только перед функцией и логическими выражениями, где используется переменная и её использует только та функция, перед которой она объявляется (На пальцах перед строкой с вашей функцией). Т.е елси функция простая без логических решений(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) 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 sr_psy_antenna.psy_antenna then
sr_psy_antenna.psy_antenna:update(delta)
end
–[[
–‘ Вывод сообщения о большой радиации
if self.object.radiation >= 0.7 then
local hud = get_hud()
local custom_static = hud:GetCustomStatic(“cs_radiation_danger”)
if custom_static == nil then
hud:AddCustomStatic(“cs_radiation_danger”, true)
hud:GetCustomStatic(“cs_radiation_danger”):wnd():TextControl():SetTextST(“st_radiation_danger”)
end
else
local hud = get_hud()
local custom_static = hud:GetCustomStatic(“cs_radiation_danger”)
if custom_static
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
В том же скрипте есть колбэки на взятие, потерю, использование предметов. Нужно лишь искать.
Этим вы займетесь сами, или спросите у меня.
В диалогах можно вызывать через тег (без () )
Делаем скрипты без вылетов
Отладив несколько скриптов на предмет вылетов решил написать это небольшое руководство, чтобы помочь скриптописателям избежать потенциальных пробем. Сразу оговорюсь – я программист, поэтому к отладке скриптов подхожу со своей профессиональной точки зрения, и то что я тут изложу вам – сие для программиста есть непреложная истина, и если вы хотите уменьшить количество глюков – старайтесь придерживаться нижеприведённого стиля программирования.
Для начала маленький экскурс в историю. Итак, скрипты в сталкере написаны на языке Lua – разработали его бразильцы, он очень гибок, легко встраивается в игры и поэтому очень часто используется для написания скриптов любой степени сложности. Так вот, у этого языка есть несколько исключительно важных особенностей, которые, при их несоблюдении, будут приводить к вылетам вашего скрипта. Итак:
Особенность первая. Типы данных и западло с nil.
Сначала сделаю маленькое отступление, чтобы понятнее было. Итак, в Lua используются следующие операторы:
== сравнение, равно ли значение
= сравнение, НЕ равно ли значение
сравнение, больше ли значение
= сравнение, больше ли значение или равно
and логический оператор И
not логический оператор НЕ
or логический оператор ИЛИ
Всё. Теперь поехали дальше. Язык Lua Изначально создавался для работы с большими строчными базами данных, поэтому ВСЕ виды конструкций в языке – это типы данных, т.е. по сути либо переменные, либо константы. Это касается так же и функций! Поэтому даже с функциями в Lua можно и нужно обращатся как с константами. Далее. Касательно, собственно “привычных” переменных. Обычные переменные в Lua получают свой тип данных только в момент присвоения им значения (запомните, это важно). При этом, в Lua есть такой важный и полезный тип данных как nil. nil – Это “пустота”, т.е. отсутствие какого-либо значения. При этом этот тип используется компилятором скриптов для “сбора мусора”, т.е. для освобождения занимаемой памяти. Смотрите пример, я объясню подробнее, что это значит:
local exposure_count = 0
Тут у нас 2 локальные переменные, одна из которых просто создана, а вторая – создана и инициализирована. Если сейчас обратиться к переменной reminder_count, считав её значение, то мы получим в качестве значения – nil, т.е. пустоту. Если же мы обратимся к переменной exposure_count – то получим, как и ожидали, 0 – так как мы это значение проинициализировали ЗАРАНЕЕ. При этом не надо путать nil и 0 – так как 0 – это всё-таки какая-то информация, а вот nil – это её полное отсутствие. Так вот, собственно, чем это чревато. Я уже сказал, что nil используется для сбора мусора. Вручную это работает так – когда вам переменная уже не нужна, вы просто пишете:
И ваша переменная test_variable сотрётся из памяти, и любые ссылки на неё будут выдавать на выходе nil (типа нет такой переменной, “абонент вне зоны действия сети”). Ну так собственно вот, зачем я это всё рассказываю. если не определить значение переменной сразу, как это было сделано с переменной reminder_count, то любые попытки обратиться к ней внутри скрипта приведут к вылетам. Происходит это следующим образом: допустим, reminder_count – это у нас счётчик напоминаний. Т.е. мы о чём-то напоминаем игроку текстовыми сообщениями, и помечаем, сколько раз мы это сделали. Определили мы переменную именно так, как в примере выше, т.е. не задав ей никакого значения. Значение же её должно присваиваться ниже по коду, после первого оповещения юзера. При этом у нас есть в коде обращение к этой переменной, по которому решается что делать дальше.
Выглядит это примерно так:
if auto_injection_active then
if antirad_check_delay == nil or game.get_game_time():diffSec(antirad_check_delay) > 60 then
if not db.actor:object(“antirad”) and not (use_scientific_kit and db.actor:object(“medkit_scientic”)) then
–обратите внимание сюда
if reminder and reminder_count == 0 or reminder_count >= mins_till_next_remind then
–обратите внимание сюда
if use_text then
local news_text = “%c[255,160,160,160]Автоматическая система ввода медицинских препаратовn”..”%c[default]Напоминаю: %c[255,230,0,0]Противорадиационные препараты отстутствуют! %c[default]Автоматический ввод препаратов невозможен.”
db.actor:give_game_news(news_text, “uiui_iconsTotal”, Frect():set(0,188,83,47), 0, 3000)
end
if use_sounds then
local snd_obj
if use_custom_sounds then
snd_obj = xr_sound.get_safe_sound_object( [[HEVno-anti-rad]] )
else
snd_obj = xr_sound.get_safe_sound_object( [[devicepdapda_tip]] )
end
if snd_obj then
snd_obj:play_no_feedback(db.actor, sound_object.s2d, 0, vector(), 1.0)
end
end
reminder_count = 1
elseif reminder then
reminder_count = reminder_count + 1
end
else
radiation_warning = true
reminder_count = 0
end
antirad_check_delay = game.get_game_time()
end
end
end
Во время игры всё это скорее всего отработает хорошо, но вот при загрузке. тут могут быть проблемы, так как скрипт при запуске может пролететь ту часть, где переменной reminder_count присваивается значение!
В итоге при запуске вышеприведённой функции check_antirad_supplies() нас получится что reminder_count не существует – он равен nil, и в итоге проверка
if reminder and reminder_count == 0 or reminder_count >= mins_till_next_remind then
выдаст ошибку и приведёт к вылету!
Почему? Да потому что НЕЛЬЗЯ сравнивать НИЧТО с вещественным значением.
Именно поэтому, когда вы создаёте новую переменную, вы ОБЯЗАНЫ задать ей значение по умолчанию, даже если вы полностью уверены, что она нигде не будет использована до инициализации.
Поверьте – в программировании бывает всё, и запросто может так случиться, что ваша переменная будет использована и спровоцирует вылет.
begin xStream upd. —
Простой способ обойти такую кучу проверок и лишних инициализаций – использование or-оператора. пример
if (reminder_count or 0) >= mins_till_next_remind then
если переменная равна nil, то выражение вычисляется дальше и получается равным 0, а это уже число и сравнение происходит безболезненно
end xStream upd. —
Кроме вышеприведённой ситуации, возможен ещё один неприятный момент, связанный с определением переменных и значением nil. Суть его заключается в том, что при присваивании значений или операциями с переменными мы можем получить кучу проблем. покажу конкретнее каких:
1) “Убийство” переменных
Положим, у нас с reminder_count происходят ещё какие-нибудь занимательные вещи, например мы его значение зачем-нибудь присваиваем другой переменной вот так:
Ну и вот, если у нас reminder_count в момент присвоения ещё не имеет никакого значения, то мы получим занимательную штуку – у нас это выражение сработает как
В результате чего переменная antirad_check_delay “сдохнет” и будет деловито убрана “сборщиком мусора” из памяти, что моментально приведёт к вылету, когда в дальнейшем какая-то часть кода обратится к значению antirad_check_delay.
2) Ошибки деления на 0.
Теперь положим что у нас reminder_count используется в каком-нибудь расчёте вот так:
Как мы помним, у нас reminder_count не инициализирована, и как следствие равна nil.
В итоге мы получим попытку поделить exposure_count на ноль (в нашем случае на nil, что суть одно и то же в нашем случае) и получим “классический” программистский вылет из-за ошибки деления на ноль.
3) Ошибки присвоения.
Предположим что мы написали скрипт, который помогает выбирать оружие при наличии вблизи врагов. И вот, у нас в скрипте есть такой кусок кода, где NPC вынимает из рюкзака оружие:
local enemy = self.npc:best_enemy()
if wpn then
–обратите внимание сюда
self.weapon_id = wpn:id()
–обратите внимание сюда
self:return_items(self.weapon_id)
— printf(“set_weapon[%s]:set %s[%s]”,self.npc:character_name(),wpn:id(),wpn:section())
else
printw(“set_wpn:weapon not exist”)
end
if self.modes.process_mode == “3” and enemy then
for k,v in pairs(self.weapons) do
for i,w in ipairs(v) do
if w.id
= self.weapon_id then
local item = level.object_by_id(w.id)
if item and item:parent() and item:parent():id() == self.npc_id then
printw(“set_weapon[%s]:process %s[%s]”,self.npc:character_name(),w.id,w.sec)
self:process_item(item)
end
end
end
end
end
if enemy then
self.npc:set_item(object.idle,wpn)
end
self.weapons = nil
В помеченном выражении self.weapon_id = wpn:id(), чтобы было понятнее, self.weapon_id – это оружие, которое сейчас в руках у персонажа, а wpn:id() ссылается на лучшее оружие из инвентаря NPC. Т.е. это выражение заставляет NPC заменить ТЕКУЩЕЕ оружие на лучшее. Всё было бы отлично если бы не одна характерная вещь – когда NPC сидит например у костра отдыхает, У НЕГО НЕТ В РУКАХ СТВОЛА! И разумеется, в этом случае значение self.weapon_id не существует! Оно равно nil. В итоге при подобном выражении
произойдёт попытка присвоить значение ПУСТОТЕ, т.е. nil = wpn:id(), и это МГНОВЕННО приведёт к вылету.
Как с этим бороться.
Бороться с такими ситуациями очень просто на самом деле. Во-первых:
ВСЕГДА ИНИЦИАЛИЗИРУЙТЕ ПЕРЕМЕННЫЕ.
Т.е. вот такое описание переменной:
local reminder_count
НЕДОПУСТИМО! ВЫ ОБЯЗАТЕЛЬНО ДОЛЖНЫ ЗАДАТЬ ПЕРЕМЕННОЙ ЗНАЧЕНИЕ! Если переменная числовая, сделайте это так:
local reminder_count = 0
Если строчная – то сделайте это так:
local reminder_count = “” (получится вместо nil пустая строка)
Если логическая, то так:
local reminder_count = false
В общем, делайте так, как вам удобнее, но ДЕЛАЙТЕ ОБЯЗАТЕЛЬНО!
И во-вторых:
ВСЕГДА ПРОВЕРЯЙТЕ ПЕРЕМЕННУЮ ПЕРЕД ИСПОЛЬЗОВАНИЕМ! Т.е. в кусках кода, чреватых вылетами (к ним относятся АБСОЛЮТНО ВСЕ части, где идёт работа с вещами или оружием) обязательно вставляйте проверки переменных на nil следующим образом:
Код: Выделить всё
= nil then
self.weapon_id = wpn:id()
end
Тогда сначала выпонится проверка, и если обе переменные имеют значение, то операция отработает, а если один из параметров пуст – то функция просто пропустит этот код.
Точно так же, если вы используете ЛЮБЫЕ математические операции например деление (но не только деление, всего остального тоже касается), тоже ОБЯЗАТЕЛЬНО поверяйте переменную. Вот так:
Код: Выделить всё
= nil and reminder_count
= 0 then
antirad_check_delay = exposure_count/reminder_count
end
Таким образом потенциальные вылеты будут аккуратно изолированы, и больше не будут создавать проблем. Настоятельно советую всем, кто уже писал скрипты, внимательно их просмотреть, и вставить в “опасные” места подобные проверки, и в будущем делать это сразу, чтобы самим себе облегчить жизнь.
Небольшое дополнение итак, вы вставили обходные проверки вот таким образом:
= nil then
self.weapon_id = wpn:id()
end
= nil and reminder_count
= 0 then
antirad_check_delay = exposure_count/reminder_count
end
И у вас в случае некорректного значения компилятор спокойно пропустил этот код, ничего не сделав ни с self.weapon_id (из первого примера), ни с antirad_check_delay (из второго). Однако вам всё-таки нужно, чтобы с ними что-то происходило, даже если проверяемые переменные неверны. Тогда я бы советовал вам дополнить этот обход отработкой нештатной ситуации. Делается это банально просто:
= nil then
self.weapon_id = wpn:id()
elseif self.weapon_id == nil then
–вставьте сюда код, что делать если self.weapon_id не существует
elseif wpn:id() == nil then
–а сюда, если wpn:id() не существует
end
И для второго случая аналогично:
= nil and reminder_count
= 0 then
antirad_check_delay = exposure_count/reminder_count
else
–а тут что мы сделаем если reminder_count не существует
–я бы сделал например вот так:
antirad_check_delay = exposure_count/1
–и все дела
end
Более конкретная реализация зависит от того, что именно вы пытаетесь сделать – тут уже вам виднее.
Скрипты для S.T.A.L.K.E.R.: Call of Pripyat
К сожалению, напрямую из консоли игры никак не удастся получить неуязвимость или тонны денег с лучшей экипировкой. Дело в том, что при разработке аддона «Сталкер — Зов Припяти» такой возможности просто не предусмотрели. Таким образом разработчики поощряют всё сталкерское сообщество к честной игре. Но читы в «Зове Припяти» всё-таки можно реализовать, иначе бы этой статьи просто не было!
Перед описанием читов к игре, хотелось бы всё-таки подробнее рассказать о важной консольной команде для свободной камеры. Бывает, что в игре нужно лучше изучить локацию или понять наше местоположение. Для этого нажимаем знак «тильда» на клавиатуре, или русская буква «ё». Входим в консоль, пишем demo_record 1, нажимаем Enter. Теперь мы можем летать над локацией и заглядывать во все щели. Для ускорения полёта камеры нажимаем клавишу Ctrl. Для выхода из режимы полёта камеры жмём Esc.
Перейдём непосредственно к читам. Для начала нужно удостовериться, что в нашей версии игры распакованы ресурсы. Только в этом случае мы можем иметь доступ к конфигурационным файлам. Если в корневой папке игры «S.T.A.L.K.E.R. Call of Pripyat» присутствует папка gamedata с подпапками ai, anims, configs и т.д., то у нас распакованная версия, и мы можем сразу править конфигурационные файлы игры, таким образом получая читы в игре. Если папки gamedata у нас нет, то придётся распаковать ресурсы специальным распаковщиком. Качаем распаковщик для «Сталкер — Зов Припяти» по прямой ссылке.
Порядок распаковки такой: разархивированную папку unpacker распаковщика кидаем в корень игры. В папке unpacker запускаем файл CS_full_unpack. Ждём несколько минут, пока распаковщик не напишет в командной строке Press any kеy… Нажимаем любую клавишу и закрываем окно командной строки. В итоге мы получаем внутри папки unpacker новую папку unpacked, в ней находятся распакованные ресурсы игры. Переименовываем папку unpacked в gamedata и переносим её в корень игры, рядом с папками bin, levels и т.д. Важно: если у вас уже существовала папка gamedata с каким-нибудь сторонним модом, то не смешайте всё в кучу, иначе игра будет вылетать.
Имея распакованные ресурсы можно приступать к правке конфигов, получая бессмертие, увеличенный переносимый вес, миллионы денег и другие вкусности. Изменение конфигурационных файлов игры и является по сути чит-кодами к игре «Сталкер — Зов Припяти». Подробнее о том, как изменять конфиги игры смотрите в статье ‘Сталкер — Тень Чернобыля: чит-коды‘. Все параметры для изменений конфигурационных файлов одинаковы и подходят для любой части трилогии «Сталкера».
Если вы не хотите копаться в файлах игры, но желаете всего лишь увеличить количество денег в «Сталкере», то воспользуйтесь бесплатными программами ArtMoney или Cheat Engine. Описание работы этих программ можно посмотреть в двух роликах ниже. Также быстрым и удобным решением для доступа к читам является мод «Повелитель Зоны» для «Зова Припяти».