Перейти к контенту

Рекомендуемые сообщения

Tris   

Как изменить эффекты при нахождении в оазисе [ЗП]

В скрипте

xr_effects (по default) на строке 2688 есть функция:
Она и отвечает за эффекты в оазисе.
function oasis_heal()
    local d_health = 0.005
    local d_power = 0.01
    local d_bleeding = 0.05
    local d_radiation = -0.05
    if(db.actor.health<1) then
        db.actor.health = d_health
    end
    if(db.actor.power<1) then
        db.actor.power = d_power
    end
    if(db.actor.radiation>0) then
        db.actor.radiation = d_radiation
    end
    if(db.actor.bleeding>0) then
        db.actor.bleeding = d_bleeding
    end
        db.actor.satiety = 0.01
end

например, так:

function oasis_heal()
    local d_health = 0.005
    local d_power = 0.01
    local d_bleeding = 0.05
    local d_radiation = 0.05
    if(db.actor.health<1) then
        db.actor.health = d_health
    end
    if(db.actor.power<1) then
        db.actor.power = d_power
    end
    if(db.actor.radiation>0) then
        db.actor.radiation = d_radiation
    end
    if(db.actor.bleeding>0) then
        db.actor.bleeding = d_bleeding
    end
        db.actor.satiety = 0.01
end

теперь находясь в оазисе, радиация будет прибавляться.


Как сделать изношенное снаряжение в начале игры ЗП

В скрипте xr_effects есть такая функция:
(Находится она на строке: 2787)
Она и отвечает за изношенность предметов.

function damage_actor_items_on_start(actor, npc)
    local actor = db.actor

    local obj = actor:object("helm_respirator")
    if obj ~= nil then
        obj:set_condition(0.8)
    end

    obj = actor:object("stalker_outfit")
    if obj ~= nil then
        obj:set_condition(0.76)
    end

    obj = actor:object("wpn_pm_actor")
    if obj ~= nil then
        obj:set_condition(0.9)
    end

    obj = actor:object("wpn_ak74u")
    if obj ~= nil then
        obj:set_condition(0.7)
    end

end

Если вы добавили в начало игры новое оружие, можно расширить функцию например так:

function damage_actor_items_on_start(actor, npc)
    local actor = db.actor

    local obj = actor:object("helm_respirator")
    if obj ~= nil then
        obj:set_condition(0.8)
    end

    obj = actor:object("stalker_outfit")
    if obj ~= nil then
        obj:set_condition(0.76)
    end

    obj = actor:object("wpn_pm_actor")
    if obj ~= nil then
        obj:set_condition(0.9)
    end

    obj = actor:object("wpn_ak74u")
    if obj ~= nil then
        obj:set_condition(0.7)
    end

    obj = actor:object("wpn_vintorez")
    if obj ~= nil then
        obj:set_condition(0.7)
    end

end

Теперь добавленное оружие тоже будет немного повреждено.

 

Изменено пользователем World_Stalker

  • http://www.amk-team.ru/forum/uploads//ratings/wrench_orange.png × 1

Поделиться этим сообщением


Ссылка на сообщение
Поделиться на других сайтах

[ЧН] Спавн сквадов и их параметры

Все параметры вытащил из

sim_squad_scripted.script, итак следующие параметры можно указать в ltx-файлах squad_descr_*
[squad_name] ;Имя сквада
auto_id = true/false ;Автоматический выбор командира
faction = army ;группировка
npc = npc_1, npc_2, npc_3, npc_4, npc_5 ;НПС
target_smart = smart_terrain_name ;Смарт в который пойдет отряд
on_death = %+infoportion% ;Инфа после смерти отряда
attack_power = 400 ;Число прибавляеющееся при атаке на смарт(чем больше тем лучше)
invulnerability = true/false ;Бессмертие
relationship = friend/enemy/neutral ;Отношение к ГГ
sympathy = 0.1 ;Симпатия
show_spot = true/false ;Показывать отметку на карте
always_walk = true/false ;Состояние в котором передвигается отряд
spawn_point = spawn_point_smart ;Спавн точка смарта

 

 

Изменено пользователем World_Stalker

  • http://www.amk-team.ru/forum/uploads//ratings/thumb_up.png × 1

Поделиться этим сообщением


Ссылка на сообщение
Поделиться на других сайтах

Внесу и свою лепту которую все знают кроме новичков разве что.

Лезем в файл

gamedata\configs\weapons\weapons.ltx
под секцией [ammo_base] есть строка:
;belt = true;

меняем её на это:

belt = true

И можем вешать патроны на пояс. Когда там нет игра автоматом берёт из рюкзака.
В зп на версии 1.6.00 при смене автоматных патронов на патроны для дробовика случался вылет stace trase. Но вроде бы только один раз.

 

Изменено пользователем World_Stalker

Поделиться этим сообщением


Ссылка на сообщение
Поделиться на других сайтах

Язык программирования Lua. Учебник для начинающих.
Скачать в формате .txt

Взято с сайта:
http://big.vip-zone.su/doc/devel/lua.xml

Изменено пользователем World_Stalker

Поделиться этим сообщением


Ссылка на сообщение
Поделиться на других сайтах
ColR_iT   

"Горячие клавиши"

Пролог

Я несколько сомневался стоит ли размещать статью здесь, ведь по сути это просто копи-паст, но тем не менее оставить это без внимания я не смог. К тому же "рекламу" такому стоит сделать и я думаю многие со мной согласятся.

Экспозиция

С самой зари модостроения многие задавались вопросом: можно ли осуществить горячие клавиши назначенные на пользовательские действия? Ответ за частую был отрицательным. Никаких функций разработчики не предоставили, а методы для тех горячих клавиши, что используются игрой прописаны в движке. Нужно было как-то находить выход из сложившейся ситуации, ведь горячие клавиши предоставляли бы весьма обширный потенциал...

Завязка

Говоря правду, игра предоставляет возможность отслеживать нажатие клавиши, правда происходит это только для элементов оконных классов, один из которых - это экран главного меню. В нём можно произвести определённое действие закреплённое за определённой клавишей. Но тот факт, что для использования клавиш необходимо выходить в главное меню - подвергало сомнениям использование данного метода в геймплее, это скорее могло пригодиться в отладочных целях.

Со временем была найдена ещё одна клавиша, нажатие которой можно отловить, причём непосредственно во время игрового процесса. Это клавиша Tab. Ведь именно она при нажатии отображает название текущего задания на экране. И вот именно этим моментом и воспользовались модостроители. Дело в том, что имя задания выводится не просто текстом, а посредством так называемого элемента "кастом статик" (custom static), дабы не углубляться в дебри терминологии, назовём это окошком, только с прозрачной рамкой, и внутри которого и отображается текст. Окошко это имеет имя - main_task. Именно благодаря этому можно отследить наличие на экране в данный момент времени присутствие этого статика, что определяет нажатие клавиши Tab. Но и это не было идеальным решением. С этим появлялись некоторые неудобства, в частности использование нужных действий в строго определённой ситуации. Данный способ весьма успешно используется в моде OGSE 0692, в нём клавиша Tab используется в качестве задействования пулемёта в БТР, открывание багажника, в других случаях применение антирадина. Казалось бы всё хорошо, но все эти манипуляции требуют строгих условий: для включения пулемёта - нахождение главного героя в БТР, для открытия багажника - нахождение главного героя позади авто, при этом каждое действие автоматически исключало другие варианты последствия нажатия клавиши. В данной ситуации, исключая мелкие неувязки, этот метод весьма к стати. Но что если нужно привязывать и другие действия, такие как: поедание еды, применение алкоголя - организовать эти действия на работе одной клавиши весьма не простая задача, а в данном случае и не реализуемая.

Развитие действия

Через некоторое время, на сцене появляется Keylogger. Динамически подключаемая библиотека, позволяющий отслеживать нажатие клавиш и сопутствующие этому действия. Библиотека хоть и решала проблему с нехваткой горячих клавиш, но почему-то не набрала популярности среди модостроя. Ещё позже появляются правки xrGame.dll, которые в полной мере могут повторить тот же функционал.

Всё это весьма полезно, за что авторам данных изобретений большое спасибо. Но что на счёт реализовать подобное скриптово, лишь стандартными методами и способами, которые может предоставить нам игра? В очередной раз скажете "нет"? Не торопитесь ...

Кульминация

- Привет, как дела?

- Привет! Хорошо всё.

- Ты когда нибудь слышал о консольной команде bind_console?

- Нет, а для чего она?

- Позволяет назначить выполнение консольной команды на клавишу.

- Здорово! Это ведь можно ...

Это можно реализовать полноценный перехватчик нажатия клавиш.

Изречение: "Всё гениальное - просто" - и здесь нашло своё место.

Идея довольно проста. Консольная команда bind_console, присутствующая в игре ещё с билда 1957, позволяет назначить выполнение другой консольной команды на незадействованную клавишу на клавиатуре. Это означает, что вот такая строка набранная в консоле:

bind_console demo_record 1 knumpad0

назначит консольную команду demo_record со значением 1 на клавишу "0" на цифровой клавиатуре. Таким образом на любую клавишу можно назначить любую консольную команду.

"Ну и для чего?" - скажете Вы - "Ведь консольные команды не позволяют выполнять функции из скриптов!" - и в этом Вы будете абсолютно правы. Но! Стандартные функции позволяют получить значение передаваемое консольной команде, а поскольку назначить на клавишу мы можем любую консольную команду, то достаточно использовать ту, которая не задействована в сингл игре. И такая команда есть - mm_net_player_name - задаёт имя игрока в мультиплеере.

Если собрать эти сведения воедино, то для полноты картины необходимо в качестве параметра передавать идентификатор нажатой кнопки и отлавливать это значение на апдейте.

Финал

Метод работает на любой версии игры, однако нельзя использовать уже задействованные клавиши, т.к. они будут переопределены на другое действие. Следует также помнить, что при открытом диалоговом окне оно перехватывает обработку клавиш и нажатия не отлавливаются.

local con = nil -- переменная для объекта консоли
local con_command = "mm_net_player_name" -- консольная команда
local def_value = "_" -- значение по умолчанию - символ подчеркивания

function update()
  if not con then -- инициализируем схему
   con = get_console() -- кешируем консоль
   con:execute( con_command .." ".. def_value ) -- инициализируем дефотлным значением, т.к. кнопка не нажата
   for k,v in pairs(_G[script_name()]) do -- перебираем функции в текущем файле
   -- v это функция и её имя является кодом клавиши
      if type(v)=='function' and DIK_keys[string.upper(k)] then
       local key = "k"..string.gsub(k,"dik_","") -- формируем ключ и
       con:execute("bind_console "..con_command.." "..k.." "..key) -- биндим кнопку на него
      end
   end
  else
   -- получаем из консоли значение параметра для нашей команды
   local str = con:get_string(con_command)
   -- если оно не является значением по умолчанию
   -- и в этом файле есть функция с таким именем, то выполняем её
   if str~=def_value and this[str] then
      this[str]()
      con:execute(con_command.." "..def_value) -- записываем значение по умолчанию
   end
  end
end

function dik_numpad0()
  news_manager.send_tip(db.actor,"нажали кнопку numpad0")
end

function dik_numpad1()
  news_manager.send_tip(db.actor,"нажали кнопку numpad1")
end

function dik_numpad2()
  news_manager.send_tip(db.actor,"нажали кнопку numpad2")
end

При нажатии клавиш "0", "1" или "2" цифровой клавиатуры будет выведено соответствующее каждой кнопке сообщение.

 

Помните способ организации горячей клавиши посредством кнопки Tab? Аналогичным способом можно отслеживать не только нажатие но и отпускание клавиши. В этом нам поможет ещё одна консольная команда bind_sec, позволяющая определить вторую горячую клавишу на одно и то же действие.

local con = nil
local con_command = "mm_net_player_name"
local def_value = "_"
local act_key = "" -- последняя нажатая клавиша

function update()
  if not con then
   con = get_console()
   con:execute(con_command .." " .. def_value)
   for k,v in pairs(_G[script_name()]) do
      if type(v)=='function' and DIK_keys[string.upper(k)] then
       local key = "k"..string.gsub(k,"dik_","")
       con:execute("bind_console "..con_command.." "..k.." "..key)
      end
   end
  else
   local str = con:get_string(con_command)
   if str~=def_value and this[str] then
      this[str]()
      con:execute(con_command .." " .. def_value)

      --отлова отпускания
      -- биндим на показ статика активного квеста нажатую кнопку
      con:execute("bind_sec scores k"..string.gsub(str,"dik_",""))
      -- если статик ещё не показан, то показываем его
      -- он будет висеть пока не отпущена клавиша
      local cs = get_hud():GetCustomStatic("main_task") or get_hud():AddCustomStatic("main_task")
      -- задаем 100% прозрачность тексту, чтоб не светился без нужды
      cs:wnd():SetTextColor(0,240,217,182)
      act_key = str -- запоминаем нажатую кнопку
      news_manager.send_tip(db.actor,"нажали "..act_key)
   end
  end

  -- отлов отпускания
  local cs = get_hud():GetCustomStatic("main_task")
  if act_key~="" and not cs then -- была нажата клавиша, а статика нет
   con:execute("unbind_sec scores")
   news_manager.send_tip(db.actor,"отпустили "..act_key)
   act_key=""
  end

end

function dik_numpad0()
end

function dik_numpad1()
end

function dik_numpad2()
end

При нажатии клавиши "0" на дополнительной клавиатуре будет выведено сообщение "нажали 0", а при отпускании - "отпустили 0".

 

Функцию update вызываем из колбека update класса actor_binder, иными словами - из апдейта биндера актора. Имена функций берутся из класса-перечисления DIK_keys, описание которого можно найти в lua_help.script.

Титры

Авторы: Charsi & Shadows.

Оригинал статьи на S.T.A.L.K.E.R. Inside Wiki: ссылка.

 


  • http://www.amk-team.ru/forum/uploads//ratings/wrench_orange.png × 1

Поделиться этим сообщением


Ссылка на сообщение
Поделиться на других сайтах
ColR_iT   

"Динамическое подключение/отключение функций"

 

 

Думаю многим известно, что такое файл bind_stalker.script. В этом файле прописан класс actor_binder обрабатывающий действия актора. Всего в классе семнадцать методов. Коротко расскажу о назначении каждого:

__init - вызывается единожды при создании экземпляра класса, т.е. в случае актора - один раз при начале новой игры;
net_spawn - вызывается при спавне актора, т.е. при загрузке (загрузка сохранения, переход между локациями);
net_destroy - противоположный предыдущему метод. Вызывается при удалении актора. В игре это единственный момент - момент перед загрузкой другой локации во время перехода;
reinit - вызывается после net_spawn и представляет из себя инициализацию объекта актора. Примечателен метод тем, что в нём устанавливаются колбеки;
take_item_from_box - вызывается, когда ГГ берёт вещи из объекта inventory_box;
level_border_enter - вызывается, когда ГГ входит в разрешенную границу уровня;
level_border_exit - вызывается, когда ГГ покидает разрешенную границу уровня;
Как именно определяются границы уровня я не знаю. Но эти колбеки нужны для схемы xr_detector.script, которая в свою очередь реагирует на данные действия повышением уровня радиации, когда мы заходим в запрещённую зону на границе уровня.
info_callback - вызывается при выдачи ГГ любой инфопорции;
on_trade - вызывается при нажатии кнопки "Торговать" в акне торговли;
article_callback - вызывается во время выдачи статьи в энциклопедии;
on_item_take - вызывается в момент появления в инвентаре ГГ любого предмета;
on_item_drop - противоположный предыдущему метод. Вызывается, когда из инвентаря удаляется любой предмет;
task_callback - вызывается для обработки заданий в ПДА. В какие именно моменты это происходит сказать сложно, скорее всего с некоторой периодичностью;
map_location_added_callback - вызывается во время установки какой-либо метки на карте ПДА;
update - знаменитый "апдейт". Вызывается движком постоянно, довольно часто (несколько десятков раз в секунду);
save - вызывается при сохранении;
load - соответственно при загрузке.

Самым частым в использовании является метод update. Именно в него неосведомлённый модостроитель порою "заталкивает" такое, что волосы становятся дыбом, и невероятно часто данный метод используют для одноразовых "заданий", прописывая проверку инфопорции, чтобы результат не проверялся несколько раз, но тем не менее проверка продолжает выполняться. А что если использовать updateпо требованию и когда необходимость в нём отпадает - убирать проверку? Как? Оказывается не очень то и сложно...
Таковым функционалом обладает файл xr_s.script из папки скриптов ЧН или ЗП. Знающий скрипты человек, уделив некоторое внимание данному файлу, сам поймёт как его использовать, не знающий - будет долго всматриваться в код в поисках знакомых слов. Ничего страшного в этом нет - самообразование всегда похвально, я же помогу Вам разобраться в коде окончательно.
Идея скрипта как раз в том и состоит, чтобы в нужный момент подключить любую функцию к одному из колбеков, включая update, и когда необходимость в функции отпадёт - убрать её от туда, тем самым избавив колбек от лишней работы. При этом список колбеков можно свободно расширить, и подключать функцию можно вообще по сути куда угодно. Итак, давайте разберём файл более подробно.

Сразу скажу, что в файле присутствуют функции, которые не относятся к "подключению" функций, поэтому речь пойдёт только о тех функциях, которые нам понадобятся.
Таблица callbacks.
Таблица состоящая из пары ключ - значение, где ключом выступает имя колбека в который подключается функция, значение - это таблица содержащая параметры для нашей функции, если она их требует. Звучит сложно, но Вы поймёте на примере, который будет ниже.

Далее идут две функции:
function register_callback (name, func, userobj)
Функция "регистрирует" нашу функцию в указанном колбеке.
Принимает следующие параметры:
name - называние колбека из таблицы callbacks в который мы подключаем нашу функцию;
func - ссылка на нашу функцию. Указывается её имя без кавычек! Если функция находится в другом файле, ты в ссылке через точку указывается и модуль в котором расположена функцию;
userobj - параметры, которые принимает наша функцию. Если параметров несколько, то нужно передавать параметры в таблице.
function unregister_callback (name, func)
Функция удаляет нашу функцию из указанного колбека.
Принимает следующие параметры:
name - называние колбека из таблицы callbacks из которого мы удаляем нашу функцию;
func - ссылка на нашу функцию. Указывается её имя без кавычек! Если функция находится в другом файле, ты в ссылке через точку указывается и модуль в котором расположена функцию.

Далее идут одиннадцать однотипных функций. Их нужно вписывать по сути в одноимённые функции в скриптах. Т.е. к примеру функция on_actor_update нужно вписывать в метод update биндера актора (файл bind_stalker.script).

Подозреваю, что вышеизложенный текст, не для всех является простым, но изложить доступно словами всю идею, не отклоняясь от основной мысли (динамическое "включение" функций) достаточно сложно. Я стараюсь, на сколько это возможно, придерживаться этого компромисса, поэтому, если Вам не понятен текст выше, прочитайте его ещё раз, чтобы у Вас была теория "на уме", а не бегать в последствии глазами по тексту - так Вам же будет проще.

Перейдём, так сказать, к делу...
В качестве примера приведу решение того, как реализовать убирание оружия во время приёма аптечки. Вопрос достаточно часто задают в соседней теме, поэтому это будет актуально, интересно, а самое главное наглядно отобразит основную идею динамического "включения" функций.

Сначала, расскажу алгоритм, т.е. как это реализуется "на словах".
Нужно отследить момент использования аптечки; затем запустить таймер, на время которого убирать оружие; и по окончании работы таймера, дать возможность вновь им пользоваться.
А теперь реализация...
Момент использования аптечки можно отследить в колбеке актора on_item_drop, но это будет не совсем правильно, так как убираться оружие будет и тогда, когда мы просто выбросим/переложим/продадим аптечку, а нам этого не нужно. Поэтому мы используем колбек именно на использование предмета use_object. В ЗП он есть, в ТЧ также есть, т.е. предусмотрен движком, но не используется. Если Вы делаете это для ТЧ, то нужно добавить метод в биндер актора, который будет отрабатывать во время использования предмета. Делается это так:
В методе reinit того же биндера установим колбек на "юз", прописав вот это в тело метода:self.object:set_callback(callback.use_object, self.use_inventory_item, self)А также в метод net_destroy добавить вот такую строку:self.object:set_callback(callback.use_object, nil)Теперь нам нужно добавить сам метод. В любое место файла (но НЕ во внутрь какой-либо функции!!!), например перед строкой:function actor_binder:update(delta)добавьте следующий код:function actor_binder:use_inventory_item(obj)
endИменно эта функция, а точнее метод биндера, будет вызываться, когда вы будете использовать какой-то предмет.
Нас интересует конкретно аптечка, при этом не важно какая: простая, армейская или научная. Чтобы не прописывать три условия, проверяющие секции аптечек на соответствие, мы используем одну, в которой проверим, что в секции присутствует слово "medkit". Это будет чуть быстрее и универсальнее. Универсальность заключается в том, что Вы можете добавить новые медпрепараты и если Вы хотите того же эффекта и от них, Вам достаточно задать название секции со словом "medkit", например "medkit_special" или "special_medkit". Проверка выглядит так:if string.find(obj:section(), "medkit") then
endЭту проверку нужно добавить в ново созданный (в случае ТЧ) метод use_inventory_item.
Момент использования аптечки мы отследили. Теперь нужно запустить таймер на время работы которого убирать оружие. Вот здесь и выходит на передний план функции файла xr_s.script.
Сама функция реализующая таймер не сложна и выглядит так (предположим, что она находится в файле use_med.script):function MedkitUsing(userObj)
--# Прячем оружие.
bind_stalker.hide_weapon()
--# Проверим работает ли ещё таймер?
--# userObj[1] - время начала работы таймера;
--# userObj[2] - время работы таймера (мсек)
if time_global() > userObj[1] + userObj[2] then
--# Работа таймера закончена - покажем оружие.
bind_stalker.restore_weapon()
end
endПринимает в качестве параметра таблицу с двумя элементами: первый - это время запуска, второй - время работы таймера в миллисекундах.
Эту функцию нужно "вешать" на апдейт, т.к. нужно постоянно проверять значение таймера. Если просто вставить это как есть, то, во-первых - нужно прописывать дополнительную проверку, что использована аптечка, во-вторых - проверяться условие будет всегда. Поэтому подключим её динамически.
В проверку использования аптечки в колбеке use_object нужно добавить вот такой вызов:xr_s.register_callback("update", use_med.MedkitUsing, {time_global(), 4000})Что это всё означает? Я описывал эту функцию, теперь для ясности давайте сопоставим переданные параметры с описанием выше:
"update" - это name, т.е. имя "колбека" из таблицы callbacks;
use_med.MedkitUsing - это ссылка на функцию, которую мы "включаем". Обратите внимание на способ подключения, указывается в каком файле находится функция и не пишется никаких скобок, не говоря уже о параметрах;
{time_global(), 4000} - помните я говорил, что функция принимает таблицу из двух элементов? Так вот это они и есть. Таблица передаётся в качестве параметра в нашу функцию.
Добавив такой вызов, функция начнёт работать на ближайшем апдейте. Всё хорошо - функция отрабатывает, когда мы используем аптечку, но как остановить работу, чтобы разгрузить апдейт? Здесь нам поможет функция unregister_callback из файла xr_s.script. Нужно вписать вызов этой функции в том месте, где работа таймера закончена. После строки:bind_stalker.restore_weapon()допишите:xr_s.unregister_callback ("update", use_med.MedkitUsing)Параметры передаваемые идентичны предыдущей только лишь отсутствуют параметры, т.к. в них нет надобности.
По окончании работы таймера, появиться возможность пользоваться оружием и функция "выключится" разгрузив тем самым апдейт.
Как видите - всё просто, даже слишком. На самом деле это не всё. В апдейт всё же придётся навсегда вписать вызов одной функции, это функция on_actor_update из файла xr_s.script. Именно эта функция будет проверять есть ли у нас другие функции которые требуется подключить к апдейту. Здесь возможно расхождение в понимании того, что же мы делаем и вообще для чего, для чего делать проверку, если задача стоит в том, чтобы избавиться от неё?
В данном примере это сопоставимо с обычной проверкой использовали ли мы аптечку или нет на самом апдейте. А что если таких "примеров" несколько - три, пять, десять? Вот именно здесь данный способ вне конкуренции. Одна проверка, которая контролирует десяток-другой вызовов, при этом те функции, которые не нуждаются в работе находятся "в спящем режиме", если так можно сказать и не используют ресурсы требуемые на постоянную проверку - "а нужно ли нам работать?".

Пример вышел тривиальным, но более чем наглядным. Естественно его можно развить, добавить медленное восстановление здоровья, ограничить возможность использования нескольких аптечек подряд, пока работает таймер и т.д. Развитие функционала уже выходит за рамки "урока", поэтому это остаётся на Ваших плечах.
Всё работает без вылетов, лично преверял на ТЧ 1.0006. Хотя это и предполагается на ТЧ, но работать будет и на ЧН и на ЗП.

 

 

Вот некоторые соответствия того, какую функцию из xr_s.script куда прописывать и какой "колбек" из таблицы callbacks использовать в последствии:
 

 

 

Имя функции из xr_s.script -> Имя функции куда вписывать -> Какой "колбек" из таблицы использовать для подключения/отключения

on_actor_update -> actor_binder:update (bind_stalker.script) -> update
on_game_load -> actor_binder:net_spawn (bind_stalker.script) -> game_load
on_actor_destroy -> actor_binder:net_destroy (bind_stalker.script) -> actor_destroy
on_npc_hit -> motivator_binder:hit_callback (xr_motivator.script) -> npc_hit
on_monster_hit -> generic_object_binder:hit_callback (bind_monster.script) -> monster_hit
on_main_menu_on -> main_menu:__init (ui_main_menu.script) -> main_menu_on
on_main_menu_off -> main_menu:OnButton_return_game (ui_main_menu.script) -> main_menu_off
on_item_drop -> actor_binder:on_item_drop (bind_stalker.script) -> item_drop

 

Изменено пользователем BFG

  • http://www.amk-team.ru/forum/uploads//ratings/wrench_orange.png × 3

Поделиться этим сообщением


Ссылка на сообщение
Поделиться на других сайтах

Ставим новые метки в ПДА [ЗП]
Дело было как ни странно, днём... Появилась необходимость поставить метки переходов с одной локации на другую - покопавшись малость в теме "ковырялки ЗП" увидел, что до меня были такие попытки создания меток, но по-крупному копаться в скриптах я не люблю по причине неопытности в скриптах - решил сделать сам.
 
Для начала идём в pda.script:
После таблицы под названием sleep_zones_tbl добавим ещё одну, должно получиться так:

local sleep_zones_tbl =
{
    {target = "zat_a2_sr_sleep_id",        hint = "st_ui_pda_sleep_place"},
    {target = "jup_a6_sr_sleep_id",        hint = "st_ui_pda_sleep_place"},
    {target = "pri_a16_sr_sleep_id",    hint = "st_ui_pda_sleep_place"},
    {target = "escape_podval_sr_sleep_id",    hint = "st_ui_pda_sleep_place"},
    {target = "garbage_base_sr_sleep_1_id",    hint = "st_ui_pda_sleep_place"},
    {target = "garbage_base_sr_sleep_2_id",    hint = "st_ui_pda_sleep_place"},
    {target = "garbage_dolg_zastava_sr_sleep_id",    hint = "st_ui_pda_sleep_place"},
}       -- это таблица отметок спального места, её мы не трогаем
 
local level_changer_tbl =
{
    {target = "perehod_darks_esc",        hint="perehod_darks_esc_name"},
    {target = "id_перехода",                    hint="надпись над переходом"},
}     --А это наша новая таблица, содержащие переходы и надписи над ними

 

 
После этой добавки идём в самый конец файла и добавляем саму функцию показания перехода

function fill_level_changers()
    for k,v in pairs(level_changer_tbl) do
        local obj_id = get_story_object_id(v.target)
        if(obj_id) then
            level.map_add_object_spot(obj_id, "level_changer_up", v.hint)
        end
    end
end

 


Где, ui_inGame2_icon_level_changer - имя значка нашего перехода, можно поставить из оригинальной игры, но я создам свой
Итак, теперь нам нужно создать вызов нашей функции - далеко ходить не будем (ибо лень :russian_ru: ): находим функцию fill_primary_objects и добавляем вызов нашей: 

function fill_primary_objects()
    for k,v in pairs(primary_objects_tbl) do
        local obj_id = get_story_object_id(v.target)
        if(obj_id) then
            level.map_add_object_spot(obj_id, "primary_object", v.hint)
        end
    end
    change_anomalies_names()
    fill_sleep_zones()
    fill_level_changers() --Вот вызов нашей функции
end

 


Со скриптами мы закончили, теперь нужно создать наш переход и текст к нему.
Для того, чтобы наш переход отображался нужно придать ему id, для этого создадим его секцию в all.spawn, но с одной добавкой:

[8057]
; cse_abstract properties
section_name = level_changer
name = perehod_darks_esc
position = -618.825927,-2.623994,-380.298706
direction = 0,0,0
cse_abstract__unk1_h16 = 0x1
; cse_alife_object properties
game_vertex_id = 1789
distance = 0
level_vertex_id = 404
object_flags = 0xffffff3e
custom_data = <<END ;Вот тут и нужно добавить его id, а далее - как раньше
[story_object]
story_id = perehod_darks_esc
END

; cse_shape properties
shapes = shape0
shape0:type = sphere
shape0:offset = 0,0,0
shape0:radius = 6
; cse_alife_space_restrictor properties
restrictor_type = 3
; cse_alife_level_changer properties
dest_game_vertex_id = 1407
dest_level_vertex_id = 593260
dest_position = 363.344421,15.172136,-39.722797
dest_direction = 0,0,0
dest_level_name = l01_escape
dest_graph_point = start_actor_01
silent_mode = 1
; se_level_changer properties

 


Идём в st_land_names.xml и добавляем в конец файла описания наших переходов:

<!-- Переходы -->
<string id="perehod_darks_esc_name">
        <text>На Кордон</text>
</string>
<!-- Переходы -->

 


 
1733042.jpg - Результат
 
Собственно всё, таким образом можно создать не только отметки переходов, но и для чего-другого с разными иконками (в данном случае, ну никак иконки "спального места" и "интересного места" под переход не подходили) - допустим, для любителей "читерки", можно добавить отметку к укрытиям (добавив в секцию укрытия в all.spawn строки присвоения id) или чего-другого, это зависит от потребности.

Изменено пользователем World_Stalker

  • http://www.amk-team.ru/forum/uploads//ratings/thumb_up.png × 1

Поделиться этим сообщением


Ссылка на сообщение
Поделиться на других сайтах

Создание инвентарного комплекса в чистом ЗП

Перед тем, как начать урок, я хочу сказать, что скриптовой частью я обязан товарищу Ховану и Николаю Болтову. Именно благодаря их скриптам я нашел способ сделать подобную вещь! Огромное им спасибо!
А теперь перейдем к уроку.

Файлы, которые нам потребуются:
- configs/misc/items.ltx
- configs/text/rus/st_items_equipment.ltx
- scripts/_g.script
- scripts/bind_stalker.script
- scripts/my_callbacks.script

Возможно, вы когда-нибудь задумывались над вопросом создания предмета, из при использовании которого в инвентарь будут выпадать сразу несколько других, как, например, универсальный медкомплект. Долго думая, я понял, что такого эффекта можно достичь используя коллбеки на использовании предметов.
Что такое "коллбек"? Если коротко, - это что-то в роде скрипта инфопорции. Однако, коллбек может работать как единожды, так и постоянно: при подборе предметов, при их использовании, при выстреле, при попадению по нпс и так далее. Нас интересует коллбек использования предмета, который будет работать постоянно.

1. Откроем items.ltx и скопируем секцию какого-нибудь бустера. Вставим новую секцию где-нибудь в это-же файле.
2. Настроим его так, как нам этого захочется.
[medkit_complex]:booster
$spawn     = "food and drugs\medkit_complex"
visual    = dynamics\devices\dev_aptechka\dev_aptechka_mid.ogf
description   = st_medkit_complex_desc
inv_name   = st_medkit_complex
inv_name_short          = st_medkit_complex
inv_weight   = 1.8
inv_grid_width     = 2
inv_grid_height    = 2
inv_grid_x         = 10
inv_grid_y         = 27
cost    = 30000
attach_angle_offset  = 0.440521, 1.378287, -0.644026
attach_position_offset         = 0.104196, -0.010821, 0.076969
attach_bone_name  = bip01_r_hand
auto_attach   = false
bone_name   = bip01_r_hand
position_offset   = 0.0,0.0,0.0
angle_offset   = 1.570790,1.570790,3.92699
use_sound   = interface\inv_medkit
Долго здесь зацикливаться не будем. Все элементарно. Могу только сказать, что при использовании будет проигрываться звук аптечки, а модель взяли армейской аптечки.
3. В st_items_equipment.ltx создаем описание и название предмета
<string id="st_medkit_complex">
                     <text>Универсальный медкомплект</text>
                    </string>
                    <string id="st_medkit_complex_desc">
                     <text>Специальный медкомплект, разработанный для спецслужб в Зоне. Включает в себя все основные медикаменты.</text>
                    </string>
На этом с конфигами все.
4. Руководствуясь материалом, взятым из сборника модостроения от Хована, мы создаем файл my_callbacks.script в папке scripts.
5. Наполняем его следующим образом
function on_use_item(sect)
--Переменные
local actor=db.actor
local item_name=sect:section()
local actor_pos=db.actor:position()
local active_slot=db.actor:active_slot()
local active_item=db.actor:active_item()
local pistol_in_slot=db.actor:item_in_slot(2)
local rifle_in_slot=db.actor:item_in_slot(3)
local outfit_in_slot=db.actor:item_in_slot(7)
local helm_in_slot=db.actor:item_in_slot(12)
--Коллбеки
if item_name=="medkit_complex" then
give_object_to_actor("drug_anabiotic")
give_object_to_actor("antirad")
give_object_to_actor("bandage")
give_object_to_actor("drug_radioprotector")
give_object_to_actor("drug_antidot")
give_object_to_actor("drug_psy_blockade")
give_object_to_actor("drug_coagulant")
give_object_to_actor("drug_booster")
end
end
give_object_to_actor - как-раз и есть скрипт выдачи ГГ предмета, опираясь на коллбек. В скобках название предмета.
Вообщем, продолжаем так-же, и добавляем, что хотим. Надеюсь, принцип ясен.
6. Зарегистрируем наш файл в bind_stalker.script. Там находим функцию function actor_binder:use_inventory_item(obj) и под вторым end прописываем
if obj~=nil then
                       my_callbacks.on_use_item(obj)
                       end
В целом выглядит так:
function actor_binder:use_inventory_item(obj)
                    if(obj) then
                     local s_obj = alife():object(obj:id())
                     if(s_obj) and (s_obj:section_name()=="drug_anabiotic") then
                      xr_effects.disable_ui_only(db.actor, nil)
                      level.add_cam_effector("camera_effects\\surge_02.anm", 10, false, "bind_stalker.anabiotic_callback")
                      level.add_pp_effector("surge_fade.ppe", 11, false)
                      give_info("anabiotic_in_process")
                      _G.mus_vol = get_console():get_float("snd_volume_music")
                      _G.amb_vol = get_console():get_float("snd_volume_eff")
                      get_console():execute("snd_volume_music 0")
                      get_console():execute("snd_volume_eff 0")
                     end
                    end
                    if obj~=nil then
                      my_callbacks.on_use_item(obj)
                       end
end
7. Осталось добавить глобальную функцию give_object_to_actor в _g.script.
Внизу пишем:
-- 'Создание предмета в рюкзаке ГГ.
function give_object_to_actor(obj,count)
                     if count==nil then count=1 end
                     for i=1, count do
                        alife():create(obj,db.actor:position(),db.actor:level_vertex_id(),db.actor:game_vertex_id(),db.actor:id())
                     end
end
На этом урок заканчивается. Осталось только прописать пак ГГ и протестировать!
 
 

Изменено пользователем FantomICW

  • http://www.amk-team.ru/forum/uploads//ratings/bf.gif × 1
  • http://www.amk-team.ru/forum/uploads//ratings/thumb_up.png × 1

Поделиться этим сообщением


Ссылка на сообщение
Поделиться на других сайтах

Добавление новых кнопок в ПДА (ЗП)

Примечание: Сей "фокус" можно проделывать только с правками от проекта X-Ray extensions, а конкретно, с правками ПДА.

 

Итак, всё-таки захотели мы создать вкладку в ПДА. Но не знаем как. Проблемы, согласен. Вот некоторая часть решения этой проблемы:

1. Заходим в pda.xml, ищем таблицу:

<tab x="443" y="57" width="468" height="27"><button x="0" y="0" width="172" height="27" id="eptTasks" hint="pda_btn_quests_hint" frame_mode="0">    <text align="c" vert_align="c" x="0" y="0" width="157" height="27" font="letterica16">pda_btn_quests</text>    <texture>ui_inGame2_pda_button</texture>    <text_color>        <t r="255" g="255" b="255"/>        <d r="255" g="255" b="255"/>        <e r="200" g="200" b="200"/>        <h r="170" g="170" b="170"/>     </text_color></button><button x="148" y="0" width="172" height="27" id="eptRanking" hint="pda_btn_ranking_hint" frame_mode="0">    <text align="c" vert_align="c" x="0" y="0" font="letterica16">pda_btn_ranking</text>    <texture>ui_inGame2_pda_button</texture>    <text_color>        <t r="255" g="255" b="255"/>        <d r="255" g="255" b="255"/>        <e r="200" g="200" b="200"/>        <h r="170" g="170" b="170"/>    </text_color></button><button x="296" y="0" width="172" height="27" id="eptLogs" hint="pda_btn_logs_hint" frame_mode="0">    <text align="c" vert_align="c" x="0" y="0" font="letterica16">pda_btn_logs</text>    <texture>ui_inGame2_pda_button</texture>    <text_color>        <t r="255" g="255" b="255"/>        <d r="255" g="255" b="255"/>        <e r="200" g="200" b="200"/>        <h r="170" g="170" b="170"/>    </text_color></button></tab>

2. Для лучшего понимания, разберём это дело по блокам:

Это блок является "колбой", в которой находятся кнопки в ПДА:

<tab x="Смещение колбы по Х" y="Смещение колбы по У" width="Ширина колбы" height="Высота колбы"></tab>

А этот блок как раз и является кнопкой:

<button x="Смещение кнопки по Х" y="Смещение кнопки по У" width="Ширина" height="Высота" id="Уникальное Айди (id) кнопки" hint="Подсказка, всплывающая при наведении на кнопку" frame_mode="0">    <text align="c" vert_align="c" x="0" y="0" font="letterica16">Ссылка на текст-описание кнопки</text>    <texture>Имя текстуры кнопки</texture>    <text_color> <!-- Цветовые настройки текста в кнопке -->        <t r="255" g="255" b="255"/>        <d r="255" g="255" b="255"/>        <e r="200" g="200" b="200"/>        <h r="170" g="170" b="170"/>    </text_color></button>

3. А теперь приступим к созданию новой кнопки:

 

В колбе, содержащей кнопки, нужно изменить параметр "Смещения по Х", отняв от значения число, равное значению "Смещения кнопки по Х" от ВТОРОЙ кнопки:

<tab x="296" y="57" width="468" height="27"></tab>

А так же, нужно к параметру "width="468"" (и последующему значению, если добавляете больше одной кнопки) прибавить число 172, которое равно ширине кнопки. Первый пункт делается для того, чтобы новая кнопка не "налезала" на другие части ПДА (Часы, другие кнопки и т.п.), а второй, чтобы кнопка была в "колбе" и была активной, то есть, доступной для нажимания.

Делается это для того, чтобы новая кнопка не "налезала" на другие части ПДА (Часы, другие кнопки и т.п.).

 

Далее, создадим саму кнопку (в данном случае для энциклопедии):

<button x="444" y="0" width="172" height="27" id="eptEncyclopedia" hint="pda_btn_encyclopedia_hint" frame_mode="0">    <text align="c" vert_align="c" x="0" y="0" font="letterica16">pda_btn_encyclopedia</text>    <texture>ui_inGame2_pda_button</texture>    <text_color>        <t r="255" g="255" b="255"/>        <d r="255" g="255" b="255"/>        <e r="200" g="200" b="200"/>        <h r="170" g="170" b="170"/>     </text_color></button>

Всё, кнопка создана и функционирует, её название некоректно отображается ("pda_btn_encyclopedia" вместо "Энциклопедия"), исправим это.

4. Идём в файл configs\text\rus\ui_st_pda.xml и добавим две секции в самый конец:

<string id="pda_btn_encyclopedia">    <text>Энциклопедия</text></string><string id="pda_btn_encyclopedia_hint">    <text>Открыть энциклопедию</text></string>

(Здесь, для энциклопедии, а вам нужно вписать ссылку на свою кнопку и её название по образцу).

Всё, теперь кнопка работает, даже отображается корректно, но не открывает новый раздел: когда нажимаем на неё, то перед нами остаётся предыдущая активная вкладка, хоть и наша новая кнопка активна.

Вот объяснение этого явления от тов. @Malandrinus:

 

Текущее содержимое окна при активации свой кнопки не убирается, поэтому придётся закрывать его своим содержимым с помощью помещения диалога поверх окна. К сожалению, получение текущего окна в ЧН и ЗП стало невозможно и пока решения этой проблемы не видно.

Так что новой вкладки мы не получим - только кнопочка. Даже не расскажу, как это окно сделать, т.к. я пробовал и у меня, пока, ничего не вышло. Будем пытаться, а пока - всё.

P.S. Вот так это будет выглядеть:

2082991.jpg

 

P.P.S. Добавлена информация, из за отсутствия которой не функционировала кнопка.

Изменено пользователем ColR_iT

Поделиться этим сообщением


Ссылка на сообщение
Поделиться на других сайтах
Файлы для работы:
Из распакованного all.spawn'а:
alife_локация.ltx

А также скрипты из gamedata\scripts :
pda.script
xr_effects.scripts


Приступим:
1) Открываем alife_локация и добавляем секцию:
[1867] ; номер секции
; cse_abstract properties
section_name = space_restrictor
name = ваше_название_места
position = -180.277893066406,9.41139984130859,77.5603179931641 ;нужная позиция (в данном случае - домик в Изумрудном)
direction = 0,0,0

; cse_alife_object properties
level_vertex_id=1233171 ; левел_вертекс
game_vertex_id=13 ; гейм_вертекс
distance = 9.09999942779541
object_flags = 0xffffff2e
custom_data = <[story_object]
story_id = ваше_название_места_id

[logic]
cfg = scripts\sr_sleep.ltx
END

; cse_shape properties
shapes = shape0,shape1
shape0:type = box
shape0:axis_x = 3.85299897193909,0,0
shape0:axis_y = 0,2.51200008392334,0
shape0:axis_z = 0,0,6.23259878158569
shape0:offset = 0,0,0
shape1:type = box
shape1:axis_x = 3.16719889640808,0,0
shape1:axis_y = 0,2.51200008392334,0
shape1:axis_z = 0,0,4.87539911270142
shape1:offset = -3.29999589920044,0,-0.199996992945671

; cse_alife_space_restrictor properties
restrictor_type = 3

Закрываем.

 

2) Заходим в pda.script, ищем:

{
{target = "zat_a2_sr_sleep_id", hint = "st_ui_pda_sleep_place"},
{target = "jup_a6_sr_sleep_id", hint = "st_ui_pda_sleep_place"},
{target = "pri_a16_sr_sleep_id", hint = "st_ui_pda_sleep_place"},
}

и меняем на это:

{
{target = "zat_a2_sr_sleep_id", hint = "st_ui_pda_sleep_place"},
{target = "jup_a6_sr_sleep_id", hint = "st_ui_pda_sleep_place"},
{target = "pri_a16_sr_sleep_id", hint = "st_ui_pda_sleep_place"},
{target = "ваше_название_места_id", hint = "st_ui_pda_sleep_place"},
}

Закрываем

 

3) Открываем xr_effects.script, ищем:

function sleep(actor, npc)
local sleep_zones = {
"zat_a2_sr_sleep",
"jup_a6_sr_sleep",
"pri_a16_sr_sleep",
"actor_surge_hide_2"
}

и меняем на это:

function sleep(actor, npc)
local sleep_zones = {
"ваше_название_места",
"zat_a2_sr_sleep",
"jup_a6_sr_sleep",
"pri_a16_sr_sleep",
"actor_surge_hide_2"
}

Всё, можно запускать игру и проверять!

 

Изменено пользователем World_Stalker

  • http://www.amk-team.ru/forum/uploads//ratings/bf.gif × 1

Поделиться этим сообщением


Ссылка на сообщение
Поделиться на других сайтах

Создание энциклопедии для ПДА в ЗП.
Примечание: Аналогично предыдущему уроку, энциклопедию реализовать можно только при помощи проекта X-Ray extensions. Для того, чтобы кнопка энциклопедии появилась, нужно выполнить мой предыдущий урок "Добавление новых кнопок в ПДА (ЗП)".
Ссылка на готовую энциклопедию+видеодемонстрация:  http://rghost.ru/47774542

Как мы уже знаем из слов тов. malandrinus, "родные" для ПДА вкладки нам нужно будет закрывать собственной. Для этого нам нужен свой GUI и нам нужна "ловля" инфопоршня при открытии вкладки. Мастерить велосипед самому мне не понравилось: хоть уроки по GUI есть, но мне показалось, что с моим опытом я могу сделать только несколько окошечек, не более. Про вкладку в ПДА, которая соответствовала бы стилю нашего электронного друга я вообще даже не мечтал, поэтому взял наработки тов.

DEXXX (записная книжка в ЧН) и Geonezis (Энциклопедия оружия, на основе предыдущей работы).

 

Скачиваем готовую энциклопедию, там есть пометки, для понимания, как это всё работает, тут объясню чуть подробней.

 

Адаптация:

С другими модами (и с оригиналом) конфликтуют только два скрипта: _g.script и bind_stalker.script. В _g.script добавлены глобальные функции:

function run_gui(gui, close_inv) --Функция для запуска GUI, в нашем случае, энциклопедии
    if close_inv == true then
        gui:ShowDialog(true)
        game_hide_menu()
        level.show_weapon(false)
    else 
	    gui:ShowDialog(true)
    end
end
function GetString(id) --Функция для инициализации имён
	if not(id) then return "" end
	return game.translate_string(id)
end

А в bind_stalker.script добавлен вызов скрипта, который отлавливает инфопоршень при открытии вкладки энциклопедии:

function actor_binder:update(delta)
gui_callbacks.on_info() --Вызов нашего "Ловчего поршней"
object_binder.update(self, delta)
...

Всё, адаптация пройдена - должна функционировать.

 

А теперь - как этой с энциклопедией работать.

Допустим, мы решили добавить нового мутанта - Тарк (Tark). Делается это так:

Добавляем этого мутанта в таблицу мутантов, что в скрипте gui_main.script:

local pda_enc_mutants={
    "Mutant_boar",
    "Flesh",
    "Pseudo_flesh",
"Tark", --Вот он
"Bloodsucker",
...

Теперь, от выбранного нами имени будет зависеть, как будет называться текстура-иконка, текст с описанием, название мутанта на "человеческом" языке (а не на машинном) и и название инфопоршня, при получении которого мы получим статью в энциклопедию.

Текстура должна иметь следующее имя: ui_enc_#Имя мутанта# .

Текст с описанием: enc_#Имя мутанта#.

Название будет равно Имени мутанта.
А инфопоршень будет "величаться": #Имя мутанта#_info.

Для лучшей ориентации и унификации, подобная структура, описанная выше, будет актуальна и для мутанта и для группировок и для всего остального. Думаю, так будет лучше.

Как я говорил ранее, инфопоршень нужно выдавать через что-либо: диалоги, награды за задания, "отловы" на то, что вы кого-то убили, либо некоторая вероятность получения поршня при обыске трупов.

Парт-текстура, по умолчанию, читается из файла ui_pda_encyclopedia.dds. Если хотим добавить иконку, то нужно вставить в файл иконку (по умолчанию, она должна быть 165 на 107 пикселей, иначе будет растянута\сплющена), измерить её координаты по аналогии с прудыдущими и задать имя, как я уже описал выше.

Описание и название указывается в фале configs\text\rus\st_notepad.xml. В принципе, можно вставить в другой файл, но лучше соблюдать порядок - вам же будет лучше.

 

Всё, на этом я удаляюсь - пользуйтесь и указывайте авторов. Доброй Зоны, сталкеры.

 

Изменено пользователем World_Stalker

  • http://www.amk-team.ru/forum/uploads//ratings/bf.gif × 1
  • http://www.amk-team.ru/forum/uploads//ratings/thumb_up.png × 1

Поделиться этим сообщением


Ссылка на сообщение
Поделиться на других сайтах

Небольшой пак уроков от меня (всего два урока, позже будут еще). Оба урока в формате .doc.

• Добавление абсолютно новых ящиков на классе inventory_box

• Показываем состояние здоровья ГГ в процентах

Надеюсь, они окажутся полезными.

Скачать : http://rghost.ru/48034494

Изменено пользователем World_Stalker

Поделиться этим сообщением


Ссылка на сообщение
Поделиться на других сайтах

Это не урок, просто небольшие памятки по некоторым вещам, которые мне были нужны.

Вся информация взята из оригинальных файлов ТЧ.

 

Настройки костей у динамического источника света

166de793236328822603d692e578fe1cb0c28716

 

Настройки комментариев у звуков монстров (в различных состояниях)

dc2ce81751c9b1c96bbe16656d57535cb0c28716

 

Конечно, это все несложно выяснить самому, но иной раз надоест все это запоминать или куда-то записывать...

 

З.Ы. такое вообще надо бы оформить в таблицу, но мне было лень это делать, поэтому как есть :)

Изменено пользователем Shadows

  • http://www.amk-team.ru/forum/uploads//ratings/thumb_up.png × 2

Поделиться этим сообщением


Ссылка на сообщение
Поделиться на других сайтах

Отключение интро-ролика, и последующий его запуск.

Примечание: Теоретически это должно работать на всех частях сталкера, но я буду показывать на примере Чистого неба.

 

Итак, начнем. Нам требуется отключить интро-ролик после начала новой игры. Проблема  в том, что запуск ролика движковый, поэтому придется изощряться. Находим в файле configs/ui/ui_movies.xml секцию "intro_game". И приводим ее к такому виду:

<intro_game>
<global_wnd x="0" y="0" width="1024" height="768">
<auto_static x="0" y="0" width="1024" height="768" stretch="1">
<texture>intro\intro_back</texture>
</auto_static>
</global_wnd>


<item type="video">
<sound>$no_sound.ogg</sound>
<delay>0</delay>
<pause_state>off</pause_state>
       <function_on_stop>xr_effects.darkness</function_on_stop>
<video_wnd x="0" y="0" width="1024" height="768" stretch="1">
<texture x="0" y="1" width="1280" height="954">intro\intro_back</texture>
</video_wnd>
</item>




</intro_game>

 

 

 

Первая часть работы сделана. Теперь при начале новой игры интро-ролика не будет. А что если нам надо его запустить впоследствии? Для этого создаем в этом же файле новую секцию, intro_game2, к примеру. И пишем в ней:

<intro_game2>
<play_each_item>1</play_each_item>
<global_wnd x="0" y="0" width="1024" height="768">
<_auto_static x="0" y="0" width="1024" height="768" stretch="1">
<window_name>back</window_name> 
<texture>intro\intro_back</texture> 
</_auto_static>
</global_wnd> 
<item type="video">
       <sound>characters_voice\scenario\video\intro</sound>
       <pause_state>on</pause_state>
       <function_on_stop>xr_effects.start_marsh_intro</function_on_stop>
       <video_wnd x="0" y="0" width="1024" height="768" stretch="1">
         <texture x="1" y="1" width="628" height="358">intro\intro_half</texture>
          </video_wnd>
          
          <background x="0" y="0" width="1024" height="768" stretch="1">
            <texture>intro\intro_back</texture>
          </background>
        </item>
<item type="image">
  <length_sec>5</length_sec>
<pause_state>off</pause_state>
<main_wnd>
<auto_static start_time="0" length_sec="5"  x="0" y="0" width="1230" height="768" light_anim="intro_1" light_anim_cyclic="0" la_alpha="1" la_texture="1" stretch="1">
<window_name>w1</window_name>
<texture>intro\intro_back</texture>
</auto_static>
</main_wnd>
</item>
</intro_game2>

 

 

Обратите внимание на поле:

<function_on_stop>xr_effects.start_marsh_intro</function_on_stop>

Здесь указывается функция, которая будет запущена по истечению туториала.

Но мы всего лишь создали новый туториал, теперь его надо запустить. Для удобства можно поместить функцию в xr_effects.script 

function go_intro()
  game.start_tutorial("intro_game2")
end

Дальше остается только запустить эту функцию, как это сделать - выбор на ваше усмотрение.

 

Изменено пользователем World_Stalker

  • http://www.amk-team.ru/forum/uploads//ratings/thumb_up.png × 3

Поделиться этим сообщением


Ссылка на сообщение
Поделиться на других сайтах
Waljok   

Так как я начинающий модостроитель, но всё же поделюсь кое-каким опытом.

Когда добавляете новую функцию с приёмом-отдачей, то всегда пишите функцию отдачи первой. Дело в том, что Меченому-Стрелку никто в Зоне не верит и сначала все требуют нужный кому либо предмет.


Сначала я не понимал, почему у меня не срабатывает функция. Но я вовремя вспомнил, что в солянке сначала ГГ отдаёт что-либо, а потом получает награду. Попробовал функцию отдачи прописать первой и - вауля, скрипт срабатывает.

 

Может быть, кому нибудь пригодится.

Изменено пользователем World_Stalker

  • http://www.amk-team.ru/forum/uploads//ratings/grey_square.png × 1

Поделиться этим сообщением


Ссылка на сообщение
Поделиться на других сайтах

Работа с Sound_occluder.
Примечание: искал (не очень тщательно) в интернете более-менее подробную инструкцию по Окклюдеру, но не нашёл. Пожалуй, черкну тут для чего он нужен и как его использовать.
Итак, вы сделали тоннель под землёй, но не отдельной локацией, а как небольшое дополнение к другой, например, как у меня: 2925626.jpg
Сделали, скомпилили локацию для пробы, но находясь в тоннеле мы слышим, как на асфальте плоти доедают бандюка, смачно чавкая и хрюкая, ещё гудение трансформатора в комнатушке, шум ветра от елей (если они являются статичным звуком на локации), а если мы на поверхности, то слышим, как в тоннеле шуршат крысы и скрепит, вращаясь, лампочка. Не порядок.
Вот для этих целей и существуют и sound_occluder - для отсечения звуков, находящихся "по ту сторону" плоскости окклюдера. Это работает как для ГГ, так и для NPC. Можно сделать окклюдер в виде плоскостей, коробок и т.п. и в СДК расставлять так, как нужно, но в данном случае, геометрия сложная и с так плоскостями придётся повозиться, поэтому сделаем в 3д редакторе. Я этот тоннель делал в Милке, там буду делать и окклюдер. Вот:
2925627.jpg
Кстати говоря, эту модель можно будет использовать и для HOM, для лучшей оптимизации.
Теперь настроим OccluderHOM. если вы захотели поставить и её) в СДК: 2925628.jpg
И ещё во вкладке Surface нужно указать параметр "2 Sided". Объект станет синим и полупрозрачным - значит, что Окклюдер готов, осталось разместить его в нужном месте.
Для того, чтобы расположить окклюдер на том же месте ,что и наш тоннель, нам нужно скопировать (ctrl+c, ctrl+v) наш тоннель и, выбрав один из них, нажать Enter и в поле Reference заменить исходную модель на наш sound_occluder, должно получится так: 2925629.jpg
Вот и всё, теперь на локации будут отсекаться звуки, проигрываемые за окклюдером, но не все!
Sound_occluder в сталкере не отсекает ambient (окружение), так как эти звуки проигрываются в позиции ГГ. Так же не отсекаются все собственные звуки ГГ, что логично. Так же окклюдер в сталкере не совершенен: в реальности, если мы находимся в том же тоннеле, то звук мы бы слышали, но тихо и со стороны выхода из него, а вот в сталкере мы не будем слышать ничего. Так же и с NPC - сли за стеной с окклюдером будет хрюкать кабан, то NPC его не услышит. Да и мы тоже...

Ссылка на скачивание архива со статьёй+иллюстрации: https://yadi.sk/d/vC18bUaZX5c7X

Изменено пользователем World_Stalker
оформил

  • http://www.amk-team.ru/forum/uploads//ratings/wrench_orange.png × 2

Поделиться этим сообщением


Ссылка на сообщение
Поделиться на других сайтах

Квест на убийство мутанта через туториал ("Press F To Win")
Платформа: Сталкер Зов Припяти 1.6.02
Автор: FantomICW, использованы наработки для Смерти Вопреки
Уровень сложности: средний (не для самых зелёных новичков)

Введение

Приветствую! К своему Дню рождения (26.07) я хотел бы преподнести Сталкер-сообществу еще один небольшой подарок. В этот раз мое внимание привлекла тема, недавно затронутая в "Вопроснице"...
Относительно недавно пользователь ap-pro Telnov1996 задал один вопрос:
Можно ли организовать скриптовые сцены борьбы с мутантами, работающие по принципу 'Press "F" to win'?
К обсуждению подключились уважаемый Dorian23Grey и, собственно, я сам. Ситуация выходит следующая:
1. Во-первых, на X-Ray сцены с анимациями в стиле CoD, Metro и т. д. делать не очень удобно, как таковые.
2. Требуется иметь отличные умения в анимации объектов.
3. Нужно настроить взаимодействие логики с таймерами и анимации.
На данный момент такое мало кто реализовывал. Однако, вариант, когда ГГ подходит к мутанту, запускается туториал с последующим выполнением убийства, - вполне реализуемая фишка. Сегодня об этом и пойдет речь.
Пускай, на Затоне в пределах Северного озера поселился уникальный болотный псевдогигант, которому совершенно плевать на пули сталкеров. Единственный быстрый способ его устранить - активировать гравитационный артефакт. Когда ГГ подойдет к мутанту с артефактом, запустится туториал с надписью "Активировать артефакт". При нажатии F, запустится функция, которая создаст на месте мутанта партикл разрыва от грави-аномалии.


Подготовка к действу

- Paint Net, Adobe Photoshop или другой редактор текстур (если кто-то будет создавать мутанту уникальную текстуру)
- Notepad++

Опять же, если желаете сделать для своего мутанта уникальную текстуру, пожалйста. Как по мне, то новую модель или текстуру стоит сделать, ибо супер-крутой псевдогиг должен как-то выделяться среди своих сородичей. Я сделал условный "ретекстур" (в кавычках, потому что ляпнуть чуток крови и "узеленить" текстуру - ретекстуром назвать нельзя) монстра под болото.:
b029acee23.png
Если кому нужна текстура, ловите (бамп подключен стандартный).

Для хорошего эффекта разрыва тела в аномалии, я буду использовать некоторые партиклы от АМК:

amk\\blow_body
amk\\zomb_explode

У кого они есть (или есть альтернативный вариант) - супер, отлично. У кого их нету - не волнуйтесь, чуть позже я загружу готовый particles.xr, а пока приложу два варианта таблицы партиклов для обоих случаев.

Если вы работаете не в СДК, а с ACDC, то вам нужно будет снять координаты для места, где будет сидеть мутант. Само место действия (примерно) показвыаю на карте:
dda2729ecf.jpg
Я прошел немного вперед к воде, снял координаты:
d7f5e24623.jpg

-19.00901222229,-7.0012526512146,526.37811279297,907875,47

 


Практика

1. В configs/gameplay/dialogs_zaton.xml добавим два новых диалога:

<dialog id="zat_super_psevdogig_take_task_dialog"> <!--Взятие квеста-->
               <dont_has_info>psevdogig_task_dialog_done</dont_has_info>
               <phrase_list>
                   <phrase id="0">
                       <text>zat_super_psevdogig_take_task_dialog_0</text>
                       <next>1</next>
                   </phrase>
                   <phrase id="1">
                       <text>zat_super_psevdogig_take_task_dialog_1</text>
           <next>2</next>
                   </phrase>
          <phrase id="2">
                       <text>zat_super_psevdogig_take_task_dialog_2</text>
           <next>3</next>
                   </phrase>
          <phrase id="3">
                       <text>zat_super_psevdogig_take_task_dialog_3</text>
           <next>4</next>
                   </phrase>
          <phrase id="4">
                       <text>zat_super_psevdogig_take_task_dialog_4</text>
           <next>5</next>
                   </phrase>
          <phrase id="5">
                       <text>zat_super_psevdogig_take_task_dialog_5</text>
           <give_info>psevdogig_task_dialog_done</give_info>
           <action>dialogs_zaton.give_super_psevdogig_task</action> <!--Выдаем задание и артефакт-->
                   </phrase>
               </phrase_list>
           </dialog>
        <dialog id="zat_super_psevdogig_task_end_dialog">
            <has_info>zat_super_psevdogig_af_activation</has_info>
               <dont_has_info>psevdogig_task_finished</dont_has_info>
               <phrase_list>
                   <phrase id="0">
                       <text>zat_super_psevdogig_task_end_dialog_0</text>
                       <next>1</next>
                   </phrase>
          <phrase id="1">
                       <text>zat_super_psevdogig_task_end_dialog_1</text>
           <give_info>psevdogig_task_finished</give_info>
           <action>dialogs_zaton.give_super_psevdogig_task_reward</action> <!--Выдаем награду-->
                   </phrase>
               </phrase_list>
           </dialog>

2. Пропишем их Бороде (секция zat_a2_stalker_barmen, файл character_desc_zaton.xml):

<actor_dialog>zat_super_psevdogig_take_task_dialog</actor_dialog>
         <actor_dialog>zat_super_psevdogig_task_end_dialog</actor_dialog>

3. В configs/text/rus/st_dialogs_zaton.xml поместим текстовку диалогов:

<string id="zat_super_psevdogig_take_task_dialog_0">
         <text>Как дела, Борода? Есть новости какие-то?</text>
        </string>
        <string id="zat_super_psevdogig_take_task_dialog_1">
         <text>Здравствуй. Новость-не новость, а у нас на Северном озере поселился какой-то убер-псевдогигант, который не дает сталкерам (да и псевдоплотям, что уж тут говорить) покоя...Тварь неубиваемая какая-то. Посоветовавшись с Гонтой, решили попробовать его (я про псевдогиганта) активацией артефакта ликвидировать. Подходящий артефакт у меня вот есть, а смельчака для этого задания найти не можем...</text>
        </string>
        <string id="zat_super_psevdogig_take_task_dialog_2">
         <text>Знаешь, я мог бы вам помочь.</text>
        </string>
        <string id="zat_super_psevdogig_take_task_dialog_3">
         <text>Ты с Цементного завода рухнул? Да эта хрень тебя может в псевдочебурек превратить...А кто мне будет все те же арты таскать? На ком Лоцман зарабатывать будет? Короче, ты уверен?</text>
        </string>
        <string id="zat_super_psevdogig_take_task_dialog_4">
         <text>Уверен. Мне скучно, прост)00)).</text>
        </string>
        <string id="zat_super_psevdogig_take_task_dialog_5">
         <text>Ну, окей, удачи. Вот тебе "Грави" для активации. Будь аккуратен.</text>
        </string>
        <string id="zat_super_psevdogig_task_end_dialog_0">
         <text>Все, старик. Нету больше твоего убер-псевдогигабайта.</text>
        </string>
        <string id="zat_super_psevdogig_task_end_dialog_1">
         <text>Вах, слушай, молодец какой! Молоток! Возьми себе печеньку.</text>
        </string>

С диалогами все. Здесь все просто, поэтому детально рассказывать о них не буду. Если же эта часть показалась Вам сложной, то, простите, этот урок не совсем для Вашего уровня знаний.

1. В configs/misc/tm_zaton.ltx добавим секция квеста:

[zat_super_psevdogig_task]
icon = ui_inGame2_Logovo_krovososov
prior = 10
storyline = false
title = {+zat_super_psevdogig_af_activation} zat_super_psevdogig_task_2, zat_super_psevdogig_task_1
descr = {+zat_super_psevdogig_af_activation} zat_super_psevdogig_task_2_text, at_super_psevdogig_task_1_text
target = {+zat_super_psevdogig_af_activation} zat_a2_stalker_barmen, zat_super_psevdogig_squad
condlist_0 = {+psevdogig_task_finished} complete

Немного разбора:
- иконка стоит от миссии на устранение логова кровососов
- задание имеет две стадии: часть на устранение мутанта и часть, которая требует поговорить с Бородой (на эту часть обновление происходит при получении инфопорции zat_super_psevdogig_af_activation, мы к ней вернемся позже)
- в первой части метка задания падает на сквад мутанта (его story_id - zat_super_psevdogig_squad), во второй - на Бороду
- квест заканчивается при получении инфы psevdogig_task_finished, которая выдается в уже созданном нами диалоге
Как видите, квест по структуре очень простой.
2. Прописываем в configs/text/rus/st_quests_zaton.xml его текстовую часть:

    <string id="zat_super_psevdogig_task_1">
       <text>Помощь криворуким: устранить убер-псевдогиганта</text>
      </string>
      <string id="zat_super_psevdogig_task_1_text">
       <text>Я оказался прав: все сталкеры на Затоне - криворукие болваны. Теперь мне нужно за них устранить очень крутого мутанта на Северном озере.</text>
      </string>
      <string id="zat_super_psevdogig_task_2">
       <text>Помощь криворуким: сломать Бороде нос</text>
      </string>
      <string id="zat_super_psevdogig_task_2_text">
       <text>Хочу сказать пару ласковых слов Бороде. Какого фига это барыго в экзе не сказало мне, что меня на озере ждет не убер-псевдогигант, а жирная зеленая Гидра Затонская?</text>
      </string>

Переходим к конфигам мутанта.

1. Файл configs/creatures/m_giant.ltx. Сделаем секцию нашего уникального псевдогиганта. Она будет почти аналогичная обычному гиганту:

[super_psevdogig]:m_gigant_e
$spawn    = "monsters\gigants\super_psevdogig"
visual    = monsters\psevdogigant\psevdogigant_uber   ;Это моя новая модель
corpse_visual      = monsters\psevdogigant\psevdogigant_uber_dead   ;Это тоже
rank    = 50  ;Увеличим ранг
spec_rank   = strong   ;Псевдик Стронг!
radiation_pp_effector_name    =  postprocess_acidic   ;Выставим кислотный постпроцесс
attack_params   = super_psevdogig_attack_params  ;Новая секция параметрво атаки
 
[super_psevdogig_attack_params]  ;Тут усилен импульс
;--------------------------------------------------------------------------------------------------------------------------------------------    -
;    anim   | time[0..1] | hit_power | impulse | impulse_dir (x,y,z)   |    Field of hit_test  (left,right, top, bottom) |    Test Dist
;--------------------------------------------------------------------------------------------------------------------------------------------    -
;Bite
stand_attack_0 =    0.25,  0.9,     200,        0.5, 1.0, 0.5,   -0.8, 0.8, -1.8, 1.8,       2.6
;Left leg Strike
stand_attack_1 =    0.40,  0.9,     150,        5.0, 2.5, 4.0,   -0.6, 0.6, -1.8, 1.8,       3.2
;Bite2
stand_attack_2 =    0.25,  0.9,     200,        0.5, 1.0, 5.0,   -0.8, 0.8, -1.8, 1.8,       2.6
stand_attack_run_0=     0.5,  0.9,     600,        0.5, 1.0, 5.0,   -0.6, 1.3, -1.8, 1.8,       3.3
jump_attack_1    =  0.1,  2.00,  1600,       0.5, 1.0, 5.0,   -1.0, 1.3, -1.6, 1.6,       5.5

2. Дальше требуется создать мутанту сквад в configs/misc/squad_descr_zaton.xml:

[zat_super_psevdogig_squad]:online_offline_group
faction = monster_special     
npc = super_psevdogig  ;НПС в скваде - наш псевдогигант
target_smart = zat_sim_2  ;Целевой смарт - полуостров на Северном озере
spawn_point = zat_sim_2_giant_home  ;Спавн поинт - поинт "логова" для мутанта
story_id = zat_super_psevdogig_squad  ;Sid совпадает с названием секции (ваш Кэп)

 

1. Прежде всего, открываем файл логики смарта полуострова - configs/scripts/zaton/smart/zat_sim_2.ltx, и внизу добавляем секцию exclusive с ссылкой на эксклюзивную логику гиганта:

[exclusive]
giant = zaton\zat_sim_2_super_psevdogig.ltx

Итак, логика нашего мутанта называется giant.
2. Переходим к самой логике. Создаем файл zaton\zat_sim_2_super_psevdogig.ltx. Заполняем его:

[logic@giant] ;Название логики - giant (смотрите выше)
suitable = {=target_squad_name(zat_super_psevdogig_squad)} true ;Логика доступна только для монстра из нашего сквада
monster_job = true
prior = 200
active = mob_home@giant
 
[mob_home@giant]
on_info = %=restore_health% ;Здоровье мутанта постоянно пополняется
;Если дистаниция до ГГ меньше 7 метров, в наличии есть квестовый артефакт, а активного туториала нету, то запускается туториал убийства:
on_info2 = {=dist_to_actor_le(7) =actor_has_item(super_psevdogig_af_gravi) !has_active_tutorial} %=run_tutorial(zat_super_psevdogig_af_tutor)%    
;Если дистаниция до ГГ больше 7 метров, в наличии есть квестовый артефакт, а туториал запущен, то запускается туториал убийства:
on_info3 = {=dist_to_actor_ge(7) =actor_has_item(super_psevdogig_af_gravi) =has_active_tutorial} %=stop_tutorial%    
;При получении инфы "zat_super_psevdogig_af_activation", убиваем НПС функцией "kill_npc" из xr_effects.script:
on_info4 = {+zat_super_psevdogig_af_activation} %=kill_npc%
;При получении инфы "zat_super_psevdogig_af_activation_begin", удаляем НПС вообще и запускаем партиклы аномалии/разрыва новой функцией    
on_info5 = {+zat_super_psevdogig_af_activation_begin} %=zat_super_psevdogig_explode_2%
path_home = giant_home ;В way_zaton.ltx это - zat_sim_2_giant_home ("логово")
;Настройки охраны "логова":
home_min_radius = 20
home_max_radius = 50
aggressive = true

3. Настало время использовать ранее снятые координаты. Распаковываем all.spawn с ACDC или же используем СДК Левел Эдитор, чтоб создать точку для монстра в way_zaton.ltx:

[zat_sim_2_giant_home]
points = p0
p0:name = wp00
p0:flags = 0x1
p0:position = -19.00901222229,-7.0012526512146,526.37811279297
p0:game_vertex_id = 47
p0:level_vertex_id = 907875

Собираем спавн.

1. В логике мы уже упомянули предмет super_psevdogig_af_gravi. Это секция квестового артефакта, который мы якобы будем активировать. Открываем configs/misc/quest_items.ltx, и добавляем туда его:

[super_psevdogig_af_gravi]:device_pda
visual    = dynamics\artefacts\af_gravi.ogf
description   = st_af_gravi_descr
inv_name   = st_af_gravi_name
inv_name_short  = st_af_gravi_name
inv_weight   = 0.5
inv_grid_x   = 15
inv_grid_y   = 0
cost    = 12000
can_trade   = false ;Нельзя продать
quest_item          = true ;Нельзя выбросить
story_id            = super_psevdogig_af_gravi

Стандартная секция квестового предмета с "родителем" device_pda.
2. Также в логике мы объявили запуск туториала:

%=run_tutorial(zat_super_psevdogig_af_tutor)%

Все туториалы игры прописываются в configs/ui/game_tutorials.xml. Вам, вполне возможно, секция ниже может показаться какой-то странной штукой. На самом деле, там все просто, но, считаю, это лучше разбирать в отдельных уроках по худу и гуи, поэтому сейчас можете не забивать голову. Самые важные параметры я укажу:

<zat_super_psevdogig_af_tutor> <!--Название-->
         <global_wnd/>     
            <item>     
                <disabled_key>quit</disabled_key>     
                <length_sec/>     
           
       <!--При нажатии F, запускается функция xr_effects.zat_super_psevdogig_explode_1-->
                <action id="use" finalize="1">xr_effects.zat_super_psevdogig_explode_1</action>     
                <guard_key>use</guard_key>
       <!----Ниже уже другие параметры-->
                <grab_input>0</grab_input>     
                    <main_wnd>
                    <!--Всякие параметры текста. Я задал 32 шрифт и красный цвет по RGB. Секция текста - st_tutor_af_activation-->        
                    <auto_static start_time="0" length_sec="5000" x="512" y="660" width="300" height="60" alignment="c" stretch="1"la_cyclic="1" la_texture="1" la_alpha="1">     
                    <text font="graffiti32" r="225" g="36" b="36" a="255" align="c">st_tutor_af_activation</text>     
                    </auto_static>     
                    </main_wnd>     
            </item>     
        </zat_super_psevdogig_af_tutor> <!--Тут секция туториала заканчивается-->

3. Дальше добавим секцию текста st_tutor_af_activation, к примеру, в ui_st_screen.xml:

<string id="st_tutor_af_activation">       
      <text>Активировать артефакт ($$ACTION_USE$$)</text>
     </string>

$$ACTION_USE$$ означает клавишу "Использовать". Это F по умолчанию

1. Начнем с диалогов. В каждом из двух мы запускаем по одной функции. Обе функции в dialogs_zaton.script. Первая:

function give_super_psevdogig_task(first_speaker, second_speaker)
       dialogs.relocate_item_section_to_actor(first_speaker, second_speaker, "super_psevdogig_af_gravi") --Выдаем "Грави"
       task_manager.get_task_manager():give_task("zat_super_psevdogig_task") --Выдаем задание
    xr_effects.create_squad(nil, nil, {"zat_super_psevdogig_squad", "zat_sim_2"}) --Спавним сквад монстра на смарте "zat_sim_2"
end

Во второй будем выдавать награду:

function give_super_psevdogig_task_reward(first_speaker, second_speaker)
    local items_pack = {
        {item = "energy_drink", amount = 2},
        {item = "medkit_army",  amount = 3},
        {item = "antirad",      amount = 2},
        {item = "vodka",        amount = 1},
        {item = "conserva",     amount = 3},
    }
       
    for k,v in pairs(items_pack) do
        dialogs.relocate_item_section_to_actor(first_speaker, second_speaker, v.item, v.amount)
    end
       
       dialogs.relocate_money_to_actor(first_speaker, second_speaker, 3000)
end

Используем условно сложную таблицу items_pack. Каждый ее элемент состоит из двух пунктов:
item - секция предмета
amount - количество, которое нужно выдать
Далее некий цикл в виде стандартного
for k,v in pairs(название_таблицы) do
Это означает, что функция ниже может выполниться для каждого элемента таблицы (v). У нас это:

dialogs.relocate_item_section_to_actor(first_speaker, second_speaker, v.item, v.amount)

Обратите внимание на v.item и v.amount.
Ну, а в выдаче денег не вижу ничего сложного.
2. Последнее, что нам нужно сделать, - это две функции: одна выдается при использовании туториала, а вторая - из логики. В xr_effects.script добавляем первую функцию:

function zat_super_psevdogig_explode_1(actor, npc)
    db.actor:give_info_portion("zat_super_psevdogig_af_activation_begin")  --Выдаем инфу
    remove_item(actor, npc, {"super_psevdogig_af_gravi"})  --Забираем у ГГ артефакт (он же активируется)
end

Опять же, ничего сложного. Два простых действия. Единственное, замечу, что remove_item - это тоже функция из xr_effects.script. Теперь добавляем вторую:

function zat_super_psevdogig_explode_2(actor, npc)
       local fx_table_1 = {
        [1] = {particle = particles_object("anomaly2\\gravity_blast_final00")},
     [2] = {particle = particles_object("anomaly2\\gravity_blast_03")},
     [3] = {particle = particles_object("anomaly2\\gravity_blast_05")},
    }    
           
       local npc_position = npc:position()
       
    for i = 1,3 do
           fx_table_1[i].particle:play_at_pos(npc_position)
    end    
       
    db.actor:give_info_portion("zat_super_psevdogig_af_activation")
    remove_squad(nil, nil, {"zat_super_psevdogig_squad"})
       
    local fx_table_2 = {
        [1] = {particle = particles_object("anomaly2\\body_tear_00")},
     [2] = {particle = particles_object("amk\\blow_body")},
     [3] = {particle = particles_object("amk\\zomb_explode")},
    }
       
    for i = 1,3 do
           fx_table_2[i].particle:play_at_pos(npc_position)
    end
end

У нас есть две таблицы. Каждая имеет три партикла (каждый партикл в функциях ниже объявляется так: таблица.particle). Зачем нужно было делить из на две таблицы? Просто лучше, чтоб партиклы грави-аномалии начали играться чуть раньше партиклов разрыва тела. Цикл здесь задан немного по-другому:

for i = 1,3 do

Гляньте на пронумерованные элементы таблиц, и все станет с этим циклом ясно.
Также надо заметить, что, поскольку функция вызывается прямо из логики НПС, мы можем задать удобную локальную переменную для объявления позиции данного НПС в реальном времени:

local npc_position = npc:position()

Кто не понял, вот это npc, после которого двоеточие, - это и есть псевдогигант. Гляньте на аргументы функции:
(actor, npc)
Итак, мы используем локальную переменную для выполнения функции с циклом/таблицей:

fx_table_1[i].particle:play_at_pos(npc_position)

Задействована движковая функция play_at_pos, предназначенная конкретно для партиклов.
Если у Вас нету партиклов АМК, то вторую таблицу изменяем:

local fx_table_2 = {
      [1] = {particle = particles_object("anomaly2\\body_tear_00")},
   [2] = {particle = particles_object("anomaly2\\body_tear_01")},
   [3] = {particle = particles_object("anomaly2\\body_tear_02")},
  }

Вот и все, со всем разобрались. Смотрим результат.

Результат


Чуть позже я также дополню материал, чтоб при ликвидации псевдогиганта игрались некоторые звуки аномалий и его самого...
Итого, ничего сверхсложного или особенного мы не сделали, но...Представьте, что мы можем использовать такую схему в связке с анимационной схваткой с химерой или сосычем. Основы есть, есть и то, к чему нужно стремиться. На самом деле, мы еще не успели перелопатить весь моддинг, не так ли? ;)На этом урок закончен. Всем большое спасибо! :)

 

Изменено пользователем Murarius

  • http://www.amk-team.ru/forum/uploads//ratings/thumb_up.png × 1
  • http://www.amk-team.ru/forum/uploads//ratings/wrench_orange.png × 1

Поделиться этим сообщением


Ссылка на сообщение
Поделиться на других сайтах

В темные времена, когда у меня были перебои с интернетом, я сохранял Web - страницы на ПК, чтобы можно было просматривать их, когда интернет отключен.

Так и появился данный пак статей о SDK 0.7, в основном о Level Editor и постройке локации. Может, кому пригодится - если тоже перебои с подключением к сети, да и просто не надо будет искать. https://yadi.sk/d/gQX8KGT6ZK6AU

Изменено пользователем World_Stalker

  • http://www.amk-team.ru/forum/uploads//ratings/bf.gif × 7
  • http://www.amk-team.ru/forum/uploads//ratings/thumb_up.png × 6
  • http://www.amk-team.ru/forum/uploads//ratings/wrench_orange.png × 6

Поделиться этим сообщением


Ссылка на сообщение
Поделиться на других сайтах

Список шрифтов для UI

Платформа: Сталкер Зов Припяти 1.6.02
Автор: FantomICW



Введение
Всем привет. Пожалуй, есть вопросы по модостроению, которые мучили меня месяцами. Один из них - список доступных для использования игровых шрифтов. Некоторые ресурсы в гугле предлагают открыть файл configs/fonts.ltx, но я так и не понял, каким образом эта вещь читается движком: названия "фонтов" не совпадают с тем, что используются в интерфейсе. Итого, данный вопрос будет пока что раскрыт наполовину. Тем не менее, благодаря исходникам движка 1.6.02, мне удалось докопаться до того самого места, где "регистрируются" реально работающие шрифты!
Предлагаю ознакомиться с этим небольшим справочником ;)


Справочная информация

Собственно, "регистрация" шрифтов проходит в файле

UIXmlInit.cpp. Строки 29-43 содержат определение переменных для большой части названий шрифтов (чуть ниже мы увидим, как эти переменные используются):


#define ARIAL_FONT_NAME   "arial"

#define MEDIUM_FONT_NAME  "medium"
#define SMALL_FONT_NAME   "small"

#define GRAFFITI19_FONT_NAME    "graffiti19"
#define GRAFFITI22_FONT_NAME    "graffiti22"
#define GRAFFITI32_FONT_NAME    "graffiti32"
#define GRAFFITI50_FONT_NAME    "graffiti50"

#define LETTERICA16_FONT_NAME    "letterica16"
#define LETTERICA18_FONT_NAME    "letterica18"
#define LETTERICA25_FONT_NAME    "letterica25"

#define DI_FONT_NAME   "di"

Структура:

#define ПЕРЕМЕННАЯ      "название"

Сама "регистрация" проходит в этом же файле, в функции InitFont:

bool CUIXmlInit::InitFont(CUIXml &xml_doc, LPCSTR path, int index, u32 &color, CGameFont *&pFnt)
{
        color = GetColor    (xml_doc, path, index, 0xff);

        LPCSTR font_name = xml_doc.ReadAttrib(path, index, "font", NULL);
        if(!font_name)
        {
         pFnt = NULL;
         return false;
        }else
        {
         if(!xr_strcmp(font_name, GRAFFITI19_FONT_NAME))
         {
          pFnt = UI().Font().pFontGraffiti19Russian;
         }
         else if(!xr_strcmp(font_name, GRAFFITI22_FONT_NAME))
         {
          pFnt = UI().Font().pFontGraffiti22Russian;
         }
         else if(!xr_strcmp(font_name, GRAFFITI32_FONT_NAME))
         {
          pFnt = UI().Font().pFontGraffiti32Russian;
         }
         else if(!xr_strcmp(font_name, GRAFFITI50_FONT_NAME))
         {
          pFnt = UI().Font().pFontGraffiti50Russian;
         }
         else if(!xr_strcmp(font_name, "arial_14"))
         {
          pFnt = UI().Font().pFontArial14;
         }
         else if(!xr_strcmp(font_name, MEDIUM_FONT_NAME))
         {
          pFnt = UI().Font().pFontMedium;
         }
         else if(!xr_strcmp(font_name, SMALL_FONT_NAME))
         {
          pFnt = UI().Font().pFontStat;
         }
         else if(!xr_strcmp(font_name, LETTERICA16_FONT_NAME))
         {
          pFnt = UI().Font().pFontLetterica16Russian;
         }
         else if(!xr_strcmp(font_name, LETTERICA18_FONT_NAME))
         {
          pFnt = UI().Font().pFontLetterica18Russian;
         }
         else if(!xr_strcmp(font_name, LETTERICA25_FONT_NAME))
         {
          pFnt = UI().Font().pFontLetterica25;
         }
         else if(!xr_strcmp(font_name, DI_FONT_NAME))
         {
          pFnt = UI().Font().pFontDI;
         }else
         {
          R_ASSERT3(0,"unknown font",font_name);
          pFnt    = NULL;
         }
        }
        return true;
}

Что можно вынести интересного:
- знакомые переменные
- arial_14 не использует переменную, как другие шрифты
- есть функция R_ASSERT:

R_ASSERT3(0,"unknown font",font_name);
          pFnt    = NULL;

 


"arial_17"

"medium"
"small"

"graffiti19"
"graffiti22"
"graffiti32"
"graffiti50"

"letterica16"
"letterica18"
"letterica25"

 




Надеюсь, информация пригодится! Спасибо за внимание и удачи!

Изменено пользователем FantomICW

  • http://www.amk-team.ru/forum/uploads//ratings/bf.gif × 1
  • http://www.amk-team.ru/forum/uploads//ratings/thumb_up.png × 4
  • http://www.amk-team.ru/forum/uploads//ratings/cross.png × 1
  • http://www.amk-team.ru/forum/uploads//ratings/wrench_orange.png × 3

Поделиться этим сообщением


Ссылка на сообщение
Поделиться на других сайтах

Всем привет, в этой статье я расскажу, как сделать рюкзак - тайник типа АМКшного.

Начнем мы с создания необходимых секций в конфигах. Открываем config\creatures\spawn_sections.ltx и добавляем секцию:

[taynik_sect]:taynik
visual = equipments\item_rukzak
radius = 1
Это тот тайник, который и будет спавниться при юзании предмета.

Далее config\misc\devices.ltx. В него пишем:

[taynik]
GroupControlSection = spawn_group
discovery_dependency =
$spawn = "devices\inventory box"
class = O_INVBOX
cform = skeleton
visual = physics\box\expl_dinamit.ogf
script_binding = bind_physic_object.init
Секцию лучше не трогать, она содержит в себе необходимые для тайника функции. Именно на нее мы ссылались в секции спавна.

В этом-же файле добавляем секцию предмета, который будем юзать:

[rukzak_taynik]:identity_immunities
GroupControlSection = spawn_group
discovery_dependency =
$spawn = "food and drugs\kolbasa"
$prefetch = 8
class = II_FOOD
cform = skeleton
visual = equipments\item_rukzak.ogf
description = taynik_desc

inv_name = taynik_name
inv_name_short = taynik_name
inv_weight = 0.5

inv_grid_width = 2
inv_grid_height = 3
inv_grid_x = 12
inv_grid_y = 32
cost = 1000

attach_angle_offset = 0.440521, 1.378287, -0.644026
; eatable item
eat_health = 0
eat_satiety = 0
eat_power = 0
eat_radiation = 0
wounds_heal_perc = 0
eat_portions_num = -1
attach_position_offset = 0.104196, -0.010821, 0.076969
attach_bone_name = bip01_r_hand
auto_attach = false

// should be deleted after update
bone_name = bip01_r_hand
position_offset = 0.0,0.0,0.0
angle_offset = 1.570790,1.570790,3.92699

; food item
slot = 4
animation_slot = 4

;hud item
hud = wpn_vodka_hud
Тут мы создали предмет. Небольшая оговорочка: иконку к моду я прописала NLCшную, при желании можно сделать самому, это описано в куче статей.

С конфигами закончили, теперь самое важное - скрипты!

Создаем свой скрипт, например kristi.script и в него пишем:

function spawn_item(obj)
local pos = db.actor:position()
local dir = db.actor:direction()
local gver = db.actor:game_vertex_id()
local lver = db.actor:level_vertex_id()
alife():create(obj, pos:add(dir:mul(1)), lver, gver)
end
kristi.spawn_item("taynik_sect") - это функция спавна нашего тайника под ногами актора.
Идем в bind_stalker.script и ищем функцию function actor_binder:reinit().В ее конце, после строки self.object:set_callback(callback.take_item_from_box, self.take_item_from_box, self) ставим свой коллбэк на юзание итема:

self.object:set_callback(callback.use_object, self.taynik_spawn, self)
В этом-же файле например после функции function actor_binder:load(reader) (после task_manager.load(reader)

self.actor_detector:load(reader)

end) пишем:

function actor_binder:taynik_spawn(obj, who)
if obj then
if obj:section() == "rukzak_taynik" then
kristi.spawn_item("taynik_sect")
end
end
end
Готово! Если мы все сделали правильно, то при использовании предмета rukzak_taynik у нас под ногами заспавнится пустой тайничок в который можно сложить хабар.

Да и не забудьте добавить предмету описание!

С уважением ツМаLinK@ツ.

 

Всё отлично работает, но...

Но, к сожалению, если тайник нам больше не нужен, мы не можем забрать рюкзак обратно.

Исправим это.

Открываем файл bind_stalker.scriptи в нём находим функцию actor_binder:take_item_from_box(box, item). В ней в самом конце добавляем такой код:

-- если это наш тайник, и он пустой, т.е. мы забрали из него последни предмет, то...
if box:section() == "taynik_sect" and box:is_inv_box_empty() then
level.start_stop_menu(level.main_input_receiver(), true) -- закрываем окно "обыскивания тайника"
alife():release(alife():object(box:id()), true) -- удаляем тайник
alife():create("rukzak_taynik",db.actor:position(),db.actor:level_vertex_id(),db.actor:game_vertex_id(),db.actor:id()) -- спавним рюкзак в инвентарь
end
Вот и всё. Теперь, когда забираем все вещи из своего тайника, рюкзак возвращается к гг в инвентарь, а тайник исчезает.

 

Сумела восстановить одну схему вертолетов, а именно, при стрельбе в вертолет, он начнет ответную атаку!

Открываем файлbind_heli.script

Ищем там вот такую строку:

-- если обидчик актёр или сталкер, то сделать его своим врагом
if enemy_cls_id == clsid.actor or enemy_cls_id == clsid.script_stalker then
-- if not self.st.combat.enemy_id then
-- self.st.combat.enemy_id = enemy_id
-- end
Удаляем коментарии...

Все,теперь сохраняйте,запускайте игру,возьмите задание волка,бегите к вагончику,стреляйте в вертолет и бегите!!!03_biggrin_ng.gif

 

Добавлено Murarius,

Рекомендуется к изучению: Правила форума, п. 2.9

Спасибо.


  • http://www.amk-team.ru/forum/uploads//ratings/bf.gif × 3
  • http://www.amk-team.ru/forum/uploads//ratings/thumb_up.png × 8
  • http://www.amk-team.ru/forum/uploads//ratings/thumb.png × 1
  • http://www.amk-team.ru/forum/uploads//ratings/cross.png × 1

Поделиться этим сообщением


Ссылка на сообщение
Поделиться на других сайтах

Создайте аккаунт или авторизуйтесь, чтобы оставить комментарий

Комментарии могут оставлять только зарегистрированные пользователи

Создать аккаунт

Зарегистрировать новый аккаунт в нашем сообществе. Это несложно!

Зарегистрировать новый аккаунт

Войти

Есть аккаунт? Войти.

Войти

  • Недавно просматривали   0 пользователей

    Ни один зарегистрированный пользователь не просматривает эту страницу.

×