Разберем на примере локации Затон
На Затоне 7 точек спавна (смарттеррейнов). В каждой точке в моде 1.6 одновременно могут спавниться 2 отряда по 6 бойцов.
Итого на карте может быть 84 Альфы одновременно.
Изменять файлы надо в каталогах: gamedata\configs\scripts\Локация\smart\
Пример Затон. В каталоге лежат 7 файлов, на одну точку спавна - 1 файл. Открываем первый: zat_sim_9.ltx
Первое, что бросается в глаза:
[smart_terrain];zat_sim_9
...
max_population = 2
...
Вот это значит, что на данном смарте может появляться две команды одновременно. Заменяем 2 на 1, чем запрещаем спавн больше, чем 1 команды на смарте.
Далее:
[zat_alfa_force_novice]
spawn_squads = zat_alfa_squad_1_novice
spawn_num = {+opt_activate_alfa_force =check_actor_rank(0:100)} 1, 0
[zat_alfa_force_regular]
spawn_squads = zat_alfa_squad_1_regular
spawn_num = {+opt_activate_alfa_force =check_actor_rank(100:200)} 0, 0
[zat_alfa_force_experienced]
spawn_squads = zat_alfa_squad_1_experienced
spawn_num = {+opt_activate_alfa_force =check_actor_rank(200:350)} 1, 0
[zat_alfa_force_veteran]
spawn_squads = zat_alfa_squad_1_veteran
spawn_num = {+opt_activate_alfa_force =check_actor_rank(350:600)} 1, 0
[zat_alfa_force_master]
spawn_squads = zat_alfa_squad_1_master
spawn_num = {+opt_activate_alfa_force =check_actor_rank(600)} 1, 0
Эти строчки указывают качество для спавна Альфы в зависимости от ранга ГГ. Но самое главное - вероятность спавна!
1, 0 - спавн 100%; 0, 0 - отсутствие спавна.
Это даёт возможность на каких-то уровнях ГГ вообще не спавнить Альфу на данном смарте.
Думаю, дальше понятно. Надо пройтись по остальным файлам смартов и сделать им такое же обрезание.
Примечание: Равномерно распределяйте спавн на смартах по рангу ГГ.
Например (Затон):
zat_sim_9
|
zat_sim_10
|
zat_sim_14
|
zat_sim_15
|
zat_sim_16
|
zat_sim_21
|
zat_sim_24
|
0,1
|
0,0
|
0,1
|
0,0
|
0,0
|
0,1
|
0,1
|
Пусть мы выбрали ранг ГГ check_actor_rank(0:100). Т.о., если ГГ - новичок будет спавнится всего 4 команды Альфы при условии max_population = 1.
|
Открываем gamedata\configs\misc\squad_descr_sgm.ltx
Тут всё про Альфу. Николай заботливо дал все комменты и ввёл понятные идентификаторы. Собственно описаны все команды Альфы от новичка до мастера. Собственно главные для нас строчки типа:
npc = alfa_novice_commander,alfa_novice_specnaz1,alfa_novice_specnaz2,alfa_novice_sniper1,alfa_novice_sniper2,alfa_novice_shotgunner
Это значит, что команда состоит из новичков и включает командира, двух спецназовцев, двух снайперов и шотганера. Вот они - наши любимые шесть пар копыт!
Людям, утомлённым Альфой можно проредить сквад, оставив там тех, кто им нужен. Допустим:
npc = alfa_novice_commander,alfa_novice_specnaz1,alfa_novice_sniper1,alfa_novice_shotgunner
Вот уже сквад из 4 бойцов. И т.д.
Уменьшая сквад на малых рангах ГГ и оставляя исходное количество бойцов Альфы при "взрослом" ГГ можно добиться желаемого игрового комфорта, пощипывая пару Альф в начале игры и вступая в "мясные" бои ближе к концу.
Для кровожадных. Если можно уменьшить сквад, так, верно, можно и увеличить. Мало того - усилить! А добавьте к этой шестёрке пару опытный снайперов и одного ветерана спецназовца. Идентификаторы берите из этого же файла и не забывайте о запятых! В предыдущем примере сквад из 4 бойцов слабоват! Четыре новичка - да их собачки порвут! Давайте дадим им наставника, такого дядьку Черномора - спецназовца ветерана!
npc = alfa_novice_commander,alfa_novice_specnaz1,alfa_novice_sniper1,alfa_novice_shotgunner,alfa_veteran_specnaz2
|
Вновь привнесённые Николаем перцы описаны в gamedata\configs\gameplay\character_desc_sgm.xml
Файл с комментами, структурирован по локам, легко читаем. Наши любимцы в самом хвосте. У каждого есть секция:
[spawn] \n
device_torch \n
wpn_svd \n
ammo_7.62x54_7h1 = 1 \n
wpn_beretta \n
ammo_9x19_spp = 1 \n
wpn_binoc = 1 \n
#include "gameplay\character_items_3.xml"
#include "gameplay\character_food.xml"
#include "gameplay\character_drugs_3.xml"
Вот чего дал Николай alfa_experienced_sniper1. Набор стандартный, в том числе основной ствол и один патрон к нему, пистолет и один патрон к нему. Почему один патрон. Это не последний патрон для себя. Неписи умеют клонировать патроны и одним патроном заряжают весь магазин!!! Нам бы так с деньгами
Так давайте нахулиганим и снабдим бойца гауссом вместо СВД ну и одной батарейкой!
[spawn] \n
device_torch \n
wpn_gauss \n
ammo_gauss = 1 \n
wpn_beretta \n
ammo_9x19_spp = 1 \n
wpn_binoc = 1 \n
#include "gameplay\character_items_3.xml"
#include "gameplay\character_food.xml"
#include "gameplay\character_drugs_3.xml"
Ну вот, парень вооружён и очень опасен! Опять же учите ГГ быстро бегать и шустро ползать на брюхе.
Ещё. Можно дать неписю ствол с оптикой или глушаком. Тогда оружейная строчка выглядит так:
wpn_lr300 = 1, scope, silencer \n
Постоянно сверяйтесь с конфигами оружия, чего можно на него навешать! Не навешивайте подствольник на Форт - игра обхохочется!!! Удачи!
|
Николай ввёл несколько новых группировок в дополнение к имеющимся:
bandit_alies - бандиты из группы Чапая
killer_alies - Юпитерские наймы
rasvet - Рассвет
monolith_alies - Монолит в кинотеатре на Припяти
alfa_force - Альфа
Старые группировки:
actor - единственный член группировки - ГГ
dolg - Долг
freedom - Свобода
bandit - бандиты
killer - наймы
stalker - сталкеры
monolith - Монолит
Кроме того Николай прописал функцию изменения взаимоотношений между группировками.
set_faction_to_faction_relation(from_faction,to_faction,type_relation)
где from_faction - наименование группировки, которая будет менять отношение
to_faction - наименование группировки, к которой будет изменяться отношение
type_relation - отношение. Можно задавать следующие значения:
"e" - установить вражеские отношения
"n" - установить нейтральные отношения
"f" - установить дружеские отношения
Тут возникает широкое поле деятельности. Например, геймерам, истомлённым Альфой поссорить её с бандитами. Рисуем:
set_faction_to_faction_relation("bandit","alfa_force","e")
После выполнения функции, при встрече бандитов с Альфой "Кушай лимончик, падла!" - гарантирую.
Но мы о краснухе.
Краснуха возникает при отстреле члена группировки, заступе на территорию группы без разрешения и глючков игры. Вот этот последний случай и попробуем лечить. Рисуем лечение отношений между Чапаевцами и ГГ:
set_faction_to_faction_relation("bandit_alies","actor","n")
После выполнения функции Чапа и его команда станут жёлто-равнодушными к ГГ.
Всё? Неа...А куда вписать эту функцию и как её запустить? Не буду изобретать паровоз: в файл меню, забиндив её на F6.
Открываем \scripts\ui_main_menu.script
Ищем
elseif db.actor~=nil and dik==DIK_keys.DIK_F5 then
self:mod_options()
Ниже вставляем
elseif db.actor~=nil and dik==DIK_keys.DIK_F6 then
set_faction_to_faction_relation("bandit_alies","actor","n")
Сохраняем, закрываем, запускаем игру.
В игре Esc-F6-Esc
Что мы сделали? Теперь все вновь рождённые бандиты на Лесничестве (неудачный пример: эти не спавнятся) будут нейтральны к ГГ. А эти, уже рождённые? Будут красными. А их надо примирять с ГГ персонально. Надо перебрать все объекты на уровне, отфильтровать сталкеров с нужной группировкой и каждого примирить с ГГ. Постреляем, к примеру в Долговцев - они стали красными. Лечим. Находим в томже файле меню:
elseif db.actor~=nil and dik == DIK_keys.DIK_F5 then
self:mod_options()
--после вставляем фрагмент:
elseif db.actor~=nil and dik == DIK_keys.DIK_F6 then
local id, obj, kto
for id=0, 65535 do
obj = level.object_by_id(id)
if obj and IsStalker(obj) then
kto = obj:character_community()
if (kto == "dolg") then
obj:force_set_goodwill(0, db.actor) --0 - нейтрал, 5000 - друг, -5000 - враг
end
end
end
Видим красных долговцев - жмём Esc-F6-Esc
Можно перекрашивать и другие кланы, заменив "dolg" на, например "bandit"
Всё!
|
gamedata\sounds\radio_music\
|
Торговля с Бородой. Вот его файл: gamedata\configs\misc\trade\trade_zat_a2_barmen.ltx
Ищи коммент Трофеи. Трофеи могут быть в секциях покупки (buy) и продажи (supplies). Покупках всё прописано и Борода честно покупает сиськи, письки и хвосты. А трофеи в секции продажи закрыты конструкцией типа:
mutant_snork_booty ;НЕ ПРОДАЕТСЯ/ПОКУПАЕТСЯ
Открыть бойкую торговлю можно прописав количество товара и вероятность его появления в продаже:
mutant_snork_booty = 1, 2
Вот теперь Борода всегда будет иметь в продаже от 1 до 2 босоножек от снорка.
Примечание: Продажи пойдут после выполнения ряда квестов. Стартовые пордажи описаны в секции [supplies_start]. Если есть острое желание купить снорковскую босоножку сразу при старте игры надо прописать её в эту секцию.
|
открыть файл gamedata\configs\mod_parameters\mod_params.ltx
добавить в конец файла строку:
dream_limited_interval = 0
|
открываем файл: scripts\ui_main_menu.script
Ищем:
elseif db.actor~=nil and dik==DIK_keys.DIK_F5 then
self:mod_options()
После этого втыкаем:
elseif db.actor~=nil and dik==DIK_keys.DIK_F6 then
create("ID_PERSA",db.actor:position().x+10,db.actor:position().y,db.actor:position().z+1,db.actor:level_vertex_id() ,db.actor:game_vertex_id())
Где: F6 - кнопка на которую назначен спавн, ID_PERSA - идентификатор персонажа из character_desc_*.xml
Заходим в игру. Нажимаем Esc=>F6=>Esc. И перс заспавниться в 10 метрах от ГГ.
|
Николай сделал несколько удобных функций - "обёрток" для работы с отношениями между группировками. Найти их можно в файле \scripts\_g.script в разделе "Работа с отношениями"
-- 'Улучшить отношения между группировкой и ГГ.
function increase_faction_goodwill(community,value)
-- 'Ухудшить отношения между группировкой и ГГ.
function decrease_faction_goodwill(community,value)
-- 'Улучшить отношения между группировкой и обьектом.
function increase_faction_goodwill_to(obj_id,community,value)
-- 'Ухудшить отношения между группировкой и обьектом.
function decrease_faction_goodwill_to(obj_id,community,value)
-- 'Установка отношений одной группировки к другой.
function set_faction_to_faction_relation(from_faction,to_faction,type_relation)
-- 'Установка отношений одного обьекта к другому.
function set_relation_between(obj1,obj2,type)
-- 'Чтение отношений одного обьекта к другому.
function check_relation_between(obj1,obj2)
Очень удобно и понятно!
|
У Николая от старых версий остались функции создания и обработки рестрикторов, создаваемых при старте (новой???) игры. А вот создание рестрикторов с версии 1.5 он перенёс в all.spawn. Для нас главное, что функции не смахнул. Итак: файл _g.script
функция
function create_restrictor(custom_add,radius,x,y,z,lv,gv)
if z==nil and lv==nil and gv==nil then
se_obj=alife():create("space_restrictor",level.vertex_position(x),x,y)
else
se_obj=alife():create("space_restrictor",vector():set(x, y,z),lv,gv)
end
custom_pack="[logic]\n".."cfg = "..custom_add
sgm_packet.setup_restrictor(se_obj,custom_pack,radius,x,y,z,lv,gv)
end
Ну, вроде , ясно, что radius - радиус границы срабатывания, далее координаты??? рестриктора, и уровниевый и игровой вертексы. А вот первый параметр - ссылка на файл с описанием рестриктора. Вот вызов создания рестриктора из версии 1.3:
create_restrictor([[scripts\SGM\zaton\restrictors\zat_quest_line.ltx]],1.0,132.765,-3.634,-139.823,1192032,150)
Значит, для создания своего рестриктора надо создать файл какойторестриктор.ltx, положить в каталог \configs\scripts\SGM\лока\restrictors\какойторестриктор.ltx
А в какойторестриктор.ltx надо прописать логику рестриктора:
[logic]
active = sr_idle
[sr_idle]
on_actor_inside = {=имя_инфопоршня_выдачи_квеста} nil %+имя_инфопоршня_1%
END
т.е. при входе ГГ в зону действия рестриктора, он проверит наличие инфопоршня квеста. При наличии инфопоршня выдастся инфопрошень_1. Всё, застукали ГГ. А теперь всё просто. В логике выдачи квеста запускаем функцию, в котором есть спавн мобов или неписей.
По аналогичной схеме сделан квест на встречу с Глухарём: есть метка у соснодуба, ГГ приходит на это место, Глухарь зовёт на ВНЗ Круг.
Примечание: данный рестриктор, наверняка, сидит в all.spawn
|
Если бы ГГ был прописан к действующим кланам, то как бы двигался сюжет? Пусть бы ГГ вступил в клан обычных бандитов, да любой сталкер почёл за удовольствие его грохнуть. Поэтому Николай ввёл группировку actor_bandits, к которой сталкеры нейтральны. А у нас идея нагло и цинично менять костюмы и имитировать членство в группировке.
Значит нам надо определить, что надето на ГГ.
Определяемся. Голый ГГ - сталкер, Если надет novice_outfit или stalker_outfit - тоже.
Если надет svoboda_light_outfit или svoboda_heavy_outfit - Свободовец.
Если надет dolg_outfit или dolg_heavy_outfit - Долговец
и так далее.
После того как мы определились какой броник соответствует какому клану можно писать свои функции. В папке скриптов создаём пустой файл perehod.script В нем создаём функцию analisis_outfit.
function analisis_outfit()
--Теперь надо узнать, что надето на ГГ
local outfit_now = db.actor:item_in_slot(7)
--Чего там на нём? Выясняем:
if (outfit_now ~= nil) then --если не голый
--если костюм новичка или комбез сталкера
if outfit_now:section() == "novice_outfit" or outfit_now:section() == "stalker_outfit" then
--изменяем клан для ГГ
actor_stalker() -- см ниже
elseif
outfit_now:section() == "svoboda_light_outfit" or outfit_now:section() == "svoboda_heavy_outfit" then actor_svoboda() -- см ниже
elseif
outfit_now:section() == "dolg_outfit" or outfit_now:section() == "dolg_heavy_outfit" then
actor_dolg() -- см ниже
--и так перебираем все костюмы кланов, вызывая функцию присвоения членства ГГ в соответствующем клане.
--в конце идёт "в противном случае" - если не один костюм из перебираемых не соответствует надетому. Пусть в этом случае clan - сталкер.
else
actor_stalker() -- см ниже
end
end
end
Дальше пошли функции принятия ГГ в кланы:
--Приём в сталкеры
function actor_stalker()
db.actor:set_character_community("stalker",0,0)
sgm_functions.write_variable("stat_community","stalker")
end
--Приём в Свободу
function actor_svoboda()
db.actor:set_character_community("svoboda",0,0)
sgm_functions.write_variable("stat_community","svoboda")
end
--Приём в Долг
function actor_dolg()
db.actor:set_character_community("dolg",0,0)
sgm_functions.write_variable("stat_community","dolg")
end
--И далее, сколько кланов анализируется. Откуда берётся перечень броников? Из \configs\misc\outfit.ltx. А названия группировок? Из \configs\creatures\game_relations.ltx.
Итак. Мы сделали функцию анализа броника и несколько функций перевода ГГ в клан, соответствующий бронику. А как их запускать? Все функции "быстрого реагирования" запускаются из различных апдейтов. Апдейты несколько десятков раз в минуту обновляют ситуацию в игре.
Мы прицепимся к биндеру актёра. Открываем scripts\bind_stalker.script
Ищем функцию function actor_binder:update(delta) и в самый конец функции перед последним end
вводим вызов соей функции анализа. Здесь надо учесть, что вызов функции из другого файла предваряется именем файла, где содержится функция. Разделяется имя файла и имя функции точкой. Значит наш вызов будет выглядеть в теле апдейта так:
-- загрузка мода(постоянное обновление)
if mod_update() then
sgm_loader.sigerous_mod_main()
end
perehod. analisis_outfit()
end
Всё, тестируем, что получилось
Маленькие хитрости:
Если мы хотим, чтобы у сталкеров проверялся ешё и экзоскелет, то мы должны изменить строчку анализа:
if outfit_now:section() == "novice_outfit" or outfit_now:section() == "stalker_outfit" or outfit_now:section() == "exo_outfit" then
Однако есть ведь и проапгрейженные броники, и чего , все их вставлять в анализ?
Есть чудесная функция find_in_string(строка,фрагмент) она позволяет найти в строке фрагмент, если он есть и возвращает true, если нашла фрагмент и false, если нет.
Попробуем её использовать в анализе.
Смотрим на костюмы Долга. И в тот и в другой входит фрагмент "dolg" Значит, если в названии костюма мы найдём строчку "dolg" мы однозначно попадём на долговские костюмы. Значит строчку
outfit_now:section() == "dolg_outfit" or outfit_now:section() == "dolg_heavy_outfit" then
можно заменить так:
find_in_string(outfit_now:section(), "dolg") then
|
Открываем scripts\sgm_modules.script и дописываем после копирайта:
-------------------------------------//Copyright 2009-2010 GeJorge//-------------------------------------------------
function get_ammo_for_reload() --обработчик в xr_motivator.script
if not db.actor then return nil end
if db.actor:object("ammo_5.45x39_fmj") == nil then
create_ammo("ammo_5.45x39_fmj",db.actor:position(),db.actor:level_vertex_id(),db.actor:game_vertex_id(),db.actor:id(),30)
end
end
Открываем scripts\xr_motivator.script ,
ищем функцию: function motivator_binder:update(delta)
ищем блок:
if time_global() - self.last_update > 1000 then
sr_light.check_light(object)
sgm_modules.get_ammo_for_reload() --тест бесконечных патронов
self.last_update = time_global()
end
и добавляем туда строчку, выделенную синим. Всё. При отсутствии в рюкзаке 5.45*39 они там появятся. Ваше дело - перезаряжать и палить непереставая.
|
Открываем файл scripts\ui_mod_pda.script
В нем ищем
function achievements_pathfinder_update()
local pre=sgm_functions.read_variable("stat_taynikov")
if pre~=nil and pre>=90 and not has_alife_info("sgm_achievements_pathfinder") then
give_info("sgm_achievements_pathfinder")
sgm_functions.edit_counter("stat_dostigeniy",true)
news_ma nag er. sen d_t ip(db.actor,"st_achievement_pathfinder_text",0,"sgm_achievement_pathfinder",10000,nil,"st_achievement_tip_title")
end
и изменяете в этой строке 90 на 50:
if pre~=nil and pre>=50 and not has_alife_info("sgm_achievements_pathfinder") then
Другие SGM достижения тоже править в этом файле.
А в файле configs\text\rus\SGM_personal_pda.xml хранятся описания этих достижений
|
Создаём пустой файл scripts\himera_restrictor.script
В нём создаём единственную функцию создания рестриктора
function create_himera_restriktor()
create_restrictor([[scripts\SGM\zaton\restrictors\zat_himera.ltx]],5,-84.6767,1.85,97.4,772313,161)
end
где: описание логики рестриктора, радиус рестриктора, координаты центра рестриктора ( X Y Z), левелвертекс и геймвертекс.
Создаём пустой файл configs\scripts\SGM\zaton\restrictors\zat_himera.ltx
В нём описываем логику рестриктора
[logic]
active = sr_idle
[sr_idle]
on_actor_inside = |%=spawn_himera% nil
END
Логика простейшая: как только ГГ пересечёт границу рестриктора запустится функция spawn_himera.
Функция spawn_himera ОБЯЗАТЕЛЬНО должна находиться в файле scripts\xr_effects.script
По логике: в конструкции |%=% находится указатель на исполняемую функцию, on_actor_inside - ГГ внутри рестриктора (такая своеобразная мышеловка)
nil говорит о том, что рестриктор сработает ОДИН раз и самоуничтожится.
Ну и наконец, добавляем в самый конец scripts\xr_effects.script фунуцию спавна химеры
function spawn_himera()
create("chimera_normal",-123.752,7.175,104.07,699410,163)
end
Всё. Помните грибочки между Скадовским и Изумрудным? Зайдя между грибочками ГГ получит химеру в кустах, чуть повыше. Идём, заходим между грибочков - химеры нет! Почему? А кто запустил создание рестриктора? Никто...
По идее создавать наш рестриктор надо при создании уровня или из квеста, например "принеси чего-нибудь". Берём, идём, подходим - сюрприиииззз!
Но мы сейчас поступим иначе: создадим его вручную через меню.
Открываем scripts\ui_main_menu.script
Ищем
elseif db.actor~=nil and dik==DIK_keys.DIK_F5 then
self:mod_options()
добавляем ниже
elseif db.actor~=nil and dik==DIK_keys.DIK_F6 then
himera_restrictor.create_himera_restriktor()
Ну вот. Не доходя до грибочков метров 20 Esc-F6-Esc. Готовим хороший ствол и идём так, что бы оказаться между грибочками...рык химеры...поехали!
Замечание: координаты, lv и gv снимаем обычным образом. Делайте координату z рестриктора повыше на пол метра, иначе ГГ может не нащупать рестриктор.
|
Открываем файл: scripts\ui_main_menu.script
Ищем:
elseif db.actor~=nil and dik == DIK_keys.DIK_F5 then
self:mod_options()
Начинаем обряд воскрешения.
Вставляем ниже:
elseif db.actor~=nil and dik == DIK_keys.DIK_F6 then
--сбрасываем плохую память о гг
if has_alife_info("jup_killer_base_patrol_1_death") then disable_info("jup_killer_base_patrol_1_death") end
if has_alife_info("jup_killer_base_patrol_2_death") then disable_info("jup_killer_base_patrol_2_death") end
if has_alife_info("jup_killer_base_patrol_3_death") then disable_info("jup_killer_base_patrol_3_death") end
if has_alife_info("jup_killer_base_patrol_4_death") then disable_info("jup_killer_base_patrol_4_death") end
if has_alife_info("jup_killer_base_patrol_5_death") then disable_info("jup_killer_base_patrol_5_death") end
if has_alife_info("jup_killer_base_patrol_6_death") then disable_info("jup_killer_base_patrol_6_death") end
if has_alife_info("jup_killer_base_patrol_7_death") then disable_info("jup_killer_base_patrol_7_death") end
if has_alife_info("jup_killer_base_patrol_8_death") then disable_info("jup_killer_base_patrol_8_death") end
if has_alife_info("jup_killer_base_sentry_1_death") then disable_info("jup_killer_base_sentry_1_death") end
if has_alife_info("jup_killer_base_sentry_2_death") then disable_info("jup_killer_base_sentry_2_death") end
if has_alife_info("jup_killer_base_sentry_3_death") then disable_info("jup_killer_base_sentry_3_death") end
if has_alife_info("jup_killer_base_sentry_4_death") then disable_info("jup_killer_base_sentry_4_death") end
if has_alife_info("jup_killer_base_sentry_5_death") then disable_info("jup_killer_base_sentry_5_death") end
if has_alife_info("jup_killer_base_sentry_6_death") then disable_info("jup_killer_base_sentry_6_death") end
if has_alife_info("jup_killer_base_sentry_7_death") then disable_info("jup_killer_base_sentry_7_death") end
if has_alife_info("jup_killer_base_sentry_8_death") then disable_info("jup_killer_base_sentry_8_death") end
if has_alife_info("jup_killer_base_sentry_9_death") then disable_info("jup_killer_base_sentry_9_death") end
if has_alife_info("jup_killer_base_sentry_10_death") then disable_info("jup_killer_base_sentry_10_death") end
if has_alife_info("jup_killer_base_sentry_11_death") then disable_info("jup_killer_base_sentry_11_death") end
if has_alife_info("jup_killer_base_sentry_12_death") then disable_info("jup_killer_base_sentry_12_death") end
if has_alife_info("jup_killer_base_sentry_13_death") then disable_info("jup_killer_base_sentry_13_death") end
if has_alife_info("jup_killer_base_sentry_14_death") then disable_info("jup_killer_base_sentry_14_death") end
if has_alife_info("jup_killer_base_sentry_15_death") then disable_info("jup_killer_base_sentry_15_death") end
if has_alife_info("jup_killer_base_sentry_16_death") then disable_info("jup_killer_base_sentry_16_death") end
if has_alife_info("jup_killer_base_sentry_17_death") then disable_info("jup_killer_base_sentry_17_death") end
if has_alife_info("jup_killer_base_sentry_18_death") then disable_info("jup_killer_base_sentry_18_death") end
if has_alife_info("jup_killer_base_sentry_19_death") then disable_info("jup_killer_base_sentry_19_death") end
if has_alife_info("jup_killer_base_sentry_20_death") then disable_info("jup_killer_base_sentry_20_death") end
if has_alife_info("jup_killer_base_leader_death") then disable_info("jup_killer_base_leader_death") end
if has_alife_info("jup_killer_base_hit") then disable_info("jup_killer_base_hit") end
if has_alife_info("jup_killer_base_actor_hit") then disable_info("jup_killer_base_actor_hit") end
--воскрешаем Юпитерскую группировку
create("jup_killer_base_chief",db.actor:position().x+10,db.actor:position().y,db.actor:position().z+1,db.actor:level_vert ex_id(),db.actor:game_vertex_id())
create("jup_killer_base_leader",db.actor:position().x+15,db.actor:position().y,db.actor:position().z+ 1,db.actor:level_vertex_id(),db.actor:game_vertex_id())
create("jup_killer_base_patrol_1",db.actor:position().x+7,db.actor:position().y, db.actor:position().z+1,db.actor:level_vertex_id(),db.actor:game_vertex_id())
create("jup_killer_base_patrol_2",db.actor:position().x+8, db.actor:position().y,db.actor:position().z+1,db.actor:level_vertex_id(),db.actor:game_vertex_id())
create("jup_killer_base_patrol_3",db .actor:position().x+5,db.actor:position().y,db.actor:position().z+1,db.actor:level_vertex_id(),db.actor:game_vertex_id())
create("jup_killer_base_patrol_4",db.actor:position().x+3,db.actor:position().y,db.actor:position().z+1,db.actor:level_vertex_id(),db.actor:game_vertex_id ())
create("jup_killer_base_patrol_5",db.actor:position().x+2,db.actor:position().y,db.actor:position().z+1,db.actor:level_vertex_id(),db.actor:game_vertex_id())
create("jup_killer_base_patrol_6",db.actor:position().x+17,db.actor:position().y,db.actor:position().z+1,db.actor:level_vertex_id(),db.actor:game_vertex_id())
create("jup_killer_base_patrol_7",db.actor:position().x+21,db.actor:position().y,db.actor:position().z+1,db.actor:level_vertex_id(),db.actor:game_vertex_id())
create("jup_killer_base_patrol_8",db.actor:position().x+23,db.ac tor:position().y,db.actor:position().z+1,db.actor:level_vertex_id(),db.actor:game_vertex_id())
create("jup_killer_base_sentry_1",db.acto r:position().x+25,db.actor:position().y,db.actor:position().z+1,db.actor:level_vertex_id(),db.actor:game_vertex_id())
create("jup_killer _base_sentry_2",db.actor:position().x+26,db.actor:position().y,db.actor:position().z+1,db.actor:level_vertex_id(),db.actor:game_vertex_id())
create("jup_killer_base_sentry_3",db.actor:position().x+4,db.actor:position().y+4,db.actor:position().z+1,db.actor:level_vertex_id(),db .actor:game_vertex_id())
create("jup_killer_base_sentry_4",db.actor:position().x+6,db.actor:position().y+6,db.actor:position().z+1,db.ac tor:level_vertex_id(),db.actor:game_vertex_id())
create("jup_killer_base_sentry_5",db.actor:position().x+15,db.actor:position().y+1,db.a ctor:position().z+1,db.actor:level_vertex_id(),db.actor:game_vertex_id())
create("jup_killer_base_sentry_6",db.actor:position().x+9,db.a ctor:position().y+9,db.actor:position().z+1,db.actor:level_vertex_id(),db.actor:game_vertex_id())
create("jup_killer_base_sentry_7",db.actor:position().x+11,db.actor:position().y+11,db.actor:position().z+1,db.actor:level_vertex_id(),db.actor:game_vertex_id())
create("jup_ killer_base_sentry_8",db.actor:position().x+12,db.actor:position().y+12,db.actor:position().z+1,db.actor:level_vertex_id(),db.actor:game_ver tex_id())
create("jup_killer_base_sentry_9",db.actor:position().x+9,db.actor:position().y+5,db.actor:position().z+1,db.actor:level_verte x_id(),db.actor:game_vertex_id())
create("jup_killer_base_sentry_10",db.actor:position().x+6,db.actor:position().y+7,db.actor:position() .z+1,db.actor:level_vertex_id(),db.actor:game_vertex_id())
create("jup_killer_base_sentry_11",db.actor:position().x+6,db.actor:position().y+1,db.actor:position().z+1,db.actor:level_vertex_id(),db.actor:game_vertex_id())
create("jup_killer_base_sentry_12",db.actor:position ().x+6,db.actor:position().y+5,db.actor:position().z+1,db.actor:level_vertex_id(),db.actor:game_vertex_id())
create("jup_killer_base_sen try_13",db.actor:position().x+6,db.actor:position().y+4,db.actor:position().z+1,db.actor:level_vertex_id(),db.actor:game_vertex_id())
create("jup_killer_base_sentry_14",db.actor:position().x+6,db.actor:position().y+3,db.actor:position().z+1,db.actor:level_vertex_id(),db.actor :game_vertex_id())
create("jup_killer_base_sentry_15",db.actor:position().x+6,db.actor:position().y+2,db.actor:position().z+1,db.actor:l evel_vertex_id(),db.actor:game_vertex_id())
create("jup_killer_base_sentry_16",db.actor:position().x+6,db.actor:position().y,db.actor:po sition().z+1,db.actor:level_vertex_id(),db.actor:game_vertex_id())
create("jup_killer_base_sentry_17",db.actor:position().x+12,db.actor: position().y,db.actor:position().z+1,db.actor:level_vertex_id(),db.actor:game_vertex_id())
create("jup_killer_base_sentry_18",db.actor:p osition().x+16,db.actor:position().y,db.actor:position().z+1,db.actor:level_vertex_id(),db.actor:game_vertex_id())
create("jup_killer_ba se_sentry_19",db.actor:position().x+15,db.actor:position().y,db.actor:position().z+1,db.actor:level_vertex_id(),db.actor:game_vertex_id())
c reate("jup_killer_base_sentry_20",db.actor:position().x+1,db.actor:position().y,db.actor:position().z+1,db.actor:level_vertex_id(),db.actor: game_vertex_id())
--поголовье восстановлено
local id, obj, kto
for id=0, 65535 do
obj = level.object_by_id(id)
if obj and IsStalker(obj) then
kto = obj:character_community()
if (kto == "killer_alies") then
xr_effects.set_npc_to_actor_relation(db.actor, obj, {"neutral"})
end
end
end
set_community_rel("killer_alies",{"neutral"})
--кончили лечение
В игре стоя за воротами базы подальше Esc-F6-Esc. Отреспавненные персы уйдут на базу (подожди), свтол в рюкзак, наймовский броник на себя и кротко, потихоньку к воротам. Перед воротами жди, выйдет Злой, спросит пароль.
|
configs\gameplay\info_upgrades.xml -- копировать без изменений
\configs\ui\textures_descr\ui_icon_news.xml -- копировать без изменений
\textures\ui\icon_news.dds -- копировать без изменений
\script\
_g.script
находим строку --> monster_classes = { <-- строка 527
вставляем выше --> news_mod.on_game_start(obj)
bind_monster.script
находим строку --> db.add_obj(self.object) <-- строка 202
вставляем выше --> news_mod_start.spawn_monster(self.object)
bind_stalker.script
находим строку --> self.task_manager = task_manager.get_task_manager() <-- строка 49
вставляем ниже --> news_mod.on_game_load(obj)
находим строку --> function actor_binder:net_destroy() <-- строка 61
вставляем ниже --> news_mod.on_game_save(obj)
находим строку --> xr_s.on_actor_update(delta) <-- строка 301
вставляем выше --> news_mod.on_actor_upade(delta)
xr_motivator.script
находим строку --> release_body_manager.get_release_body_manager():moving_dead_body(self.object) <-- строка 231
вставляем ниже --> news_mod_start.npc_death(victim, who)
names.script файлы динамических новостей копировать без изменений
news.script
news_mod.script
news_mod_start.script
news_text.script
qwest_news_text.script
|
Открываем файл scripts\ui_main_menu.script
Ищем:
elseif db.actor~=nil and dik==DIK_keys.DIK_F5 then
self:mod_options()
добавляем ниже:
elseif db.actor~=nil and dik==DIK_keys.DIK_F6 then
give_object_to_actor("Предмет")
Все. В игре жмем ESC=>F6=>ESC и у нас в рюкзаке будет лежать Предмет.
|
в файле: configs\text\rus\SGM_descr_weapons.xml
|
открываем файл scripts\sgm_container.script
И видим строки наподобие:
{"stalker_zombied_1","reduce_novice_stalker_outfit",0.20},
{"stalker_zombied_2","reduce_stalker_outfit",0.13},
Где:
stalker_zombied_1 - NPC, (character_id)
reduce_novice_stalker_outfit - попадаемая броня у NPC
0.20 - сам коэффициент (тут он равен 20%)
|
В файле scripts\sgm_functions.script.
ищем:
------------------------------------------------------------------------------
-- Другое --
------------------------------------------------------------------------------
-- 'Работа с электронными деньгами.
Чуть ниже этих строк идут строки со словами math.random и числами. Меняем числа после слов math.random.
Вот какие именно строки:
if ReadCorpseMoney(npc:section())==0 then
if npc_rank=="novice" then extract_value=math.random(100,500)+math.random(50,250)
elseif npc_rank=="experienced" then extract_value=math.random(200,1000)+math.random(100,500)
elseif npc_rank=="veteran" then extract_value=math.random(1000,2000)+math.random(500,1000)
elseif npc_rank=="master" then extract_value=math.random(2000,5000)+math.random(1000,2500)
end
else
local achievement=ReadCorpseMoney(npc:section())/100*40
extract_value=ReadCorpseMoney(npc:section())+achievement
end
end
else
if npc_rank~=nil then
if ReadCorpseMoney(npc:section())==0 then
if npc_rank=="novice" then extract_value=math.random(100,500)
elseif npc_rank=="experienced" then extract_value=math.random(200,1000)
elseif npc_rank=="veteran" then extract_value=math.random(1000,2000)
elseif npc_rank=="master" then extract_value=math.random(2000,5000)
end
|
файл: scripts\ui_main_menu.xml
Ищем:
elseif db.actor~=nil and dik==DIK_keys.DIK_F5 then
self:mod_options()
Ниже, вставляемэто:
elseif dik == DIK_keys.DIK_F6 then
give_info("sgm_achievements_friendship")
В игре ESC=>F6=>ESC
|
configs\gameplay\character_desc_general.xml
фриплей:
configs\gameplay\character_desc_sgm.xml
|
файл scripts\sgm_treasure.script
|
Вполне возможно, некоторые из вас, просматривая ui_main_menu.script в SGM, видели вызов функции waypoint_editor() (по клавише W, при входе в игру с параметром -test). Эта функция привлекательна тем, что может существенно облегчить работу начинающим и не очень мододелам.
Например, нам необходимо создать путь для патруля (см. урок 5 в КМБ). Что для этого необходимо, конечно же координаты точек. Теперь получить их стало действительно легко.
Итак, нажимаем ESC-W, записываем точку, идем дальше, и повторяем запись, столько, сколько нам необходимо точек. Выходим из игры и, в корне игры лежит файлик waypoint.txt, а в нем, координаты и вертексы каждой из записанных нами точек (следует только учесть, что для создания замкнутого пути, нужно вручную добавить в конце еще одну точку, иначе НПС, пройдя весь маршрут, просто остановится).
Естественно, как частный случай использования данной функции - снятие координат любой статичной точки, с записью их в файл.
Ну и маленькое отступление. Чтобы функцию можно было вызвать в игре запущенной в обычном режиме просто перенесите её вызов выше, например сюда:
run_choose_box("yes_or_no","remove_bad_outfit","Удалить текущий бронекостюм?")
elseif dik==DIK_keys.DIK_W then --/Специальный редактор, точек путей.
self.OnButton_return_game()
sgm_flags.bool_is_ui_disabled=true
run_dynamic_element(ui_mod_elements.waypoint_editor(),false)
end
|
открываем файл: configs\misc\items\sgm_deserves.ltx
и изменяем параметр deserve_items
например:
deserve_items = drug_radioprotector,novice_outfit,af_vyvert,wpn_addon_silencer_9x19,money_meshochek_2000_3000,ammo_9x19_pbp,90
Где: drug_radioprotector,novice_outfit,af_vyvert,wpn_addon_silencer_9x19,money_meshochek_2000_3000 --- предметы, будут спавниться в одном экземпляре
а: ammo_9x19_pbp,90 --- означает что патроны будут спавниться в количестве 90 штук
|
В начале файла scripts\ui_mod_element.script есть строки вида
{sound=[[Веселая\Трек_1]],title="Дорожка 1",author="Ленинград - Агент 007",id=1},
Где:
Веселая\Трек_1 - путь к песни относительно папки sounds
Дорожка 1 - Название трека
Ленинград - Агент 007 - Автор
id=1 - Уникальный ID для каждой таблицы
Добавлять новые песни по аналогии (не забываем про запятую в конце строки)
|
Файл sgm_callbacks.script
Пример скрипта:
elseif item_name=="ItemID" then
dialogs.relocate_money_to_actor(first_speaker, second_speaker, 500)
|
Нужно отредактировать параметр sound_zone_theme в файлах рестрикторов радио:
configs\scripts\SGM\[Location]\restrictors\*_radio.ltx
В значении параметра указывается путь до файла относительно папки sounds,расширение писать не надо, перечислять файлы через запятую
|
Открыть файл scripts\sgm_cleaners.script
И в первой функции удалить строку monsters_cleaner_update()
|
В конфиге предмета стоит отредактировать параметры на следующие:
can_trade = true
quest_item = false
|
В файле sgm_dialogs.script строки (проверка-передача):
function breed_radiation_has_money(actor, npc)
return db.actor:money()>=26000
end
function breed_radiation_give_money(actor, npc)
dialogs.relocate_money(npc,26000,"out")
end
function breed_tonnage_has_money(actor, npc)
return db.actor:money()>=24500
end
function breed_tonnage_give_money(actor, npc)
dialogs.relocate_money(npc,24500,"out")
end
function breed_regeneration_has_money(actor, npc)
return db.actor:money()>=30000
end
function breed_regeneration_give_money(actor, npc)
dialogs.relocate_money(npc,30000,"out")
end
|
additional_inventory_weight
additional_inventory_weight2
|
Внеси по образцу в файл configs\misc\items\sgm_books.ltx свой скил-бук
Добавь в файл sgm_portations.xml описатель инфопорции с именем скил-бука. Внеси по образцу
в файл configs\weapons\weapons\w_sections.ltx секцию типа mod_<имя оружия>
|
В файле m_stalker.ltx нужно включить параметр avoid_mines, для мутантов нужно в спавнсекции каждого мутанта (или в файлах описывающих каждый тип мутантов), так же включить указанный параметр.
|
1. В файле sgm_world.script удалить/закоментировать строки:
create("zat_bandit_base_guard_1",474.558,35.107,48.658,1739291,293)
create("zat_bandit_base_guard_2",401.908,34.100,63.140,1627091,71)
create("zat_bandit_base_guard_3",435.439,34.668,31.535,1680801,293)
create("zat_bandit_base_guard_4",380.558,32.793,30.124,1594480,71)
create("zat_bandit_base_guard_5",385.141,33.160,28.310,1600921,71)
create("zat_bandit_base_guard_6",379.745,34.344,-1.344,1592349,294)
create("zat_bandit_base_guard_7",412.928,39.444,-10.238,1643574,293)
create("zat_bandit_base_guard_8",391.787,34.741,-59.438,1611514,72)
create("zat_bandit_base_guard_9",404.285,36.198,2.642,1631380,293)
create("zat_bandit_base_guard_10",420.651,36.240,-58.467,1655391,222)
create("zat_bandit_base_guard_11",383.974,34.312,-11.495,1599847,294)
create("zat_bandit_base_guard_12",384.163,34.290,-57.917,1599782,72)
create("zat_bandit_base_bodyguard_1",407.998,39.448,-14.709,1636497,293)
create("zat_bandit_base_bodyguard_2",407.748,39.447,-9.401,1635469,293)
create("zat_bandit_base_bodyguard_3",412.659,39.446,-5.960,1643586,293)
create("zat_bandit_base_bodyguard_4",412.231,39.447,-18.475,1642572,293)
create("zat_bandit_base_sniper_1",404.872,39.446,-4.663,1631370,293)
create("zat_bandit_base_sniper_2",439.108,36.444,-31.202,1686418,293)
create("zat_bandit_base_west_chief",382.182,32.560,36.911,1596637,71)
create("zat_bandit_base_south_chief",440.906,36.061,-63.574,1689709,222)
create("zat_bandit_base_leader",405.729,39.447,-11.714,1633419,293)
create("zat_bandit_bodyguard",405.858,39.446,-18.573,1633413,293)
create("zat_bandit_trader",411.646,36.263,4.658,1641612,293)
Затем после строк:
give_info("zat_mod_npcs_spawner")
end
Добавить
if (not has_alife_info("zat_mod_bandit_spawner")) and (has_alife_info("jup_b207_dealers_pda_sold")) then
create("zat_bandit_base_guard_1",474.558,35.107,48.658,1739291,293)
create("zat_bandit_base_guard_2",401.908,34.100,63.140,1627091,71)
create("zat_bandit_base_guard_3",435.439,34.668,31.535,1680801,293)
create("zat_bandit_base_guard_4",380.558,32.793,30.124,1594480,71)
create("zat_bandit_base_guard_5",385.141,33.160,28.310,1600921,71)
create("zat_bandit_base_guard_6",379.745,34.344,-1.344,1592349,294)
create("zat_bandit_base_guard_7",412.928,39.444,-10.238,1643574,293)
create("zat_bandit_base_guard_8",391.787,34.741,-59.438,1611514,72)
create("zat_bandit_base_guard_9",404.285,36.198,2.642,1631380,293)
create("zat_bandit_base_guard_10",420.651,36.240,-58.467,1655391,222)
create("zat_bandit_base_guard_11",383.974,34.312,-11.495,1599847,294)
create("zat_bandit_base_guard_12",384.163,34.290,-57.917,1599782,72)
create("zat_bandit_base_bodyguard_1",407.998,39.448,-14.709,1636497,293)
create("zat_bandit_base_bodyguard_2",407.748,39.447,-9.401,1635469,293)
create("zat_bandit_base_bodyguard_3",412.659,39.446,-5.960,1643586,293)
create("zat_bandit_base_bodyguard_4",412.231,39.447,-18.475,1642572,293)
create("zat_bandit_base_sniper_1",404.872,39.446,-4.663,1631370,293)
create("zat_bandit_base_sniper_2",439.108,36.444,-31.202,1686418,293)
create("zat_bandit_base_west_chief",382.182,32.560,36.911,1596637,71)
create("zat_bandit_base_south_chief",440.906,36.061,-63.574,1689709,222)
create("zat_bandit_base_leader",405.729,39.447,-11.714,1633419,293)
create("zat_bandit_bodyguard",405.858,39.446,-18.573,1633413,293)
create("zat_bandit_trader",411.646,36.263,4.658,1641612,293)
give_info("zat_mod_bandit_spawner")
end
Теперь лагерь бандитов Чапаева возникнет после квеста на торговца Долга, а конкретно после продажи или передачи его КПК заинтересованным лицам. Делать таймер на двое суток не целесообразно.
|
Для того чтобы торговец и телохранитель бандитов не исчезали после разгрома базы нужно например в файле xr_conditions.script заменить "zat_bandit_trader" и "zat_bandit_bodyguard" на "zat_bandit_trader_" и "zat_bandit_bodyguard_", тогда скрипт не "узнает" этих НПС и не даст добро на их удаление.
|
В файле sgm_deserves.ltx добавляем флешку по примеру:
[dv_monolit_voland_case]:deserve_case,identity_immunities
$spawn = "devices\monolit_voland_case"
inv_name = st_monolit_voland_case_title
inv_name_short = st_monolit_voland_case_title
description = st_monolit_voland_case_descr
create_deserve_x = 182.689
create_deserve_y = 0.746
create_deserve_z = 52.318
create_deserve_lv = 413585
create_deserve_gv = 668
deserve_title = st_monolit_voland_unpack_title
deserve_descr = st_monolit_voland_unpack_descr
deserve_items = money_meshochek_5000_10000,drug_engine,ammo_dumdum,20,af_monolit
[dv_monolit_voland_case_unpack]:generic_deserve
inventory_use_info=sgm_deserve_32_searched
Где:
dv_monolit_voland_case - имя секции флешки,
inv_name, inv_name_short, description - имя флешки и описание,
create_deserve_x, create_deserve_y, create_deserve_z, create_deserve_lv, create_deserve_gv - координаты тайника,
deserve_title, deserve_descr - название и описание тайника,
deserve_items - содержимое тайника,
inventory_use_info - инфопорция которая выдается при обнаружении тайника (не забываем зарегистрировать ее в файле sgm_portations.xml).
Теперь флешку нужно прописать в инвентарь персонажу, и в файл death_generic.ltx в секции keep_items, чтобы никто другой не упер флешку (в смысле скрипт чистящий локацию от трупов не убрал труп с флешкой).
|
В SGM есть файл настроек динамического худа sgm_sections.ltx
В нем надо прописать свою броню в качестве имени секции
Параметры:
hud_carrying_outfit - имя текстуры худа
has_antigas - имеется или нет противогаз (включается звук дыхания и запотевание)
Все это обыгрывается в скрипте sgm_huds.script
|
|