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

Уроки по модостроению

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

Описание: Менеджер контроля за положением курсора мыши на экране. (экспериментальный, как вариант)
Автор: Singapur22
Принцип: "1 из 4'ёх >> компресс >> 1 из 4'ёх >> компресс >> и т.д."


130923438071.jpg


1. Создаём скриптовый файл, например: _mouse_pos.script


2. Вписываем в тело файла, код класса:
local const_wins  = {"winLT", "winRT", "winLD", "winRD"}
	--/summary/>> Event Rece
function StaticRece(args)
    args[1].rec = args[2]
end
	local win_id = 0
	class "mouse_position" (CUIStatic)
	function mouse_position:__init(x, y, width, height, scriptWnd) super()
    win_id = win_id + 1
    self.id = win_id
    self.X = x
    self.Y = y
    self.widthEl = width / 2   --ширина элемента зоны контроля, в режиме ожидания
    self.heightEl = height / 2 --высота элемента зоны контроля, в режиме ожидания
    self.rec = nil             --постоянная элемента, на котором произашло событие захвата курсора
    self.get = false           --ключ запуска, определения позиции курсора
    self.method = nil          --метод (функция), в которую требуется передать полученные координаты
    self.owner = nil           --объект, которому требуется передать полученные координаты
    
    self:SetWndRect(x, y, width, height) --устанавливаем общий размер зоны контроля (относительно её и будут выдаваться координаты)
    scriptWnd:Register(self, "event_winZC"..self.id)
    scriptWnd:AddCallback("event_winZC"..self.id, ui_events.STATIC_FOCUS_LOST, self.ZoneControllLost, self)
    
    --//делим зону контроля на 4 части
    self.winLT = CUIStatic() --элемент левого,  верхнего угла
    self.winRT = CUIStatic() --элемент правого, верхнего угла
    self.winLD = CUIStatic() --элемент левого,  нижнего угла
    self.winRD = CUIStatic() --элемент правого, нижнего угла
    
    self.winLT.X, self.winLT.Y = x, y
    self.winRT.X, self.winRT.Y = x + self.widthEl, y
    self.winLD.X, self.winLD.Y = x, y + self.heightEl
    self.winRD.X, self.winRD.Y = x + self.widthEl, y + self.heightEl
    
    for _, v in ipairs(const_wins) do
        self[v]:Init(self[v].X, self[v].Y, self.widthEl, self.heightEl)
        self[v]:SetAutoDelete(true)
        local reg_name = "event_"..v..self.id
        scriptWnd:Register(self[v], reg_name)
        scriptWnd:AddCallback(reg_name, ui_events.STATIC_FOCUS_RECEIVED, StaticRece, {self, v})
        self:AttachChild(self[v])
    end
end
	--/summary/>> Event Lost Zone_Controll
function mouse_position:ZoneControllLost()
    self.rec = nil
    if self.get then
        self.get = false
        self:recompress_zone()
    end
end
	--/summary/>> Method Compress
function mouse_position:compress_zone(win)
    if not win then return end
    local x, y = win.X, win.Y
    local width = win:GetWidth() / 2
    local height = win:GetHeight() / 2
    
    if win:GetWidth() < 5 then
        if self.method then
            self.method(self.owner, x + width, y + height)
            self.get, self.method, self.owner = false
            self:recompress_zone()
        end
        return
    end
    
    self:SetWndRectElements(x, y, width, height)
end
	--/summary/>> Method Recompress
function mouse_position:recompress_zone()
    self:SetWndRectElements(self.X, self.Y, self.widthEl, self.heightEl)
end
	--/summary/>> Method SetWndRect
function mouse_position:SetWndRectElements(x, y, width, height)
    self.winLT.X = x
    self.winLT.Y = y
    self.winLT:SetWndRect(self.winLT.X, self.winLT.Y, width, height)
    
    self.winRT.X = x + width
    self.winRT.Y = y
    self.winRT:SetWndRect(self.winRT.X, self.winRT.Y, width, height)
    
    self.winLD.X = x
    self.winLD.Y = y + height
    self.winLD:SetWndRect(self.winLD.X, self.winLD.Y, width, height)
    
    self.winRD.X = x + width
    self.winRD.Y = y + height
    self.winRD:SetWndRect(self.winRD.X, self.winRD.Y, width, height)
end
	--/summary/>> Update
function mouse_position:Update()
    if self.get then
        if not self.rec then
            self.get = false
            return
        end
        get_console():execute("mouse_pos="..tostring(self.rec))
        self:compress_zone(self[self.rec])
    end
end
	--/summary/>> Method Start Get Position Cursor
function mouse_position:GetPos(method, owner)
    self.get, self.method, self.owner = true, method, owner
end


Конструктор, инициализатор менеджера позиции курсора:

self.mp = _mouse_pos.mouse_position(x, y, width, height, scriptWnd)

Где:
x = позиция начала координат, зоны контроля, по X
y = позиция начала координат, зоны контроля, по Y
width = ширина зоны контроля
height = высота зоны контроля
scriptWnd = объект класса CUIScriptWnd,
относительно которого была произведена инициализация менеджера позиции курсора.

Апдейт схемы контроля:

self.mp:Update()

Апдейт необходимо производить из виртуальной функции Update(), объекта класса CUIScriptWnd,
относительно которого была произведена инициализация менеджера позиции курсора.

Метод определения координат, относительно зоны контроля:

self.mp:GetPos(method, owner)

Где:
method = метод (функция), в которую требуется передать полученные координаты, после завершения просчёта
owner = объект, в котором нужно обратиться к указанному методу.
если method является простой функцией (не методом), то owner передаётся в неё как первый аргумент.

Приаттачиваем менеджер к объекту контроля:

self:AttachChild(self.mp)


Изменено пользователем Murarius
  • Нравится 1

Опаа-а!!! Ливер вылез!

Ссылка на комментарий

Всем привет… Я долго искал статью по созданию работающего радио в ЗП, это было бессмысленно, пришлось учиться самому…


Итак приступим…

Для того что бы сделать новое РАБОТАЮЩЕЕ радио нам понадобятся файлы:
all.spawn (распакованный)
sound_theme.script
Итак сначала заходим в файл alife_zaton.ltx (он находится в распакованном all.spawn)
И добавляем в конец вот такие строки:
[1866]
; cse_abstract properties
section_name = physic_object
name = zaton_radio
position = 131.13690185547,-6.1206126213074,177.25036621094
direction = 0,2.40000009536743,0
; cse_alife_object properties
game_vertex_id = 296
distance = 0.400000005960464
level_vertex_id = 1189961
object_flags = 0xffffff3a
custom_data = <<END
[logic]
cfg = scripts\zaton_radio.ltx
END
; cse_visual properties
visual_name = dynamics\el_tehnika\priemnik_gorizont
; cse_ph_skeleton properties
skeleton_flags = 1
; cse_alife_object_physic properties
physic_type = 0x3
mass = 10
fixed_bones = link

Теперь сохраняем и можно собирать all.spawn он нам больше не нужен(не забывайте ставить его на место переименовывая из файла new в all.
Так теперь по порядку все объясню:

[1866] – номер секции, он не должен повторяться.Если у вас чистый all то номер будет 1866
; cse_abstract properties
section_name = physic_object
name = zaton_radio – уникальное имя
position = 131.13690185547,-6.1206126213074,177.25036621094 - координаты
direction = 0,2.40000009536743,0
; cse_alife_object properties
game_vertex_id = 296 – координаты вертикс
distance = 0.400000005960464
level_vertex_id = 1189961 - координаты уровня
object_flags = 0xffffff3a
custom_data = <<END
[logic]
cfg = scripts\zaton_radio.ltx – путь к логике
END
; cse_visual properties
visual_name = dynamics\el_tehnika\priemnik_gorizont – путь визуалу модели ogf причем заметьте что ogf т.е. формат писать не надо
; cse_ph_skeleton properties
skeleton_flags = 1
; cse_alife_object_physic properties
physic_type = 0x3
mass = 10
fixed_bones = link

Редактируем только те места которые я откомментировал!!!

Так теперь самое главное… Логика
Заходим в папку gamedata//configs//scripts создаём там файл zaton_radio.ltx и в нём пишем:

[logic]
active = ph_sound
[ph_sound]
snd = music_radio
looped = false
min_idle = 300
max_idle = 500
random = true

Сохраняем…
Теперь заходим в папку gamedata\\ sound\\ characters_voice\\scenario\\ и создаем там папку zaton_radio после чего кидаем в эту папку музыкальные файлы в формате ogg и назовем их примерно так:

zaton_1, zaton_2, zaton_3, zaton_4, zaton_5

(я написал только 5 названий песен, потому что вам для начало и 5 треков хватит)
Все с музыкальными файлами закончили…

Теперь открываем файл gamedata\\script\\sound_theme.script и в самом начале после строчки theme = {} пишем вот это:

ph_snd_themes = {}
ph_snd_themes["music_radio"] = {
"characters_voice\\scenario\\zaton_radio\\zaton_5",
"characters_voice\\scenario\\zaton_radio\\zaton_4",
"characters_voice\\scenario\\zaton_radio\\zaton_3",
"characters_voice\\scenario\\zaton_radio\\zaton_2",
"characters_voice\\scenario\\zaton_radio\\zaton_1"
}

Сохраняем…После последней строчки запятую ставить не надо!!!

Всё можно идти на и слушать радио (оно появится в скадовске на столе)
(Теперь для тех, кто ещё не понял, строки в виде: "characters_voice\\scenario\\zaton_radio\\zaton_1" - это списки песен, которые будет проигрывать наше радио)
Внимание: этот метод проверялся на чистом сталкере зов припяти версии 1.6.00
На некоторых модах может не работать из-за не совместимости
Статья от Akella-96

 

Изменено пользователем World_Stalker
  • Согласен 1

AWRP : Re - Load 0.2 ©

Ссылка на комментарий

Сложность:

средне.
Что потребуется: программа для снятия координат (Position Informer или любая другая), распаковщик-запаковщик all.spawn – ACDC конвертер от bardak’а, несколько файлов из ЗП.
Для начала снимаем координаты того места, где нужно поставить метку. Желательно снимать метку, находясь в центре нужного объекта. Записываем координаты x,y,z, level- и game-vertex'ы.
Распаковываем all.spawn необходимой версией распаковщика. Открываем блокнотом алайф.лтх нужной нам локации и в конце файла создаём секцию вида:
[номер, следующий за номером предыдущей секции]
; cse_abstract properties
section_name = space_restrictor
name = st_pri_b302
position = 135.845,16.680,219.551 ;подставляем нужные координаты
direction = 0,0,0

; cse_alife_object properties
game_vertex_id = 3764 ;пишем нужный гейм-вертекс
distance = 0
level_vertex_id = 340694 ;пишем нужный левел-вертекс
object_flags = 0xffffff3e
story_id = 16000 ;присваиваем стори_айди

; cse_shape properties
shapes = shape0
shape0:type = sphere
shape0:offset = 0,0,0
shape0:radius = 1

; cse_alife_space_restrictor properties
restrictor_type = 3

Стори_айди не должны повторяться, для этого открываем блокнотом файл game_story_ids.ltx – смотрим, каких цифр нет, и дописываем в конец файла все вновь присвоенные стори_айди по типу уже существующих. Очень большие числа не брать, достаточно предела 10000-15000, допустим, хватит для чего угодно.
В итоге в конце файла дописываем строки вида:

16000           = "st_pri_b306_name"

где число – это айди, в кавычках имя, в принципе можно ставить любое, названия меток у нас будут прямо в скрипте.
Далее открываем блокнотом файл level.tasks.script (gamedata/scripts…)
Видим там функцию:

function add_lchanger_location()
    local sim = alife()
    if sim then
        -- escape
        local obj = sim:story_object(91)
        if obj then
            level.map_add_object_spot(obj.id, "level_changer", "to_garbage")
        end…
-- и.т.д…
--    Для каждой нужной нам метки создаём секцию вида:
        local obj = sim:story_object(91) –- номер стори_айди метки
        if obj then
            level.map_add_object_spot(obj.id, "тип метки", "название метки, например Мост им. Преображенского")
        end…

Далее, по типам меток. В принципе, можно использовать стандартные ТЧ-метки.
Например:
crlc_big – большой белый круг;
crlc_mdl – средних размеров круг;
crlc_small – маленький кружок.
Но можно сделать метки объектов из ЗП. Для этого открываем блокнотом файлик map_spots.xml (config/ui) и дописываем перед финальным </map_spots> секцию вида:

<primary_object>
    <level_map spot="primary_object_spot"    pointer="quest_pointer"/>
</primary_object>
<primary_object_spot  x="0" y="0" width="15" height="15" alignment="c" scale="1" scale_min="1" scale_max="6" stretch="1">
    <texture x="0" y="585" width="205" height="205">ui\ui_actor_sleep_screen</texture>
</primary_object_spot>

Теперь можно тип метки указывать ”primary_object”.
Закидываем по адресу textures/ui файлик ui_actor_sleep_screen.dds из ЗП, заходим в игру, начинаем НИ и любуемся метками… Метки через данный способ будут отображаться постоянно.
Описал вроде всё, текстурку ui_actor_sleep_screen.dds берём из файлов ЗП.

 

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

Подарки

  • Ссылка на комментарий

    Нам понадобится файл

    treasure_manager.script.
    В этом файле находим такие строки:
    --' Юзание инициатора (возможность выдать тайник)
    function CTreasure:use(npc)
        printf("TREASURE USE")
    После строки printf("TREASURE USE") пишем:
    if (npc and db.actor) then
        lootmoney.lootmoney(npc)
    end

    У нас должно выйти:
    --' Юзание инициатора (возможность выдать тайник)
    function CTreasure:use(npc)
        printf("TREASURE USE")
    
        if (npc and db.actor) then
            lootmoney.lootmoney(npc)
        end

    Теперь создаём файл lootmoney.script и в нём пишем:
    function lootmoney(npc)
        if npc ~= nil and not string.find(npc:section(),"arena") and npc:character_community()~="arena_enemy" then
            local money = npc:money()
            if money ~= nil and money ~=0 then
                local deadmoney = money
                local npc_rank
                npc_rank = ranks.get_obj_rank_name(npc)
                if npc_rank ~= nil then
                    if npc_rank == "novice" and deadmoney >=400 then deadmoney=math.random(25,400)  
                    elseif npc_rank == "experienced" and deadmoney >=500 then deadmoney=math.random(50,500)  
                    elseif npc_rank == "veteran" and deadmoney >=600 then deadmoney=math.random(100,600)
                    elseif npc_rank == "master" and deadmoney >=700 then deadmoney=math.random(200,700)  
                    end
                end
                local news_texti = "\\n%c[255,255,0,0]Мёртвый сталкер: %c[default]"..npc:character_name().."\\n%c[255,255,0,0]Обнаружено денег: %c[default]"..game.translate_string(tostring(deadmoney).."руб.")
                db.actor:give_game_news(news_texti, "ui\\ui_iconsTotal", Frect():set(0,0,83,47), 1, 4000)
                db.actor:give_money(deadmoney)
                game_stats.money_quest_update(deadmoney)
                npc:give_money(-money)
                game_stats.money_quest_update(-money)
            end
        end
    end

    Итак, первым делом в директории gamedata\scripts создайте файл с названием имя_вашего_файла.script
    1.Открываем его и пишем:

    -- названия локаций
    local level_name = {
        ["l01_escape"] = "Кордон",
        ["l02_garbage"] = "Свалка",
        ["l03_agroprom"] = "НИИ Агропром",
        ["l03u_agr_undergroun"] = "Подземелье НИИ Агропром",
        ["l04_darkvalley"] = "Тёмная долина",
        ["l04u_labx18"] = "Лаборатория X-18",
        ["l05_bar"] = "Бар",
        ["l06_rostok"] = "Дикая территория",
        ["l07_military"] = "Арм.склады",
        ["l08_yantar"] = "Янтарь",
        ["l08u_brainlab"] = "Лаборатория X-16",
        ["l10u_bunker"] = "Лаборатория X-10",
        ["l10_radar"] = "Радар",
        ["l11_pripyat"] = "Припять",
        ["l12_stancia"] = "ЧАЭС",
        ["l12_stancia_2"] = "ЧАЭС",
        ["l12u_sarcofag"] = "Саркофаг",
        ["l12u_control_monolith"] = "Управление Монолитом"
        }
    
    -- названия группировок
    local community = {
        ["stalker"] = "Сталкер",
        ["monolith"] = "Монолит",
        ["military"] = "Военные",
        ["bandit"] = "Бандит",
        ["killer"] = "Наемник",
        ["ecolog"] = "Эколог",
        ["dolg"] = "Долг",
        ["freedom"] = "Свобода",
        ["zombied"] = "Зомбированный",
        ["trader"] = "Торговец"
        }
    
    function kill_npc(victim, who)
        if victim and IsStalker(victim) then
            -- определяется какая группировка у убитого, его имя, локация
            local dead_news = "\\n%c[255,160,160,160]Группировка: %c[default]"..community[victim:character_community()].."\\n%c[255,160,160,160]Имя: %c[default]"..victim:character_name().."\\n%c[255,160,160,160]Локация: %c[default]"..level_name[level.name()]..""
            db.actor:give_game_news(dead_news, "ui\\ui_icons_npc", Frect():set(2,130,124,124), 1, 4000)
        end
    end

    2. Далее открываем xr_motivator.script, который находится в gamedata\scripts, ищем функцию:
    function motivator_binder:death_callback(victim, who)
    и после пишем: имя_вашего_файла.kill_npc(victim, who) в итоге:
    function motivator_binder:death_callback(victim, who)
        имя_вашего_файла.kill_npc(victim, who)
        if who:id() == db.actor:id() then
            xr_statistic.addKillCount(self.object)
        end
    Вот собственно и все!

    Прим. от AntdiabloN. Можно сделать так чтобы при выводе инфы возможно было услышать звук принятого сообщения. В конце файла с сообщениями о смерти пишем -
    -- Звук сообщения
    function news_sound()
        local snd_obj
        snd_obj = xr_sound.get_safe_sound_object([[device\pda\pda_tip]]) -- путь до звукового файла
        snd_obj:play_no_feedback(db.actor, sound_object.s2d, 1, vector(), 1.0)
    end
    и в функции news_of_npc_kill перед первым end пишем - имя_вашего_файла.news_sound()
    Пример как может быть выглядеть функция:
    function kill_npc(victim, who)
        if victim and IsStalker(victim) then
            local dead_news = "\\n%c[255,160,160,160]Группировка: %c[default]"..community[victim:character_community()].."\\n%c[255,160,160,160]Имя: %c[default]"..victim:character_name().."\\n%c[255,160,160,160]Локация: %c[default]"..level_name[level.name()]..""
            db.actor:give_game_news(dead_news, "ui\\ui_icons_npc", Frect():set(2,130,124,124), 1, 4000)
            имя_вашего_файла.news_sound()
        end
    end

    Изменено пользователем World_Stalker
    Поправил
    • Спасибо 2
    Ссылка на комментарий

    Последняя версия скрипта для отлова выстрела из оружия

    http://dl.dropbox.com/u/23885395/sm_wpns.rar

     

    Огромное спасибо Artos-у и KD87 за помощь.

     

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

    Работает с любой частью Сталкера. Тестировался на ЧН. Для ЗП скрипт немного изменён.

     

    Особенности этой версии:

    * Скрипт теперь работает без сторонних программ по отлову нажатия клавиш. (не требует кейлогеров)

    * Существенно поднята точность отлова.

    * Расширена передаваемая в колбек на выстрел информация.

     

    Информация о известных багах внутри скрипта.

    Все предыдущие обсуждения скрипта в этой теме лучше стереть.

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

     

     

    • Нравится 1

    Можно просто Shoker, форум АМК съел моё старое имя и не хочет отдавать о_О

    Мастер аномалий на свою заднюю точку.

    Ссылка на комментарий

    Еще функции (Для ТЧ).



    function kill_stalker(actor, npc)
        npc:kill(npc)
    end


    function enemy(actor, npc)
    npc:set_relation (game_object.enemy, db.actor)
    end


    function any_sound()
    local snd = sound_object([[characters_voice\human_03\stalker\talk\leaves\leaves_42]])
    snd:play_no_feedback(db.actor,sound_object.s2d, 0, vector():set(0, 0, 0), 2.0)
    end


    function НАЗВАНИЕ_create()
    local x=
    local y=
    local z=
    local level_vertex=
    local game_vertex_id=
    alife():create("НАЗВАНИЕ",vector():set(x,y,z),level_vertex,game_vertex_id)
    end


    Например:

    function all_spawn()
    НАЗВАНИЕ_create()
    any_sound()
    end
    	function НАЗВАНИЕ_create()
    local x=
    local y=
    local z=
    local level_vertex=
    local game_vertex_id=
    alife():create("НАЗВАНИЕ",vector():set(x,y,z),level_vertex,game_vertex_id)
    end
    	function any_sound()
    local snd = sound_object([[characters_voice\human_03\stalker\talk\leaves\leaves_42]])
    snd:play_no_feedback(db.actor,sound_object.s2d, 0, vector():set(0, 0, 0), 2.0)
    end



    Изменено пользователем Murarius
    Ссылка на комментарий

    На досуге решил поковыряться в файлах "ui" решил покапать файлы: actor_menu\actor_menu_16 (обычные\широкоформатные мониторы)
    Автор: Tris

    вот что накопал:

    <actor_money_static x="501" y="75" width="104" height="22">
            <text align="r" font="graffiti22"/>
        </actor_money_static>
    
        <partner_money_static x="55" y="75" width="104" height="22">
            <text align="r" font="graffiti22"/>
        </partner_money_static>
    
    
    ;;;;;;;;;;;;;;;;;;; Место нахождение денег(actor\partner);;;;;;;;;;;;;;;;;;;;;;
                               (Актёр\тот с кем ведёте разговор)
    
    
    <inv_slot2_highlight x="189" y="17" width="65" height="353" stretch="1">;;;;1 оружие
            <texture>ui_inGame2_weapon_highlighter</texture>
        </inv_slot2_highlight>
        <inv_slot3_highlight x="368" y="17" width="65" height="353" stretch="1">;;;;2 оружие
            <texture>ui_inGame2_weapon_highlighter</texture>
        </inv_slot3_highlight>
        <helmet_slot_highlight x="172" y="17" width="76" height="98" stretch="1">;;;; шлем
            <texture>ui_inGame2_helmet_highlighter</texture>
        </helmet_slot_highlight>
        <outfit_slot_highlight x="172" y="142" width="76" height="161" stretch="1">;;;; костюм
            <texture>ui_inGame2_armor_highlighter</texture>
        </outfit_slot_highlight>
        <detector_slot_highlight x="172" y="330" width="76" height="48" stretch="1">;;;; детектор
            <texture>ui_inGame2_detector_highlighter</texture>
        </detector_slot_highlight>
        <quick_slot_highlight x="187" y="398" width="52" height="59" dx="64" stretch="1">;;;; быстрое использование
            <texture>ui_inGame2_quick_item_highlighter</texture>
        </quick_slot_highlight>
        <artefact_slot_highlight x="187" y="476" width="41" height="52" dx="52" stretch="1">;;;; артифакты
            <texture>ui_inGame2_artefakt_highlighter</texture>
        </artefact_slot_highlight>
    
    
    ;;;;;;;;;;;;;;;;;Подсветка слотов;;;;;;;;;;;;;;;;;;;;;;;
    
    
    
    <quick_slot1_text x="386" y="550" width="14" height="13">
            <text align="c" font="letterica16">quick_use_str_1</text>;;;;;;;; F1
        </quick_slot1_text>
        <quick_slot2_text x="451" y="550" width="14" height="13">
            <text align="c" font="letterica16">quick_use_str_2</text>;;;;;;;; F2
        </quick_slot2_text>
        <quick_slot3_text x="516" y="550" width="14" height="13">
            <text align="c" font="letterica16">quick_use_str_3</text>;;;;;;;; F3
        </quick_slot3_text>
        <quick_slot4_text x="580" y="550" width="14" height="13">
            <text align="c" font="letterica16">quick_use_str_4</text>;;;;;;;; F4
        </quick_slot4_text>
    
    ;;;;;;;;;;; Надписи f1 - f2 - f3 - f4;;;;;;;;;;;;;;;;;;;;;;;;;;;
    
    
    
    
    <progess_bar_weapon1 x="198" y="378" width="47" height="5" horz="1" min="0" max="1" pos="0">;;;;; 1 оружие
            <progress stretch="1">
                <texture r="142" g="149" b="149">ui_inGame2_inventory_status_bar</texture>
            </progress>
            <min_color r="196" g="18" b="18"/>
            <middle_color r="255" g="255" b="118"/>
            <max_color r="107" g="207" b="119"/>
        </progess_bar_weapon1>
        <progess_bar_weapon2 x="178" y="378" width="47" height="5" horz="1" min="0" max="1" pos="0">;;;;; 2 оружие
            <progress stretch="1">
                <texture r="142" g="149" b="149">ui_inGame2_inventory_status_bar</texture>
            </progress>
            <min_color r="196" g="18" b="18"/>
            <middle_color r="255" g="255" b="118"/>
            <max_color r="107" g="207" b="119"/>
        </progess_bar_weapon2>
        <progess_bar_outfit x="188" y="309" width="47" height="5" horz="1" min="0" max="1" pos="0">;;;;; костюм
            <progress stretch="1">
                <texture r="142" g="149" b="149">ui_inGame2_inventory_status_bar</texture>
            </progress>
            <min_color r="196" g="18" b="18"/>
            <middle_color r="255" g="255" b="118"/>
            <max_color r="107" g="207" b="119"/>
        </progess_bar_outfit>
        <progess_bar_helmet x="188" y="118" width="47" height="5" horz="1" min="0" max="1" pos="0">;;;;; шлем
            <progress stretch="1">
                <texture r="142" g="149" b="149">ui_inGame2_inventory_status_bar</texture>
            </progress>
            <min_color r="196" g="18" b="18"/>
            <middle_color r="255" g="255" b="118"/>
            <max_color r="107" g="207" b="119"/>
        </progess_bar_helmet>
    
    
    ;;;;;;;;;;;;;;;;;;;Прогресс бар(состояние:оружие 1\2; костюм; шлем;;;;;;;;;;;;;;
    
    
    
    <actor_weight_caption x="450" y="736" width="57" height="16">
            <text align="r" font="letterica16" color="ui_3">ui_total_weight</text>
        </actor_weight_caption>
        <actor_weight x="307" y="736" width="35" height="16">
            <text align="c" font="letterica16"/>
        </actor_weight>
        <actor_weight_max x="242" y="736" width="68" height="16">
            <text align="l" font="letterica16" color="ui_3"/>
        </actor_weight_max>
    
    
    
        <partner_weight_caption x="74" y="738" width="68" height="14">
            <text align="r" font="letterica16" color="ui_3">ui_total_weight</text>
        </partner_weight_caption>
        <partner_weight x="242" y="738" width="36" height="14">
            <text align="l" font="letterica16" color="ui_7"/>
        </partner_weight>
    
    
    ;;;;;;;;;;;актёр: текущий вес рюкзака\максиальный;;;;;; с кем разгованиваеш:общий вес;;;;;;;;;;;;;;;;
                                (actor)                                        (partner)
    
    
    
    
    
    <!-- partner  ---------------------------------------------------------------- -->
        <left_delimiter x="102" y="226" width="273" height="163" stretch="1">
            <texture>ui_inGame2_center_trade_devider</texture>
            <trade_caption x="118" y="74" width="48" height="16">
                <text align="l" font="letterica16" color="ui_3">ui_total_price</text>
            </trade_caption>
            <trade_price x="166" y="74" width="13" height="16">
                <text align="l" font="letterica16"/>
            </trade_price>
            <trade_weight_max x="206" y="74" width="40" height="16">
                <text align="l" font="letterica16" color="ui_3"/>
            </trade_weight_max>
        </left_delimiter>
        <!-- actor  ---------------------------------------------------------------- -->
        <right_delimiter x="648" y="226" width="273" height="163" stretch="1">
            <texture>ui_inGame2_center_trade_devider</texture>
            <trade_caption x="118" y="74" width="48" height="16">
                <text align="r" font="letterica16" color="ui_3">ui_total_price</text>
            </trade_caption>
            <trade_price x="166" y="74" width="40" height="16">
                <text align="c" font="letterica16"/>
            </trade_price>
            <trade_weight_max x="206" y="74" width="40" height="16">
                <text align="l" font="letterica16" color="ui_3"/>
            </trade_weight_max>
        </right_delimiter>
    
    
    
    
    ;;;;;;;;;;;;;;;;Левый разделитель\ правый разделитель;;;;;;;;;;;;;;;;;;;;;;
                     (с кем разговариваеш)      (актёр)
    
    
    
    
    <belt_list_over x="384" y="472" width="47" height="59" dx="52" stretch="1">
            <texture >ui_inGame2_artefact_blocker</texture>
        </belt_list_over>
    
        <helmet_over x="467" y="11" width="89" height="115" stretch="1">
            <texture >ui_inGame2_helmet_blocker</texture>
        </helmet_over>
    
    
    ;;;;;;;;;;;;;;;текстуры закрытия слотов под арты/шлем;;;;;;;;;;;;;;;
    
    
    
    <dragdrop_bag x="162" y="119" width="250" height="574"
            cell_width="33" cell_height="41" rows_num="14" cols_num="7"
            unlimited="1" group_similar="1" always_show_scroll="1" condition_progress_bar="1"/>
    
    
    ;;;;;;;;;;;;;сетка инвентаря(там где распологаются все вещи);;;;;;;;;;;;;;
    
    
    
    <dragdrop_outfit x="269" y="137" width="85" height="178"
            cell_width="33" cell_height="41" rows_num="3" cols_num="2"
            custom_placement="0" a="0" virtual_cells="1" vc_vert_align="c"
            vc_horiz_align="c"/>
    
        <dragdrop_helmet x="269" y="14" width="85" height="110"
            cell_width="33" cell_height="41" rows_num="2" cols_num="2"
            custom_placement="0" a="0" virtual_cells="1" vc_vert_align="c"
            vc_horiz_align="c" />
    
    ;;;;;;;;;;;;;;;;;;;слоты: костюм\шлем;;;;;;;;;;;;;;;;;;;;;;;;;
    
    
    <dragdrop_detector x="469" y="328" width="85" height="55"
            cell_width="33" cell_height="41" rows_num="1" cols_num="2"
            custom_placement="0" a="0" virtual_cells="1" vc_vert_align="c"
            vc_horiz_align="c"/>
    
    ;;;;;;;;;;;;;;;;;;;;;;;;слот детектора;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    
    
    
    <dragdrop_pistol x="384" y="14" width="74" height="368"
            cell_width="33" cell_height="41" rows_num="6" cols_num="2"
            custom_placement="0" vertical_placement="1" a="0"
            virtual_cells="1" vc_vert_align="c" vc_horiz_align="c"/>
    
    
    ;;;;;;;;;;;;;;;;;;1 слот для оружия;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    
    
    <dragdrop_automatic x="563" y="14" width="74" height="370"
            cell_width="33" cell_height="41" rows_num="6" cols_num="2"
            custom_placement="0" vertical_placement="1" a="0"
            virtual_cells="1" vc_vert_align="c" vc_horiz_align="c" />
    
    
    ;;;;;;;;;;;;;;;;2 слот для оружия;;;;;;;;;;;;;;;;;;;;;
    
    
    
    
    <dragdrop_quick_slots x="398" y="407" width="227" height="41"
            cell_width="33" cell_height="41" a="0" rows_num="1"    cols_num="4"
            cell_sp_x="32" cell_sp_y="0" custom_placement="1"/>
    
    
    ;;;;;;;;;; слоты быстрого использования вещей;;;;;;;;;;;;;;;

    Изменено пользователем World_Stalker
    Ссылка на комментарий

    Для создания спального мешка, нам понадобятся эти файлы:


    В папке scripts
    bind_stalker.script
    пустой файл main_sleep.script

    В папке config/ui
    ui_movies.xml
    пустой ui_sleep.xml

    В папке config/misc
    dream.ltx
    items.ltx


    В папке config/texs/rus
    string_table_enc_equipment.xml


    Заходим в gamedata\config\misc, ищем файл items.ltx и в конце пишем:
    [sleep_bag]:identity_immunities
    GroupControlSection    = spawn_group
    discovery_dependency =
    $spawn             = "food and drugs\sleep_bag"
    $prefetch         = 32
    class            = II_ANTIR;класс
    cform           = skeleton
    visual          = physics\decor\bag_01.ogf;модель мешка с песком
    description        = enc_equipment_sleep_bag;описание
    
    inv_name            = sleep_bag;наименование
    inv_name_short        = sleep_bag;наименование
    inv_weight            = 0.2;вес
    
    inv_grid_width        = 2;ширина иконки
    inv_grid_height        = 2;высота иконки
    inv_grid_x            = 12;ширина по x
    inv_grid_y            = 0; высота по y
    cost                = 3000;стоимость
    
    ; eatable item
    eat_health = 0
    eat_satiety = 0
    eat_power = 0
    eat_radiation = 0.0
    wounds_heal_perc = 0
    eat_portions_num = 1
    
    ; food item
    animation_slot        = 4
    
    ;hud item
    hud = wpn_vodka_hud

    Работа с созданием спального мешка завершена.

     

    Название и описание.
    Заходим в gamedata\config\text\rus, находим файл string_table_enc_equipment.xml, открываем его и в самом низу, перед </string_table> пишем:

    <string id="sleep_bag">
        <text>Спальный мешок</text>
    </string>
    <string id="enc_equipment_sleep_bag">
        <text>Отличный спальный мешок. Ткань не рвется, устойчивая к воде. Отличная вещь переночевать в Зоне.</text>
    </string>

    Итак с предметом закончили Приступим к главному.

    Работа со скриптами
    Заходим в gamedata\scripts, находим файл bind_stalker.script, открываем его, находим функцию function actor_binder:net_destroy() и в колбеках пишем:

    self.object:set_callback(callback.use_object, nil)

    Должно получиться так:

    function actor_binder:net_destroy()
        if(actor_stats.remove_from_ranking~=nil)then
            actor_stats.remove_from_ranking(self.object:id())
        end
    --    game_stats.shutdown ()
        db.del_actor(self.object)
    
        sr_light.clean_up ()
    
        self.object:set_callback(callback.inventory_info, nil)
        self.object:set_callback(callback.article_info, nil)
        self.object:set_callback(callback.on_item_take, nil)
        self.object:set_callback(callback.on_item_drop, nil)
        --self.object:set_callback(callback.actor_sleep, nil)
        self.object:set_callback(callback.task_state, nil)
        self.object:set_callback(callback.level_border_enter, nil)
        self.object:set_callback(callback.level_border_exit, nil)
        self.object:set_callback(callback.take_item_from_box, nil)
        self.object:set_callback(callback.use_object, nil) -- вот наш коллбэк
    
        if sr_psy_antenna.psy_antenna then
            sr_psy_antenna.psy_antenna:destroy()
            sr_psy_antenna.psy_antenna = false
        end
    
        xr_sound.stop_all_sound_object()
    
        object_binder.net_destroy(self)
    end

    В этом же файле находим функцию function actor_binder:reinit() и так же в коллбэках пишем

    self.object:set_callback(callback.use_object, self.use_obj, self)

    Должно получиться так:

    function actor_binder:reinit()
        object_binder.reinit(self)
    
        local npc_id = self.object:id()
    
        db.storage[npc_id] = { }
    
        self.st = db.storage[npc_id]
        self.st.pstor = nil
    
        self.next_restrictors_update_time = -10000
    
        self.object:set_callback(callback.inventory_info, self.info_callback, self)
        self.object:set_callback(callback.article_info, self.article_callback, self)
        self.object:set_callback(callback.on_item_take, self.on_item_take, self)
        self.object:set_callback(callback.on_item_drop, self.on_item_drop, self)
        self.object:set_callback(callback.trade_sell_buy_item, self.on_trade, self) -- for game stats
        --self.object:set_callback(callback.actor_sleep, self.sleep_callback, self)
        self.object:set_callback(callback.task_state, self.task_callback, self)
        --self.object:set_callback(callback.map_location_added, self.map_location_added_callback, self)
        self.object:set_callback(callback.level_border_enter, self.level_border_enter, self)
        self.object:set_callback(callback.level_border_exit, self.level_border_exit, self)
        self.object:set_callback(callback.take_item_from_box, self.take_item_from_box, self)
        self.object:set_callback(callback.use_object, self.use_obj, self) -- вот наш колбек
    end

    Так же в этом файле находим функцию function actor_binder:on_item_drop (obj) и после неё пишем:

    function actor_binder:use_obj(obj)
        main_sleep.sleep(obj)
    end

    Должно получиться так:

    ----------------------------------------------------------------------------------------------------------------------
    function actor_binder:on_item_drop (obj)
        level_tasks.proceed(self.object)
        --game_stats.update_drop_item (obj, self.object)
    end
    ----------------------------------------------------------------------------------------------------------------------
    function actor_binder:use_obj(obj) -- функция на использование предмета
        main_sleep.sleep(obj) -- наш будущий скрипт и функция в нем.
    end
    ----------------------------------------------------------------------------------------------------------------------

    Теперь в gamedata\scripts создаем файл c названием main_sleep.script, открываем его и пишем:

    function sleep(obj)
       if obj ~= nil then
          if obj:section() == "sleep_bag" then -- при использовании спального мешка будет открываться выборочное меню
           local hud = sleep_ui(get_hud()) -- указываем на class "sleep_ui" (CUIScriptWnd)
             level.start_stop_menu(hud, true) -- открываем меню
        end
        end
    end
    
    
    class "sleep_ui" (CUIScriptWnd)
    
    function sleep_ui:__init(owner) super()
        self.owner = owner
        self:InitControls()
        self:InitCallBacks()
    end
    
    function sleep_ui:__finalize() end
    
    function sleep_ui:InitControls()
        self:Init(50,50,550,450)
    
        local xml = CScriptXmlInit()
        xml:ParseFile("ui_sleep.xml") -- настройки будут воспроизводиться в этом xml файле
    
        xml:InitStatic("back_video", self) -- видео сзади
    
        xml:InitStatic("background", self) -- рамка сзади
    
        self:Register(xml:Init3tButton("caption", self),"caption") -- заголовок
        self:Register(xml:Init3tButton("btn_1", self),"btn_1") -- кнопка на сон одного часа
        self:Register(xml:Init3tButton("btn_2", self),"btn_2") -- кнопка на сон трех часов
        self:Register(xml:Init3tButton("btn_3", self),"btn_3") -- кнопка на сон девяти часов
        if db.actor.health < 0.9 then -- если здоровье упало, то
        self:Register(xml:Init3tButton("btn_4", self),"btn_4") -- кнопка на выздоровления
        end
        self:Register(xml:Init3tButton("btn_quit", self),"btn_quit") -- кнопка выхода
    end
    
    function sleep_ui:InitCallBacks()
        self:AddCallback("btn_1", ui_events.BUTTON_CLICKED, self.sleep_ui1, self) -- кнопка один идет на функцию sleep_ui1
        self:AddCallback("btn_2", ui_events.BUTTON_CLICKED, self.sleep_ui2, self) -- кнопка два идет на функцию sleep_ui2
        self:AddCallback("btn_3", ui_events.BUTTON_CLICKED, self.sleep_ui3, self) -- кнопка три идет на функцию sleep_ui3
        if db.actor.health < 0.9 then
        self:AddCallback("btn_4", ui_events.BUTTON_CLICKED, self.sleep_ui4, self) -- кнопка идет на sleep_ui4
        end
        self:AddCallback("btn_quit", ui_events.BUTTON_CLICKED, self.on_quit, self) -- кнопка идет на выход
    end
    
    function sleep_ui:OnKeyboard(dik, keyboard_action) -- функция на отмену сна при нажатии клавиши Esc
        CUIScriptWnd.OnKeyboard(self,dik,keyboard_action)
        if keyboard_action == ui_events.WINDOW_KEY_PRESSED then
            if dik == DIK_keys.DIK_ESCAPE then
                self:on_quit()
            end
            if dik == DIK_keys.DIK_NUMPAD1 then
                self:sleep_ui1()
            end
            if dik == DIK_keys.DIK_NUMPAD2 then
                self:sleep_ui2()
            end
            if dik == DIK_keys.DIK_NUMPAD3 then
                self:sleep_ui3()
            end
            if dik == DIK_keys.DIK_NUMPAD4 then
                self:sleep_ui4()
            end
        end
        return true
    end
    
    function sleep_ui:sleep_ui1() -- вот функция от кнопки один
            main_sleep.sleep_one_hour() -- спим один час
            self:on_quit() -- выход
    end
    function sleep_ui:sleep_ui2() -- вот функция от кнопки два
            main_sleep.sleep_three_hours() -- спим три часа
            self:on_quit()
    end
    function sleep_ui:sleep_ui3() -- вот функция от кнопки три
            main_sleep.sleep_nine_hours() -- спим девять часов
            self:on_quit()
    end
    function sleep_ui:sleep_ui4() -- функция от кнопкм четыри
            main_sleep.sleep_health(scale) -- спим до выздоровления
            self:on_quit()
    end
    
    function sleep_ui:check_game() -- проверка запущена ли игра
        local check = false
        if level.present() and (db.actor ~= nil) and db.actor:alive() then
            check = true
        end
        return check
    end
    
    function sleep_ui:on_quit() -- вот кнопка выхода
        self:GetHolder():start_stop_menu(self, true)
        alife():create("sleep_bag", db.actor:position(), db.actor:level_vertex_id(), db.actor:game_vertex_id(), db.actor:id()) -- спаун мешка обратно
    end
    
    
    [code]-- -----------------------------
    --  DreamMod v0.1 by Ab@dDon ---
    --  Edited by Weanchester    ---
    -- -----------------------------
    
    function sleep_one_hour() -- сон один час
        main_sleep.main(1)
    end
    
    function sleep_three_hours() -- сон три часа
        main_sleep.main(3)
    end
    
    function sleep_nine_hours() -- сон девять часов
        main_sleep.main(9)
    end
    
    function sleep_health(scale) -- сон до выздоровления
        local sleep_time = (1 - db.actor.health)*5.00
        main_sleep.main(sleep_time)
    end
    
    function main(scale) -- основная функция
        basic_time_factor = level.get_time_factor () -- вычисление стандартной скорости течения времени
        db.actor:stop_talk() -- если игрок с кем-нибудь говорит, диалог закрывается. Здесь в ней нет смысла, но вдруг кому пригодится
        db.actor:hide_weapon() -- ГГ прячет оружие в рюкзак
        level.disable_input() -- отключение управления  
        main_sleep.starter (scale) -- запуск скрипта, перематывающего время
    end
    
    function starter(scale) -- скрипт перемотки на нужное время
        local factor = scale * 2650 -- вычисление времени "пробуждения"
        game.start_tutorial("time_scaling") -- вызов функции перемотки
        level.set_time_factor(factor) -- собственно сама перемотка
    end
    
    function dreamer() -- отвечает за сны
        level.set_time_factor(basic_time_factor) --остановка перемотки. basic_time_factor - стандартная скорость течения времени
        local dream = dream.sleep_video_name_callback () -- позволяет "показать" сон
        if dream ~= "" then
        game.start_tutorial(dream) -- показ одного из трёх снов
        else
        game.start_tutorial("without_dream")  -- "без сна"
        end
    end
    
    function stopper()
        level.add_cam_effector("camera_effects\\dream.anm", 1, false, "") -- эффект подъема
        db.actor:restore_weapon() -- ГГ достаёт оружие
        level.enable_input() -- включается управление
        level.add_pp_effector("yantar_underground_psi.ppe", 222, false, "") -- эффект подъема
        if db.actor.health <= 0.60 then -- если хп упало меньше 60, то запускается функция съедания еды
        main_sleep.eat_food()
        end
    end
    
    function eat_food() -- функция съедания еды
    if db.actor:eat(db.actor:object("conserva")) ~= nil or
       db.actor:eat(db.actor:object("bread")) ~= nil or
       db.actor:eat(db.actor:object("kolbasa")) ~= nil then
       end
    end[/code]

    С самым главным работа завершена. Переходим к предпоследнему пункту.

    Работа с XML-описателем
    Заходим в gamedata\config\ui, создаем файл с названием ui_sleep.xml, открываем его и пишем:

    <?xml version="1.0" encoding="windows-1251" ?>
    
    <main>
        <back_video x="10" y="10" width="380" height="320" stretch="1">
            <texture>ui\credits_back_512_v10</texture>
        </back_video>
    
        <background x="0" y="0" width="400" height="340" stretch="1">
            <texture x="0" y="0" width="350" height="460">ui\ui_dg_inventory</texture>
        </background>
    
        <caption x="175" y="30" width="50" height="35">
            <text>Сон</text>
        </caption>
    
        <btn_1 x="72" y="80" width="256" height="35">
        <texture_e>ui\ui_btn_mm_e</texture_e>
        <texture_t>ui\ui_btn_mm_t</texture_t>
        <texture_h>ui\ui_btn_mm_h</texture_h>
            <text>Спать 1 час</text>
        </btn_1>
    
        <btn_2 x="72" y="130" width="256" height="35">
        <texture_e>ui\ui_btn_mm_e</texture_e>
        <texture_t>ui\ui_btn_mm_t</texture_t>
        <texture_h>ui\ui_btn_mm_h</texture_h>
            <text>Спать 3 часа</text>
        </btn_2>
    
        <btn_3 x="72" y="180" width="256" height="35">
        <texture_e>ui\ui_btn_mm_e</texture_e>
        <texture_t>ui\ui_btn_mm_t</texture_t>
        <texture_h>ui\ui_btn_mm_h</texture_h>
            <text>Спать 9 часов</text>
        </btn_3>
    
        <btn_4 x="72" y="230" width="256" height="35">
        <texture_e>ui\ui_btn_mm_e</texture_e>
        <texture_t>ui\ui_btn_mm_t</texture_t>
        <texture_h>ui\ui_btn_mm_h</texture_h>
            <text>Спать до восстановления здоровья</text>
        </btn_4>
    
            <btn_quit x="270" y="300" width="117" height="29">
        <texture_e>ui_button_ordinary_e</texture_e>
        <texture_t>ui_button_ordinary_t</texture_t>
        <texture_h>ui_button_ordinary_h</texture_h>
            <text>Выход</text>
            </btn_quit>
    </main>

    Итак, кнопки описали. Последний пункт.

     

    Сны
    Заходим в gamedata\config\ui, ищем файл ui_movies, открываем и в самом конце пишем:

    <Movie-003_Rats_OutPut-010>
            <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\dream_rats</sound>
                <pause_state>on</pause_state>
                <function_on_stop>main_sleep.stopper</function_on_stop>
                <video_wnd x="0" y="0" width="1024" height="768" stretch="1">
                    <texture x="0" y="1" width="512" height="245">sleep\movie-003_rats_output-010</texture>
                </video_wnd>
            </item>
        </Movie-003_Rats_OutPut-010>
    
        <esc_sky_01>
            <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\human_01\dolg\states\sleep\sleep_1.ogg</sound>
                <pause_state>on</pause_state>
                <function_on_stop>main_sleep.stopper</function_on_stop>
                <video_wnd x="0" y="0" width="1024" height="768" stretch="1">
                    <texture x="0" y="1" width="512" height="245">sleep\esc_sky_01</texture>
                </video_wnd>
            </item>
        </esc_sky_01>
    
        <aes_sky_red>
            <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>ambient\air_2.ogg</sound>
                <pause_state>on</pause_state>
                <function_on_stop>main_sleep.stopper</function_on_stop>
                <video_wnd x="0" y="0" width="1024" height="768" stretch="1">
                    <texture x="0" y="1" width="512" height="245">sleep\aes_sky_red</texture>
                </video_wnd>
            </item>
        </aes_sky_red>
    
        <without_dream>
            <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\human_01\dolg\states\sleep\sleep_1.ogg</sound>
                <pause_state>on</pause_state>
                <function_on_stop>main_sleep.stopper</function_on_stop>
                <video_wnd x="0" y="0" width="1024" height="768" stretch="1">
                    <texture x="0" y="1" width="1024" height="768">intro\intro_back</texture>
                </video_wnd>
            </item>
        </without_dream>
    
        <time_scaling>
            <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\human_01\monolith\states\sleep\sleep_6.ogg</sound>
                <pause_state>off</pause_state>
                <can_be_stopped>off</can_be_stopped>
                <function_on_stop>main_sleep.dreamer</function_on_stop>
                <video_wnd x="0" y="0" width="1024" height="768" stretch="1">
                    <texture x="0" y="1" width="1024" height="768">intro\intro_back</texture>
                </video_wnd>
            </item>
        </time_scaling>

    Теперь зайдем в gamedata\config\misc, найдем файл dream.ltx, откроем его. В начале будет такая конструкция:

    ;--------------------------------------------------------------------------------
    ;--- Regular dreams -------------------------------------------------------------
    ;--------------------------------------------------------------------------------
    [regular_dream1]
    dream       = sleep\aes_sky_red
    probability = 10
    type        = nightmare
    
    [regular_dream2]
    dream       = sleep\esc_sky_01
    probability = 5
    type        = normal
    
    [regular_dream3]
    dream       = sleep\Movie-003_Rats_OutPut-010
    probability = 8
    type        = happy

    Удаляем sleep\, чтобы получилось так:

    ;--------------------------------------------------------------------------------
    ;--- Regular dreams -------------------------------------------------------------
    ;--------------------------------------------------------------------------------
    [regular_dream1]
    dream       = aes_sky_red
    probability = 10
    type        = nightmare
    
    [regular_dream2]
    dream       = esc_sky_01
    probability = 5
    type        = normal
    
    [regular_dream3]
    dream       = Movie-003_Rats_OutPut-010
    probability = 8
    type        = happy

    Сделали мы это, чтоб игра не вылетала во время сна.
    Со снами закончили.

     

    Заключение
    Осталось добавить мешок в игру.
    Для этого заходим в gamedata\scripts, ищем файл escape_dialog.script, открываем его, ищем функцию function give_weapon_to_actor (trader, actor) и после dialogs.relocate_item_section(trader, "wpn_knife", "in") пишем:

    dialogs.relocate_item_section(trader, "sleep_bag", "in")

    Должно получиться:

    function give_weapon_to_actor (trader, actor)
        dialogs.relocate_item_section(trader, "wpn_pm", "in")
        dialogs.relocate_item_section(trader, "ammo_9x18_fmj", "in")
        dialogs.relocate_item_section(trader, "ammo_9x18_fmj", "in")
        dialogs.relocate_item_section(trader, "wpn_knife", "in")
        dialogs.relocate_item_section(trader, "sleep_bag", "in")
    end

    Спальный мешок заспаунится в инвентаре после согласия отбить Шустрого у бандитов.

     

    Примечания
    Иконка у нас не спального мешка, а костюма бандита. Модель - мешок с песком.
    Вот, собственно, и все! Можете тестировать!

     

    Авторы
    Статья создана: Weanchester, TuMaN
    Создал скрипт сна: Ab@dDon
    Отредактировал статью анонимный граммар-наци.

     

    Изменено пользователем World_Stalker
    • Полезно 1
    Ссылка на комментарий

    Пишу в сокращенной форме(без кода) ибо с диалогами давно отлично справляется утилита из состава ЗП sdk и разбирать

    xml в ручную стало гораздо меньше необходимости. Плюс урок явно не для совсем начинающих.

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

    Напрашивающееся решение состоит в том, чтобы проверить dont_has_info "first_time" в ветке 1 и has_info "positive" и "negative" в 2 и 3. После первого разговора и выдачи инфопорции "first_time" выдаем так же один из 2 возможных инфопорций по результату разговора и дело в шляпе - первая ветка отсечена навсегда, так же как и одна из двух других.

    Но на самом деле в таком случае произойдет вылет - казалось бы без всякой логики, но в действительности игра предостерегает нас от ошибок избыточности. Ибо инфорпорция "first_time" нам совершенно не нужна - достаточно в первой ветке написать dont_has_info "positive" и dont_has_info "negative"(2 и 3 помечены как раньше). Выдача одной из этих инфопорций автоматически отсечет 2 ветки из 3.


    Допустим, так же, что в другом случае вам надо, чтобы непись четко решал что-то в вашу пользу при определенном условии и, с какой-то вероятностью, обратном случае тоже(да, именно так). Например, какие-то вопросы скидок, уступок, помощи и т.п. То есть, если вы сделали ему что-то хорошее в прошлом - точно поможет, но может помочь и просто так, по доброте душевной, даже если вы не помогали(ведь вы не враги).

    То есть у нас 2 ветки
    1. Положительное решение вопроса
    2. Отрицательное решение вопроса

    Проще всего сделать так: поставить has_info "neutral" на вторую ветку. Инфопорция эта будет заранее выдаваться вами в том случае, если вы и правда совершенно нейтральны к неписю - тогда выбор автоматически произойдет из двух вариантов случайно - помочь или нет. Если вы помогали ранее, то инфопорция выдана не будет и сработает только первая ветка.

    Понятно, это можно и легко обратить - чтобы непись чаще отказывал, а не помогал, если вы раньше никак не общались.

     

    Изменено пользователем World_Stalker
    Ссылка на комментарий

    Частенько некоторые начинающие модостроители задаются вопросом. Вот я сделал новую модель сталкера, а как сделать к нему иконку? На этот вопрос я постараюсь дать ответ. Итак как я делаю иконки новым визуалам.

    Что нам понадобится для создания иконки нового нпс.


    1. Adobe Photoshop CS 1, 2, 3 (неважно какая версия, я работаю на версии CS 2)
    2. Плагин DDS для фотошопа.
    3. FsCapture
    4. Stalker Icon Editor
    5. И собственно скриншот нашего нпс. Начинаем.

    Сначала заходим в игру. Заходим в опции убираем прицел и распознование нпс. Находим нашего нового нпс (или его можно добавить в повелитель зоны и заспаунить там где хочется) прописываем demo_record 1 и с удобной позиции делаем скриншот. Скриншоты сохраняются по такому пути C:\Documents and Settings\All Users\Документы\STALKER-STCS\screenshots (Это у меня так).

    Итак идем в эту папку, открываем скриншот нашего нпс и включаем FsCapture. Выбираем захват прямоугольной области и захватываем нужную нам часть. Потом когда захватили нужную часть, сохраняем ее в удобную нам папку. Теперь идем в папку в которую сохранили обрезанный скриншот.

    Открываем его Adobe Photoshop'ом. Теперь идем в папку где содержится файл с иконками. В папке gamedata это textures/ui/ui_npc_unique. Его тоже открываем фотошопом. Открываем вкладку с нашим обрезанным скриншотом. Вверху нажимаем кнопку "Изображение" потом выбираем размер изображения. Далее выходит окно. В графе Разрешение стираем все цифры и пишем туда 72. В графе где написано "бикубическая" выбираем вместо нее "бикубическую четкую". В верхней графе где написано "ширина" стираем все цифры и пишем 165, а вместо "высоты" пишем 108. Наше изображение уменьшилось, теперь слева на панели выбираем инструмент "Прямоугольная область" и захватываем всю нашу картинку. Нажимаем Ctrl+C и переходим на вкладку с нашими иконками. Нажимаем Ctrl+V, затем Ctrl+T и перетаскиваем нашу новую иконку на место той которую хотим заменить. Поставили? Нажимаем Enter и сохраняем в формате dds c параметром NO MIP MAPS. Вот всё и готово, заходим и любуемся новой иконкой.

    Если же у вас иконка для уникального нпс, то сохраняем нашу иконку в свободную ячейку, сохраняем открываем программой Stalker Icon Editor(SIE) и находим ее координаты. Координаты находятся так: Нажимаем на новую нашу иконку, потом правой кнопкой мыши и выбираем "Информация о выделении для XML". Там смотрим координаты и записываем в ui_npc_unique.xml в папке configs/ui/textures_descr. Копируем любую строчку называем ее как хотим например было ui_npc_u_nebo_2_face_4, а мы вместо него пишем своё название и вместо цифр которые были ставим наши координаты. Потом заходим в профиль нашего нпс и в графе <Icon> вставляем наше название иконки.

     

    Изменено пользователем World_Stalker
    Ссылка на комментарий
     

    1. Проверка на то, что ГГ находится в укрытии от выброса:

    
    function название_функции()
    if surge_manager.actor_in_cover() then 
    --действие
    end
    end
     

    2. Проверка на то, что ГГ НЕ находится в укрытии от выброса:

    
    function название_функции()
    if not surge_manager.actor_in_cover() then 
    --действие
    end
    end
     

     

    3. Проверка на то, что ГГ жив:

    
    function название_функции()
    if db.actor:alive() then 
    --действие
    end
    end
     

    4. Проверка на то, что ГГ мёртв:

    
    function название_функции()
    if not db.actor:alive() then 
    --действие
    end
    end
     

    5. Проверка на то, что в данный момент идёт выброс:

    
    function название_функции()
    if surge_manager.is_started() then 
    --действие
    end
    end
     

    6. Проверка на то, что в данный момент нет выброса:

    
    function название_функции()
    if surge_manager.is_finished() then 
    --действие
    end
    end
     

    7. Проверка на наличие заданного кол-а денег у ГГ:

    
    function название_функции()
    local money = 1000 - заданное кол-во денег
    if db.actor:money() >= money then 
    --действие
    end
    end
     

    8. Проверка на отсутствие заданного кол-а денег у ГГ:

    
    function название_функции()
    local money = 1000 - заданное кол-во денег
    if db.actor:money() < money then 
    --действие
    end
    end
     

    9. Проверка на то, что у ГГ совсем нет денег:

    
    function название_функции()
    if db.actor:money() == 0 then 
    --действие
    end
    end
     

    10. Проверка на то, что ГГ имеет при себе какой-либо предмет:

    
    function название_функции()
    if db.actor:object("предмет") ~= nil then 
    --действие
    end
    end
     

    11. Проверка на то, что ГГ НЕ имеет при себе какой-либо предмет:

    
    function название_функции()
    if db.actor:object("предмет") == nil then 
    --действие
    end
    end
     
    Изменено пользователем Jurok
    • Полезно 2
    Ссылка на комментарий

    Создание квеста с использованием рестрикторов в Зове Припяти
    Автор: GEONEZIS


    Предположим нам необходимо реализовать квест следующего типа: ГГ будет выдано задание на извлечение определенного предмета из физического обьекта на локации. Пусть будет такой вариант: Сыч дает Дягтереву задание на изьятие из старой антенны и генератора на ВНЗ Круг различных деталей. Для осуществления подобных заданий необходимо использовать рестрикторы. Данный тип квестов в корне отличается от простых, когда по заданным меткам необходимо было просто подобрать заспавненные ранее предметы.

    Необходимые для редактирования файлы:
    1. конфигурационные в (gamedata\configs\gameplay\)
    -character_desc_zaton.xml
    -dialogs_zaton.xml
    -info_zaton.xml

    2. конфигурационные в (gamedata\configs\misc\)
    - tm_zaton.ltx
    - quest_items.ltx
    - death_generic.ltx

    3. конфигурационные в (gamedata\configs\text\rus\)
    - st_dialogs_zaton.xml
    - st_quests_zaton.xml
    - ui_st_screen.xml
    - st_items_quest.xml

    4. конфигурационные в (gamedata\configs\ui\)
    - game_tutorials.xml
    5. логики рескрипторов в (gamedata\configs\scripts\zaton\)
    - zat_restr_logic_1.ltx
    - zat_restr_logic_2.ltx

    6. скриптовый в (gamedata\scripts\)
    - dialogs_zaton.script
    - xr_effects.script
    - ui_si.script

    7. Спавн в файле all.spawn (gamedata\spawns\)
    - alife_zaton.ltx

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

    В файл dialogs_zaton.xmlв самом низу добавим диалог:
     
    <dialog id="zat_b106_stalker_sich_test_quest_dialog">            
                     <dont_has_info>zat_b106_sich_quest_complete</dont_has_info>         
                     <phrase_list>
                       <phrase id="0">
                          <text>zat_b106_stalker_sich_test_quest_dialog_0</text>           
                          <next>1</next>
                          <next>2</next>
                       </phrase>
                       <phrase id="1">
                       <dont_has_info>zat_b106_sich_quest_begin</dont_has_info>
                          <text>zat_b106_stalker_sich_test_quest_dialog_1</text>                           
                          <next>11</next>
                          <next>12</next>           
                       </phrase>
                       <phrase id="12">
                          <text>zat_b106_stalker_sich_test_quest_dialog_12</text>
                          <action>dialogs.break_dialog</action>          
                       </phrase>          
                       <phrase id="11">
                          <text>zat_b106_stalker_sich_test_quest_dialog_11</text>
                          <next>111</next>           
                       </phrase>         
                       <phrase id="111">
                           <text>zat_b106_stalker_sich_test_quest_dialog_112</text>
                           <action>dialogs_zaton.zat_b106_sich_give_tasks</action>
                           <give_info>zat_b106_sich_quest_begin</give_info>           
                       </phrase>          
                       <phrase id="2">
                       <has_info>zat_b106_sich_quest_begin</has_info>
                           <text>zat_b106_stalker_sich_test_quest_dialog_2</text>                           
                           <next>3</next>           
                           <next>4</next>
                       </phrase>
                       <phrase id="4">
                           <dont_has_info>zat_b106_sich_quest_restr_2</dont_has_info>
                           <text>zat_b106_stalker_sich_test_quest_dialog_4</text>
                           <action>dialogs.break_dialog</action>           
                       </phrase>             
                       <phrase id="3">
                           <has_info>zat_b106_sich_quest_restr_2</has_info>
                           <text>zat_b106_stalker_sich_test_quest_dialog_3</text>
                           <give_info>zat_b106_sich_quest_complete</give_info>                       
                           <next>331</next>           
                       </phrase>
                       <phrase id="331">              
                           <text>zat_b106_stalker_sich_test_quest_dialog_331</text>           
                           <next>332</next>                           
                       </phrase>
                       <phrase id="332">              
                           <text>zat_b106_stalker_sich_test_quest_dialog_332</text>
                           <action>dialogs_zaton.zat_b106_sich_quest_relocate_item</action>                       
                           <next>333</next>           
                       </phrase>
                       <phrase id="333">
                           <text>zat_b106_stalker_sich_test_quest_dialog_333</text>
                           <action>dialogs_zaton.zat_b106_sich_quest_relocate_reward</action>
                           <next>334</next>           
                       </phrase>
                       <phrase id="334">
                           <text>zat_b106_stalker_sich_test_quest_dialog_334</text>                          
                       </phrase>                   
                   </phrase_list>
            </dialog>

    Ну и чтобы понимать о чем в диалогах идет речь сразу пропишем русскую транскрипцию фраз в файле st_dialogs_zaton.xml
     

    <string id="zat_b106_stalker_sich_test_quest_dialog_0">
             <text>Я по поводу работы.</text>
    </string>
    <string id="zat_b106_stalker_sich_test_quest_dialog_1">
             <text>Работы, хм. Ах да забыл. Есть у меня одно поручение. Нужно сходить на ВНЗ Круг и снять показатели нескольких старых приборов. С одной антенны и старого генератора. Ну что, согласен?</text>
    </string>
    <string id="zat_b106_stalker_sich_test_quest_dialog_11">
            <text>Да, сделаю.</text>
    </string>
    <string id="zat_b106_stalker_sich_test_quest_dialog_12">
            <text>Пока есть другие дела.</text>
    </string>
    <string id="zat_b106_stalker_sich_test_quest_dialog_112">
            <text>Отлично, жду. Награду достойную получишь.</text>
    </string>
    <string id="zat_b106_stalker_sich_test_quest_dialog_2">
            <text>Ну что, сделал что я просил?</text>
    </string>
    <string id="zat_b106_stalker_sich_test_quest_dialog_4">
            <text>Нет, работаю над этим.</text>
    </string>
    <string id="zat_b106_stalker_sich_test_quest_dialog_3">
            <text>Да. Все сделано.</text>
    </string>
    <string id="zat_b106_stalker_sich_test_quest_dialog_331">
            <text>Отлично, давай сюда приборы.</text>
    </string>
    <string id="zat_b106_stalker_sich_test_quest_dialog_332">
            <text>Забирай.</text>
    </string>
    <string id="zat_b106_stalker_sich_test_quest_dialog_333">
            <text>Вот твоя награда. Успехов сталкер.</text>
    </string>
    <string id="zat_b106_stalker_sich_test_quest_dialog_334">
            <text>Бывай.</text>
    </string>

    Теперь разберем по порядку то что добавили.

    Диалог на выдачу и завершение квеста имеет следующую структуру:
    1.Первая часть диалога на выдачу задания. (ветка <next>1</next>)
    - ГГ предлагают задание и он на выбор может временно отказаться от него, тогда диалог будет доступен во второй раз. Либо же согласиться на исполение.
    - Соответсвенно при согласии происходит выдача инфопоршня zat_b106_sich_quest_begin(при старте квеста) и выдача самого квеста через актшион <action>dialogs_zaton.zat_b106_sich_give_tasks</action>.
    - На этом генерация ветки диалога на выдачу задания будет заблокирована, из-за наличия во фразе 1условия <dont_has_info>zat_b106_sich_quest_begin</dont_has_info>
    2.Вторая часть диалога доступная уже после взятия задания.
    - Ее генерация происходит путем активации ветки (<next>2</next>), первая фраза которой будет доступна только полсе старта задания то есть наличия условия <has_info>zat_b106_sich_quest_begin</has_info>
    - Следующие фразы будут доступны также на выбор (<next>3</next>и <next>4</next>) Фраза 4будет доступна сразу же после взятия квеста- она будет являться закрывающей диалог (акшион <action>dialogs.break_dialog</action>). Генерируется она путем наличия условия <dont_has_info>zat_b106_sich_quest_restr_2</dont_has_info>Эта фраза сообщает о том что ГГ еще не выполнил задание.
    - Фраза 3которая является веткой завершения диалога будет доступна только при наличии условия <has_info>zat_b106_sich_quest_restr_2</has_info>(этот инфопоршень мы получим в процессе выполнения квеста) при этом фраза 4 будет заблокирована.
    - в треьей фразе будет происходить выдача условия <give_info>zat_b106_sich_quest_complete</give_info>обеспечивающего завершение квеста и полное блокирование диалога.
    - также отметим наличие акшионов <action>dialogs_zaton.zat_b106_sich_quest_relocate_item</action>и <action>dialogs_zaton.zat_b106_sich_quest_relocate_reward</action>отвечающих за передачу квестовых предметов и выдачу награды.


    Объявим используемые инфопоршни в info_zaton.xml. Добавим в конце файла код:

    ....
    <info_portion id="zat_b106_sich_quest_complete"></info_portion>
    <info_portion id="zat_b106_sich_quest_begin"></info_portion>
    <info_portion id="zat_b106_sich_quest_restr_1"></info_portion>
    <info_portion id="zat_b106_sich_quest_restr_2"></info_portion>
    ....

    Добавим наш диалог НПС (В данном случае Сычу) для этого в файл character_desc_zaton.xmlв его профиль <specific_character id="zat_b30_owl_stalker_trader" team_default="1">добавим строку диалога

    ....
    <actor_dialog>zat_b106_stalker_sich_test_quest_dialog</actor_dialog>
    ....

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

    В файл quest_items.ltxпропишем две секции предметов zat_b206_sich_quest_item_1и zat_b206_sich_quest_item_2. Оба предмета являются квестовым- невозможна их продажа и выкладывание из инвентаря


    [zat_b206_sich_quest_item_1]:device_pda
    $spawn     = "quest_items\zat_b206_sich_quest_item_1"
    visual    = dynamics\equipments\quest\materials_textolite.ogf
    description   = st_zat_b206_sich_quest_item_1_descr
    inv_name   = st_zat_b206_sich_quest_item_1_name
    inv_name_short                       = st_zat_b206_sich_quest_item_1_name
    inv_weight   = 0.1
    can_trade   = false
    quest_item                     = true
    inv_grid_width                = 1
    inv_grid_height                = 1
    inv_grid_x   = 2
    inv_grid_y   = 19
    
    [zat_b206_sich_quest_item_2]:device_pda
    $spawn     = "quest_items\zat_b206_sich_quest_item_2"
    visual    = dynamics\equipments\quest\materials_wire.ogf
    description   = st_zat_b206_sich_quest_item_2_descr
    inv_name   = st_zat_b206_sich_quest_item_2_name
    inv_name_short                    = st_zat_b206_sich_quest_item_2_name
    inv_weight   = 0.1
    can_trade   = false
    quest_item                     = true
    inv_grid_width                = 1
    inv_grid_height                = 1
    inv_grid_x   = 14
    inv_grid_y   = 19

    В файл death_generic.ltxпропишем: (в данном случае также необязательно так как генерации в инвентаре НПС нет)

    ....
    zat_b206_sich_quest_item_1 = true
    zat_b206_sich_quest_item_2 = true
    ....

    В файл ui_si.scriptтаблица info_tableдобавим (для спавна, в принципе работать будет и без внесения в этот файл):
     

    ....
    "zat_b206_sich_quest_item_1",
    "zat_b206_sich_quest_item_2",
    ....

    В файл st_items_quest.xmlпропишем дескрипцию предметов.
     

    <string id="st_zat_b206_sich_quest_item_1_name">
            <text>Первая деталь</text>
    </string>
    <string id="st_zat_b206_sich_quest_item_1_descr">
            <text>Одна из основных деталей общей схемы в исседовательской антенне.</text>
    </string>
    <string id="st_zat_b206_sich_quest_item_2_name">
            <text>Вторая деталь</text>
    </string>
    <string id="st_zat_b206_sich_quest_item_2_descr">
            <text>Одна из компановочных составляющих старого генератора.</text>
    </string>

    Квестовые предметы прописали, теперь же добавим рестрикторы используемые в квесте.

    - Прежде всего создадим сами рестрикторы добавив в файл alife_zaton.ltxраспакованного программой ACDC all.spawn



    [zaton_1865120]
    ; cse_abstract properties
    section_name = space_restrictor
    name = zat_test_quest_restrictor_1
    position = -432.537384048828,11.5833719020996,-46.925877601563
    direction = 0,0.841602981090546,0
    
    ; cse_alife_object properties
    game_vertex_id = 51
    distance = 0
    level_vertex_id = 131423
    object_flags = 0xffffff3e
    custom_data = <<END
    [story_object]
    story_id = zat_restr_1_id
    
    [logic]
    cfg = scripts\zaton\zat_restr_logic_1.ltx
    END
    
    ; cse_shape properties
    shapes = shape0
    shape0:type = box
    shape0:axis_x = 4,0,0
    shape0:axis_y = 0,3.13100147247314,0
    shape0:axis_z = 0,0,2
    shape0:offset = 0,0,0
    
    ; cse_alife_space_restrictor properties
    restrictor_type = 3
    
    [zaton_1865121]
    ; cse_abstract properties
    section_name = space_restrictor
    name = zat_test_quest_restrictor_2
    position = -391.867065048828,10.9986919020996,-15.951530601563
    direction = 0,0.841602981090546,0
    
    ; cse_alife_object properties
    game_vertex_id = 51
    distance = 0
    level_vertex_id = 190168
    object_flags = 0xffffff3e
    custom_data = <<END
    [story_object]
    story_id = zat_restr_2_id
    
    [logic]
    cfg = scripts\zaton\zat_restr_logic_2.ltx
    END
    
    ; cse_shape properties
    shapes = shape0
    shape0:type = box
    shape0:axis_x = 4,0,0
    shape0:axis_y = 0,3.13100147247314,0
    shape0:axis_z = 0,0,2
    shape0:offset = 0,0,0
    
    ; cse_alife_space_restrictor properties
    restrictor_type = 3

    - Имена секций рестикторов должны быть уникальны (как собственное имя, так и порядковое внутри алл спавна)
    - Они должны иметь тип 3
    - Координаты точки спавна рестикторов должны задаваться рядом с тем обектом на локации который мы будем использовать. (position, level_vertex_id, game_vertex_id)
    - story_id = zat_restr_2_id- уникальный айди номер рестриктора на который будет выставляться квестовая метка.
    - shape0- общий тип и размер зоны рестриктора- при изменении числовых значений можно как увеличить, так и уменьшить радиус активной зоны вблизи юзаемого предмета.
    - cfg = scripts\zaton\zat_restr_logic_2.ltx- путь к файлу логики рестриктора.

    Теперь пропишем логики рестрикторов. Рассмотрим только одну- вторая создается по образу первой.
    Создадим файл zat_restr_logic_1.ltxИ пропишем в него следующий код:
     

    [logic]
    active = sr_idle@start
    
    [sr_idle@start]
    on_info  = {+zat_b106_sich_quest_begin =actor_in_zone(zat_test_quest_restrictor_1)} sr_idle@tutorial %=run_tutorial(zat_sich_quest_1_tutor)%
    on_info2 = {+zat_b106_sich_quest_restr_1} sr_idle@nil
    
    [sr_idle@tutorial]
    on_info   = {+zat_b106_sich_quest_begin !actor_in_zone(zat_test_quest_restrictor_1)} sr_idle@start %=stop_tutorial%
    on_info2 = {+zat_b106_sich_quest_restr_1} sr_idle@nil
    on_info3 = {!has_active_tutorial} sr_idle@start
    
    [sr_idle@nil]

    Опишем что означает эта логика и по какому принципу она строиться:

    - всего логика имеет три секции это sr_idle@start- она же изначально активная, [sr_idle@tutorial]по исполнению гайм туториала, [sr_idle@nil]- нулевое значение логики.
    - основной принцип работы это проверка наличия двух условий- это старт квеста (zat_b106_sich_quest_begin) и наличия актора в зоне рестиктора =actor_in_zone(zat_test_quest_restrictor_1)при их соблидение подается команда на старт туториала юзания предмета %=run_tutorial(zat_sich_quest_1_tutor)%
    - если актор находился в зоне рестиктора, но потом вышел из нее !actor_in_zone(zat_test_quest_restrictor_1)происходит выдача команды на остановку туториала %=stop_tutorial% и возвращение логики в исходное стартовое состоянии. Запуск или остановку туториала можно проследить по активации надписи юзания предмета.
    - соотвестсвенно в независимости от того какая секция логики активна при выдаче инфопоршня zat_b106_sich_quest_restr_1происходит обнуление логики рестиктора. Дальнейшая работа туториалов в ней будет невозможно.

    Текст активирущийся при юзании рестриктора буде прописан в ui_st_screen.xml

    <string id="zat_sich_quest_tips">
                <text>Извлечь деталь</text>
    </string>

    Сам туториал пропишем в файле game_tutorials.xml
     

    <zat_sich_quest_1_tutor>
    <global_wnd/>
    <item>
    <disabled_key>quit</disabled_key>
    <length_sec/>
    <action id="use" finalize="1">xr_effects.zat_sich_quest_1</action>
    <guard_key>use</guard_key>
    <grab_input>0</grab_input>
    <main_wnd>
    <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="graffiti22" r="225" g="225" b="250" a="255" align="c">zat_sich_quest_tips</text>
    </auto_static>
    </main_wnd>
    </item>
    </zat_sich_quest_1_tutor>

    Основные параметры это:
    - <action id="use" finalize="1">xr_effects.zat_sich_quest_1</action>выполняемое действие по скрипту xr_effects.zat_sich_quest_1
    - zat_sich_quest_tips- текст сообщения перед юзанием

    В файл xr_effects.scriptпропишем скрипты исполняемые при юзании рескриптора.

    function zat_sich_quest_1(actor, npc)
         if xr_conditions.actor_in_zone(actor, npc, {"zat_test_quest_restrictor_1"})
          then
          db.actor:give_info_portion("zat_b106_sich_quest_restr_1")
          give_actor(db.actor,nil,{"zat_b206_sich_quest_item_1"})
         end
    end
    function zat_sich_quest_2(actor, npc)
         if xr_conditions.actor_in_zone(actor, npc, {"zat_test_quest_restrictor_2"})
          then
          db.actor:give_info_portion("zat_b106_sich_quest_restr_2")
          give_actor(db.actor,nil,{"zat_b206_sich_quest_item_2"})
         end
    end

    -Происходит проверка наличия актора в зоне zat_test_quest_restrictor_1и если оно истинно тогда происходит выдача инфопоршня zat_b106_sich_quest_restr_1и спавн в рюкзак ГГ айтема zat_b206_sich_quest_item_1


    С созданием рестрикторов и туториалов разобрались. Теперь пропишем остальные скриптовые функции:

    В файле dialogs_zaton.scriptдобавим следующие функции:
     

    function zat_b106_sich_give_tasks(first_speaker, second_speaker)      
          task_manager.get_task_manager():give_task("geonezis_zat_b206_sich_example_task")
    end
    
    function zat_b106_sich_quest_relocate_item(first_speaker, second_speaker)    
           local items_table = {
             "zat_b206_sich_quest_item_1",
             "zat_b206_sich_quest_item_2",
             }
        for k,v in pairs(items_table) do
         if db.actor:object(v) ~= nil then
          dialogs.relocate_item_section_from_actor(first_speaker, second_speaker, v)      
         end
        end
    end
    
    function zat_b106_sich_quest_relocate_reward(first_speaker, second_speaker)    
          dialogs.relocate_money_to_actor(first_speaker, second_speaker, 5000)
    end

    Поясним их:

    - Выдача квеста
    - Передача квестовых предметов неписю
    - Выдача ГГ награды за квест


    Так и собственно в завершении осталось расписать сам квест:

    В файл tm_zaton.ltxдобавим код:
     

    [geonezis_zat_b206_sich_example_task]
    icon = ui_inGame2_Zamanchiviy_biznes
    prior = 1
    storyline = false
    title = {+zat_b106_sich_quest_restr_2} zat_b206_sich_example_title2, {+zat_b106_sich_quest_restr_1 -zat_b106_sich_quest_restr_2} zat_b206_sich_example_title1, {-zat_b106_sich_quest_restr_1} zat_b206_sich_example_title0
    descr = {+zat_b106_sich_quest_restr_2} zat_b206_sich_example_text2, {+zat_b106_sich_quest_restr_1 -zat_b106_sich_quest_restr_2} zat_b206_sich_example_text1, {-zat_b106_sich_quest_restr_1} zat_b206_sich_example_text0
    target = {+zat_b106_sich_quest_restr_2} zat_b30_owl_stalker_trader_id, {+zat_b106_sich_quest_restr_1 -zat_b106_sich_quest_restr_2} zat_restr_2_id, {-zat_b106_sich_quest_restr_1} zat_restr_1_id    
    condlist_0 = {+zat_b106_sich_quest_complete} complete
    condlist_1 = {+zat_b106_sich_quest_begin =is_squad_enemy_to_actor(zat_b30_owl_stalker_trader_squad)} fail
    on_complete = %=inc_faction_goodwill_to_actor(stalker:50)%    

    Пояснения:

    - квест исполняется в три этапа- сначала мы юзаем рестриктор 1, потом после этого второй и в завершении отдаем полученные предметы заказчику. соответсвенно метки перемещаются с zat_restr_1_idна zat_restr_2_idи в завершении на Сыча zat_b30_owl_stalker_trader_id. При этом же обновляются тайтлы и дескрипшины этапов задания. Основные условия их изменения это выдача или же остутсвие двух основных инфопоршней zat_b106_sich_quest_restr_1(получаемого при юзании первого рестриктора) и zat_b106_sich_quest_restr_2(второго)
    - задание завершается при выдаче инфопоршня zat_b106_sich_quest_complete
    - квест будет провален если после его старта НПС заказчика стал враждебен по отношению к ГГ =is_squad_enemy_to_actor(zat_b30_owl_stalker_trader_squad)
    - по завершению квеста происходит повышение репутации у сталкеров %=inc_faction_goodwill_to_actor(stalker:50)%

    В файле st_quests_zaton.xmlпропишем тайтлы и дескрипшины квеста:
     

    <string id="zat_b206_sich_example_title0">
        <text>Задание Сыча: извлеките компонент из старой антенны.</text>
    </string>
    <string id="zat_b206_sich_example_text0">
        <text>Необходимо отправиться на ВНЗ Круг и извлечь деталь обьекта со старой антенны.</text>
    </string>
    <string id="zat_b206_sich_example_title1">
        <text>Задание Сыча: извлеките вторую деталь со старого генератора</text>
    </string>
    <string id="zat_b206_sich_example_text1">
        <text>Заберите вторую необходимую заказчику деталь.</text>
    </string>
    <string id="zat_b206_sich_example_title2">
        <text>Задание Сыча: отдайте заказчику найденные детали.</text>
    </string>
    <string id="zat_b206_sich_example_text2">
        <text>Передайте все старые детали и компоненты Сычу.</text>
    </string>

    На этом урок добавления подобного класса заданий завершен.

    Файл с отработанным заданием можно скачать тут: http://narod.ru/disk/40325310001/example_q...ezis_2.rar.html

     

    Изменено пользователем World_Stalker
    • Нравится 1
    • Полезно 2

    - автор модов GA for SGM 1.7, серия "Смерти вопреки".
    - автор уроков квестостроения на X-Ray 1.6
    - работал в командах SGM, Spectrum Project (Путь во Мгле). 

    Ссылка на комментарий

    Лёгкий спавн трупа NPC (без функций АМК)

    Пишем вот такую простенькую функцию:


    function [имя функции]()
    local obj= alife():create("имя секции в spawn_sections.ltx",vector():set(x,y,z),level_vertex,game_vertex)
    obj:on_death()
    end
    На примере - Ученый, близ упавшего вертолета, на армейских складах:
    function tester()
    local obj= alife():create("yan_ecolog_respawn_1",vector():set(-38.981,-17.916,355.841),273797,1816)
    obj:on_death()
    end

    Изменено пользователем World_Stalker
    Ссылка на комментарий

    В файле

    spawn_sections.ltx пишем конфиг тайника:
    [s_inventory_box7]:kostya_box  -- в квадратных скобках уникальная секция тайника
    visual = equipments\item_rukzak
    radius = 1
    custom_data = scripts\s_inventory_box7.ltx   -- файл с наполнением тайника

    Файл s_inventory_box7.ltx содержит следующее:

    [spawn]
    mutant_gigant_cocoon = 1
    mutant_poltergeist_cocoon = 1
    af_armor_3 = 3
    strelok_taynik_pda30

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

        -- спавним наш тайник
        local obj = alife():create("s_inventory_box7",db.actor:position(),db.actor:level_vertex_id(),db.actor:game_vertex_id())
        -- в нужном нам месте вызываем функцию спавна дополнительного хабара в тайник:
        function dospavn(section, obj)
            alife():create(section,vector():set(0,0,0),0,0,obj.id)
        end

    В функцию передается секция предмета и ссылка на тайник, полученная с помощью команды создания тайника alife():create(). Координаты тайника не нужны. Когда в функции alife():create() задан последний параметр, так называемый parent или родитель создаваемого объекта, то координаты игнорируются - новый предмет будет в рюкзаке.

            local obj = alife():create("esc_stalker_respawn_1",db.actor:position(),db.actor:level_vertex_id(),db.actor:game_vertex_id())
            local tbl = amk.read_stalker_params(obj)
            tbl.health = 0.1
            tbl.updhealth = 0.05
            amk.write_stalker_params(tbl, obj)

    В результате выполнения этого кода рядом с ГГ появится раненый сталкер и будет просить аптечку. Для использования этого кода нужны функции АМК.

     

    Изменено пользователем World_Stalker
    • Смешно 1
    Ссылка на комментарий

    Вывод сообщения о малом ХП (рабочая функция)
    Автор статьи - Akella-96 aka SvD

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

    Итак, начнем :

    Сперва находим в

    gamedata\scripts\bind_stalker.script вот эту функцию
    --[[
        --' Вывод сообщения о большой радиации
        if self.object.radiation >= 0.7 then
            local hud = get_hud()
            local custom_static = hud:GetCustomStatic("cs_radiation_danger")
            if custom_static == nil then
                hud:AddCustomStatic("cs_radiation_danger", true)
                hud:GetCustomStatic("cs_radiation_danger"):wnd():TextControl():SetTextST("st_radiation_danger")
            end
        else
            local hud = get_hud()
            local custom_static = hud:GetCustomStatic("cs_radiation_danger")
            if custom_static ~= nil then
                hud:RemoveCustomStatic("cs_radiation_danger")
            end
        end
    ]]--

    И после неё пишем

    -----------------------------------------------------------------------------------------------------------
        --' Вывод сообщения о малом ХП автор - Akella-96 aka SvD
        if self.object.health <= 0.3 then
            local hud = get_hud()
            local custom_static = hud:GetCustomStatic("cs_health_danger")
            if custom_static == nil then
                hud:AddCustomStatic("cs_health_danger", true)
                hud:GetCustomStatic("cs_health_danger"):wnd():TextControl():SetTextST("st_health_danger")
            end
        else
            local hud = get_hud()
            local custom_static = hud:GetCustomStatic("cs_health_danger")
            if custom_static ~= nil then
                hud:RemoveCustomStatic("cs_health_danger")
            end
        end
    ----------------------------------------------------------------------------------------------------------

    Потом идем в gamedata\configs\ui\ui_custom_msgs.xml и в самом начале пишем

            <cs_health_danger  x="262" y="50" width="500" height="20" complex_mode="1">
                    <text font="graffiti22"  r="255" g="0" b="0" a="255" align="c"/>
            </cs_health_danger>

    Далее идем в gamedata\configs\text\rus\ui_st_screen.xml в самый конец, перед </string_table> добавляем

             <string id="st_health_danger">
            <text>У вас мало здоровья! Примите аптечку!</text>
        </string>

    Все. Теперь при состоянии здоровья, меньшего 30% будет выводиться сообщение.

     

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

    AWRP : Re - Load 0.2 ©

    Ссылка на комментарий

    Создание многоэтапного квеста на последовательный поиск предметов. Реализация на X-Ray 1.6

    Автор урока: GEONEZIS


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

    Необходимые для редактирования файлы:
    1. конфигурационные в (gamedata\configs\gameplay\)
    -character_desc_jupiter.xml
    -dialogs_jupiter.xml
    -info_jupiter.xml

    2. конфигурационные в (gamedata\configs\misc\)
    - tm_jupiter.ltx
    - quest_items.ltx
    - death_generic.ltx

    3. конфигурационные в (gamedata\configs\text\rus\)
    - st_dialogs_jupiter.xml
    - st_quests_jupiter.xml
    - st_items_quest.xml

    4. конфигурационные в (gamedata\configs\misc\trade\)
    - trade_generic.ltx
    5. скриптовый в (gamedata\scripts\)
    - dialogs_jupiter.script
    - ui_si.script
    - bind_stalker.script
    - new_tasks.script


    Рассмотрим структуру квестовых диалогов. Для этого откроем dialogs_jupiter.xmlи в самом низу добавим два диалога. Один активный при старте задания. Второй на завершение. В принципе можно было объединить их в один, но рассмотрим более легкий вариант. Однока при этом внесем разнообразие в процесс выдачи задания предоставив несколько вариантов его получения внутри диалога. Этот несколько освежит стандартные методы диалогостроения, когда все они делаются последовательными, без каких-либо вариантов.

    1- ый диалог:
    <dialog id="jup_b6_scientist_tech_quest_anomalies_scaner">           
        <dont_has_info>jup_novikov_quest_zaton_scanner_start</dont_has_info>
            <phrase_list>
               <phrase id="0">
                           <text>jup_b6_scientist_tech_quest_anomalies_scaner_0</text>
                           <next>1</next>                       
                </phrase>
                <phrase id="1">
                           <text>jup_b6_scientist_tech_quest_anomalies_scaner_1</text>
                           <next>2</next>                       
                </phrase>
                <phrase id="2">
                           <text>jup_b6_scientist_tech_quest_anomalies_scaner_2</text>
                           <action>dialogs_jupiter.jup_b6_create_first_scaner</action>
                           <next>3</next>                       
                </phrase>
                <phrase id="3">
                           <text>jup_b6_scientist_tech_quest_anomalies_scaner_3</text>
                           <next>4</next>        
                           <next>5</next>
                           <next>6</next>           
                </phrase>          
                <phrase id="4">
                           <text>jup_b6_scientist_tech_quest_anomalies_scaner_4</text>
                           <next>41</next>                       
                </phrase>
                <phrase id="41">
                           <text>jup_b6_scientist_tech_quest_anomalies_scaner_41</text>
                           <next>401</next>        
                           <next>402</next>           
                       </phrase>
                <phrase id="401">
                           <text>jup_b6_scientist_tech_quest_anomalies_scaner_401</text>
                           <next>4011</next>                       
                       </phrase>
                <phrase id="4011">
                           <text>jup_b6_scientist_tech_quest_anomalies_scaner_4011</text>
                           <next>4012</next>                       
                       </phrase>
                <phrase id="4012">
                           <text>jup_b6_scientist_tech_quest_anomalies_scaner_4012</text>
                           <next>4013</next>
                           <action>dialogs_jupiter.give_novikov_zaton_scaner_quest</action>                       
                       </phrase>
                <phrase id="4013">
                           <text>jup_b6_scientist_tech_quest_anomalies_scaner_4013</text>
                           <give_info>jup_novikov_quest_zaton_scanner_start</give_info>           
                       </phrase>          
                <phrase id="402">
                           <text>jup_b6_scientist_tech_quest_anomalies_scaner_402</text>
                           <next>4021</next>                       
                       </phrase>
                <phrase id="4021">
                           <text>jup_b6_scientist_tech_quest_anomalies_scaner_4021</text>
                           <next>4022</next>                       
                       </phrase>
                <phrase id="4022">
                           <text>jup_b6_scientist_tech_quest_anomalies_scaner_4022</text>
                           <next>4023</next>
                           <action>dialogs_jupiter.give_novikov_zaton_scaner_quest</action>                       
                       </phrase>
                <phrase id="4023">
                           <text>jup_b6_scientist_tech_quest_anomalies_scaner_4023</text>
                           <give_info>jup_novikov_quest_zaton_scanner_start</give_info>           
                </phrase>          
                <phrase id="5">
                           <text>jup_b6_scientist_tech_quest_anomalies_scaner_5</text>
                           <next>51</next>                       
                </phrase>
                <phrase id="51">
                           <text>jup_b6_scientist_tech_quest_anomalies_scaner_51</text>
                           <next>52</next>                       
                </phrase>
                <phrase id="52">
                           <text>jup_b6_scientist_tech_quest_anomalies_scaner_52</text>
                           <next>53</next>                       
                </phrase>
                <phrase id="53">
                           <text>jup_b6_scientist_tech_quest_anomalies_scaner_53</text>
                           <action>dialogs_jupiter.jup_b6_to_actor_give_spez_outfit</action>
                           <next>531</next>
                           <next>532</next>                       
                       </phrase>
                <phrase id="531">
                           <text>jup_b6_scientist_tech_quest_anomalies_scaner_531</text>
                           <next>5312</next>                       
                       </phrase>
                <phrase id="5312">
                           <text>jup_b6_scientist_tech_quest_anomalies_scaner_5312</text>
                           <next>5313</next>
                           <action>dialogs_jupiter.give_novikov_zaton_scaner_quest</action>           
                       </phrase>
                <phrase id="5313">
                           <text>jup_b6_scientist_tech_quest_anomalies_scaner_5313</text>
                           <give_info>jup_novikov_quest_zaton_scanner_start</give_info>           
                </phrase>          
                <phrase id="532">
                           <text>jup_b6_scientist_tech_quest_anomalies_scaner_532</text>
                           <next>5321</next>
                           <action>dialogs_jupiter.give_novikov_zaton_scaner_quest</action>                       
                       </phrase>
                <phrase id="5321">
                           <text>jup_b6_scientist_tech_quest_anomalies_scaner_5321</text>
                           <give_info>jup_novikov_quest_zaton_scanner_start</give_info>           
                </phrase>          
                <phrase id="6">
                           <text>jup_b6_scientist_tech_quest_anomalies_scaner_6</text>
                           <next>61</next>                       
                </phrase>                   
                <phrase id="61">
                           <text>jup_b6_scientist_tech_quest_anomalies_scaner_61</text>
                           <next>611</next>                       
                </phrase>
                <phrase id="611">
                           <text>jup_b6_scientist_tech_quest_anomalies_scaner_611</text>
                           <action>dialogs_jupiter.give_novikov_zaton_scaner_quest</action>
                           <next>6111</next>                       
                </phrase>
                <phrase id="6111">
                           <text>jup_b6_scientist_tech_quest_anomalies_scaner_6111</text>
                           <give_info>jup_novikov_quest_zaton_scanner_start</give_info>           
                </phrase>          
                 </phrase_list>
               </dialog>

    2-ой диалог:
    <dialog id="jup_b6_scientist_tech_quest_anomalies_scaner_end">
                   <has_info>jup_novikov_quest_zaton_scanner_have_6</has_info>
                   <dont_has_info>jup_novikov_quest_zaton_scanner_end</dont_has_info>
            <precondition>dialogs_jupiter.actot_have_all_zaton_scaner</precondition>
                   <phrase_list>
                <phrase id="0">
                       <text>jup_b6_scientist_tech_quest_anomalies_scaner_end_0</text>
                       <action>dialogs_jupiter.actot_to_novikov_give_zaton_scaner</action>
                           <next>1</next>
                       </phrase>
                       <phrase id="1">
                           <text>jup_b6_scientist_tech_quest_anomalies_scaner_end_1</text>
                           <give_info>jup_novikov_quest_zaton_scanner_end</give_info>
                       </phrase>                   
                   </phrase_list>
               </dialog>

    Сразу же пропишем русскую транскрипцию в st_dialogs_jupiter.xmlдля того чтобы понимать о чем в диалоге идет речь :
    <string id="jup_b6_scientist_tech_quest_anomalies_scaner_0">
             <text>Приветствую, хотел бы оказал вам максимально возможное содействие. Какого рода помощь тебе необходима?</text>
            </string>
            <string id="jup_b6_scientist_tech_quest_anomalies_scaner_1">
             <text>В принципе есть одно небольшое дело, главное это твое желание работать.</text>
            </string>
            <string id="jup_b6_scientist_tech_quest_anomalies_scaner_2">
             <text>Я готов.Что нужно делать?</text>
            </string>
            <string id="jup_b6_scientist_tech_quest_anomalies_scaner_3">
             <text>Прекрасно. Правда придется немного побегать. Мне необходимо получить кое-какие данные.</text>
            </string>
            <string id="jup_b6_scientist_tech_quest_anomalies_scaner_4">
             <text>Замеры? Необходимо будет устанавливать какие-нибудь сканеры?</text>
            </string>
            <string id="jup_b6_scientist_tech_quest_anomalies_scaner_41">
             <text>Нет, устанавливать не придется. Их уже установили. Тебе же наоборот придется их собрать и доставить сюда, чтобы я смог получить с них результаты замеров.</text>
            </string>
            <string id="jup_b6_scientist_tech_quest_anomalies_scaner_401">
             <text>Что за сканеры-то? Аномальная активность?</text>
            </string>
            <string id="jup_b6_scientist_tech_quest_anomalies_scaner_4011">
             <text>Обыкновенные сканеры аномалий. Их показатели результатов замеров будут мне необходимы для проведения настройки моего оборудования.</text>
            </string>
            <string id="jup_b6_scientist_tech_quest_anomalies_scaner_4012">
             <text>Все ясно. Придется взять научный комбез. Передавай координаты.</text>
            </string>
            <string id="jup_b6_scientist_tech_quest_anomalies_scaner_4013">
             <text>Уже загрузил. Комбез это хорошая тема. Обязательно возьми. И смотри не сварись в аномалиях.</text>
            </string>
            <string id="jup_b6_scientist_tech_quest_anomalies_scaner_402">
             <text>Кто их устанавливал и куда мне придется отправиться?</text>
            </string>
            <string id="jup_b6_scientist_tech_quest_anomalies_scaner_4021">
             <text>Тебе то не все-равно, кто их размещал. Пару дней назад, сталкеры из Свободы - сойдет такой ответ? Не о том думаешь. Твоя задача отправиться на Затон, пробежаться по точкам и вернуться назад живым вместе со сканерами. Все ясно?</text>
            </string>
            <string id="jup_b6_scientist_tech_quest_anomalies_scaner_4022">
             <text>Все. Передавай координаты.</text>
            </string>
            <string id="jup_b6_scientist_tech_quest_anomalies_scaner_4023">
             <text>Уже загрузил. Комбез научный только одень. И смотри не сварись в аномалиях.</text>
            </string>        
            <string id="jup_b6_scientist_tech_quest_anomalies_scaner_5">
             <text>А может еще что нужно?</text>
            </string>        
            <string id="jup_b6_scientist_tech_quest_anomalies_scaner_51">
             <text>Нет, хотя может быть потом я подберу для тебя работку. Но сначала ты должен будешь добыть результаты измерений с установленных на Затоне сканеров аномалий.</text>
            </string>
            <string id="jup_b6_scientist_tech_quest_anomalies_scaner_52">
             <text>Искать сканеры в аномалиях. Ха, веселая преспектива. Без специального научного костюма мне там долго не пролазить...</text>
            </string>        
            <string id="jup_b6_scientist_tech_quest_anomalies_scaner_53">
             <text>Намек понял. Вот держи ССП-99. Неплохой костюм, хотя и поношенный. Координаты сканеров я тебе загрузил.</text>
            </string>
            <string id="jup_b6_scientist_tech_quest_anomalies_scaner_531">
             <text>Хотя бы кровь с костюма отмыли? По-любому с трупака какого-нибудь своего ботанического дружка сняли...</text>
            </string>
            <string id="jup_b6_scientist_tech_quest_anomalies_scaner_5311">
             <text>Ой, ну давай мне не заливай..Тоже мне брезгливый нашелся. У самого-то, чай не первой свежести костюмчик..</text>
            </string>
            <string id="jup_b6_scientist_tech_quest_anomalies_scaner_5312">
             <text>Проехали Кулибин. Все, я отправляюсь за замерами...</text>
            </string>
            <string id="jup_b6_scientist_tech_quest_anomalies_scaner_5313">
             <text>Поосторожнее там...</text>
            </string>        
            <string id="jup_b6_scientist_tech_quest_anomalies_scaner_532">
             <text>Все понял, отправляюсь.</text>
            </string>        
            <string id="jup_b6_scientist_tech_quest_anomalies_scaner_5321">
             <text>Поосторожнее там...</text>
            </string>        
            <string id="jup_b6_scientist_tech_quest_anomalies_scaner_6">
             <text>Хорошо, я сделаю то что нужно. Говори с чего начинать.</text>
            </string>
            <string id="jup_b6_scientist_tech_quest_anomalies_scaner_61">
             <text>Вот это деловой разговор, делового человека. Вообщем план таков. Сначала ты находишь на Затоне сканеры аномалий, установленные там нашими сподручными сталкерами. Координаты я тебе уже сбросил. Потом, я может быть посмотрю еще что для тебя..</text>
            </string>
            <string id="jup_b6_scientist_tech_quest_anomalies_scaner_611">
             <text>Все ясно, Кулибин. Жди, я за твоими сканерами.</text>
            </string>
            <string id="jup_b6_scientist_tech_quest_anomalies_scaner_6111">
             <text>Поосторожнее там. В аномалиях не сгинь...</text>
            </string>        
            <string id="jup_b6_scientist_tech_quest_anomalies_scaner_end_0">
             <text>Вот все твои сканеры.</text>
            </string>
            <string id="jup_b6_scientist_tech_quest_anomalies_scaner_end_1">
             <text>Отличная работа. Немедленно начинаю работу над обработкой результатов замеров. Новую работу получишь позже. А пока гуляй.</text>
            </string>

    Теперь разберем структуру представленных диалогов:

    - Во втором диалоге нет ничего сложного: активен при наличие инфопоршня jup_novikov_quest_zaton_scanner_have_6, исчезает после выдачи jup_novikov_quest_zaton_scanner_end, имеет прекондишн actot_have_all_zaton_scanerкогда в инвенторе ГГ наличие всех квестовых предметов. содержит один акшион actot_to_novikov_give_zaton_scanerна передачу предметов заказчику.
    - первый диалог сложнее. основная особенность это вложенная тройная разветвленность, когда можно выбрав одну из трех веток получить один и тот же результат.
    - внутри каждой из веток также имеет место дополнительные ответвления.
    - старт задания происходит по выдачи акшиона give_novikov_zaton_scaner_questсопровождается также выдачей инфопоршня jup_novikov_quest_zaton_scanner_start
    - создание первого квестового предмета происходит также внутри диалога- акшион
    jup_b6_create_first_scaner
    - чисто для атмосферности происходит выдача ГГ костюма для выполнения задания при выборе одной из трех веток.
    это акшион jup_b6_to_actor_give_spez_outfit


    Объявим используемые инфопоршни в info_jupiter.xml. Добавим в конце файла код:
    <!--New Quests-->
          <info_portion id="jup_novikov_quest_zaton_scanner_start"></info_portion>
             <info_portion id="jup_novikov_quest_zaton_scanner_end"></info_portion>
             <info_portion id="jup_novikov_quest_zaton_scanner_have_1"></info_portion>
             <info_portion id="jup_novikov_quest_zaton_scanner_create_2"></info_portion>
             <info_portion id="jup_novikov_quest_zaton_scanner_have_2"></info_portion>
             <info_portion id="jup_novikov_quest_zaton_scanner_create_3"></info_portion>
             <info_portion id="jup_novikov_quest_zaton_scanner_have_3"></info_portion>
             <info_portion id="jup_novikov_quest_zaton_scanner_create_4"></info_portion>
             <info_portion id="jup_novikov_quest_zaton_scanner_have_4"></info_portion>
             <info_portion id="jup_novikov_quest_zaton_scanner_create_5"></info_portion>
             <info_portion id="jup_novikov_quest_zaton_scanner_have_5"></info_portion>
             <info_portion id="jup_novikov_quest_zaton_scanner_create_6"></info_portion>
             <info_portion id="jup_novikov_quest_zaton_scanner_have_6"></info_portion>
             <info_portion id="jup_novikov_quest_zaton_scanner_create_7"></info_portion>
             <info_portion id="jup_novikov_quest_zaton_scanner_have_7"></info_portion>


    Добавим наши диалоги НПС (В данном случае Новикову) для этого в файл character_desc_jupiter.xmlв его профиль <specific_character id="jup_b6_scientist_tech" team_default="1">добавим строки диалогов
    .....
    <actor_dialog>jup_b6_scientist_tech_quest_anomalies_scaner</actor_dialog>
    <actor_dialog>jup_b6_scientist_tech_quest_anomalies_scaner_end</actor_dialog>
    .....

    С диалогами и инфопоршнями разобрались теперь добавим необходимые для выполнения квеста предметы.

    В файл quest_items.ltxпропишем семь секций предметов zat_spec_anomaly_scanner_№. Все предметы являются квестовыми- невозможна их продажа и выкладывание из инвентаря ГГ.
    [zat_spec_anomaly_scanner_1]:device_pda
    $spawn     = "quest_items\zat_spec_anomaly_scanner_1"
    description   = zat_spec_anomaly_scanner_1_descr
    inv_name   = zat_spec_anomaly_scanner_1_name
    visual    = dynamics\equipments\quest\scanner_anomaly.ogf
    inv_weight   = 2
    story_id    = zat_spec_anomaly_scanner_1
    can_trade   = false
    quest_item       = true
    inv_grid_width  = 1
    inv_grid_height  = 2
    inv_grid_x   = 10
    inv_grid_y   = 23

    В файл death_generic.ltxпропишем: (в данном случае также необязательно так как генерации в инвентаре НПС нет)
    .......
    zat_spec_anomaly_scanner_1 = true
    zat_spec_anomaly_scanner_2 = true
    zat_spec_anomaly_scanner_3 = true
    zat_spec_anomaly_scanner_4 = true
    zat_spec_anomaly_scanner_5 = true
    zat_spec_anomaly_scanner_6 = true
    zat_spec_anomaly_scanner_7 = true
    .....

    В файл ui_si.scriptв таблицу info_tableдобавим (для спавна, в принципе работать будет и без внесения в этот файл):

    ........
    "zat_spec_anomaly_scanner_1"
    "zat_spec_anomaly_scanner_2"
    "zat_spec_anomaly_scanner_3"
    "zat_spec_anomaly_scanner_4"
    "zat_spec_anomaly_scanner_5"
    "zat_spec_anomaly_scanner_6"
    "zat_spec_anomaly_scanner_7"
    ........

    В файл st_items_quest.xmlпропишем дескрипцию предметов.

    <string id="zat_spec_anomaly_scanner_1_name">
           <text>«Сканер грави-химического симбионта»</text>
          </string>
          <string id="zat_spec_anomaly_scanner_1_descr">
           <text>«Специализированный сканер аномальной активности из серии 32.1351. Используется учеными для изучения процессов происходящих в грави-химическом симбионте»</text>
          </string>
          <string id="zat_spec_anomaly_scanner_2_name">
           <text>«Сканер химической аномалии»</text>
          </string>
          <string id="zat_spec_anomaly_scanner_2_descr">
           <text>«Специализированный сканер аномальной активности из серии 27.7724. Используется учеными для изучения процессов происходящих в химической аномалии»</text>
          </string>
          <string id="zat_spec_anomaly_scanner_3_name">
           <text>«Сканер гравитационной аномалии»</text>
          </string>
          <string id="zat_spec_anomaly_scanner_3_descr">
           <text>«Специализированный сканер аномальной активности из серии 78.9835. Используется учеными для изучения процессов происходящих в гравитационной аномалии»</text>
          </string>
          <string id="zat_spec_anomaly_scanner_4_name">
           <text>«Сканер термальной аномалии»</text>
          </string>
          <string id="zat_spec_anomaly_scanner_4_descr">
           <text>«Специализированный сканер аномальной активности из серии 47.3246. Используется учеными для изучения процессов происходящих в термальной аномалии»</text>
          </string>
          <string id="zat_spec_anomaly_scanner_5_name">
           <text>«Сканер пси-статической аномалии»</text>
          </string>
          <string id="zat_spec_anomaly_scanner_5_descr">
           <text>«Специализированный сканер аномальной активности из серии 06.8912. Используется учеными для изучения процессов происходящих в пси-статической аномалии»</text>
          </string>
          <string id="zat_spec_anomaly_scanner_6_name">
           <text>«Сканер термального симбионта»</text>
          </string>
          <string id="zat_spec_anomaly_scanner_6_descr">
           <text>«Специализированный сканер аномальной активности из серии 35.0205. Используется учеными для изучения процессов происходящих в термальном симбионте»</text>
          </string>
          <string id="zat_spec_anomaly_scanner_7_name">
           <text>«Сканер электро-статической аномалии»</text>
          </string>
          <string id="zat_spec_anomaly_scanner_7_descr">
           <text>«Специализированный сканер аномальной активности из серии 03.1392. Используется учеными для изучения процессов происходящих в электро-статической аномалии»</text>
          </string>

    В файле trade_generic.ltxпропишем торговлю. также нужно добавлять индивидуально во все остальные файлы конфигов торговли. (но не обязательно)
    .....
    zat_spec_anomaly_scanner_1          ;NO TRADE
    zat_spec_anomaly_scanner_2          ;NO TRADE
    zat_spec_anomaly_scanner_3          ;NO TRADE
    zat_spec_anomaly_scanner_4          ;NO TRADE
    zat_spec_anomaly_scanner_5          ;NO TRADE
    zat_spec_anomaly_scanner_6          ;NO TRADE
    zat_spec_anomaly_scanner_7          ;NO TRADE
    ......

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

    В файле dialogs_jupiter.scriptдобавим следующие функции:
    function jup_b6_create_first_scaner(first_speaker, second_speaker)
           alife():create("zat_spec_anomaly_scanner_1",vector():set(-436.574,-6.527,170.169),116113,16)     
    end
    
    function jup_b6_to_actor_give_spez_outfit(first_speaker, second_speaker)
           dialogs.relocate_item_section_to_actor(first_speaker, second_speaker, "scientific_outfit")
    end
    
    function give_novikov_zaton_scaner_quest()     
            task_manager.get_task_manager():give_task("geonezis_jup_spec_scaner")        
    end
    
    function actot_to_novikov_give_zaton_scaner(first_speaker, second_speaker)
           local items_table = {"zat_spec_anomaly_scanner_1","zat_spec_anomaly_scanner_2","zat_spec_anomaly_scanner_3","zat_spec_anomaly_scanner_4","zat_spec_anomaly_scann    er_5","zat_spec_anomaly_scanner_6","zat_spec_anomaly_scanner_7"}
           for k,v in pairs(items_table) do
              if db.actor:object(v) ~= nil then
                 dialogs.relocate_item_section_from_actor(first_speaker, second_speaker, v)       
              end
           end     
    end
    
    function actot_have_all_zaton_scaner(first_speaker, second_speaker)
           return db.actor:object("zat_spec_anomaly_scanner_1")~=nil and db.actor:object("zat_spec_anomaly_scanner_2")~=nil and     
           db.actor:object("zat_spec_anomaly_scanner_3")~=nil and db.actor:object("zat_spec_anomaly_scanner_4")~=nil and     
           db.actor:object("zat_spec_anomaly_scanner_5")~=nil and db.actor:object("zat_spec_anomaly_scanner_6")~=nil and
           db.actor:object("zat_spec_anomaly_scanner_7")~=nil        
    end

    коротко их поясним:
    - спавн первого квестового предмета
    - передача бронекостюма ГГ
    - выдача задания
    - передача всех квестовых предметов НПС
    - скрипт проверки наличия в инвенторе ГГ всех необходимых предметов

    Теперь создадим файл new_tasks.scriptи добавим в него следующий код одной основной функции task_spec():

    --/Квест:Сканеры аномалий
    function task_spec()
    local level_name=level.name()
    if level_name=="zaton" then
        if has_alife_info("jup_novikov_quest_zaton_scanner_start") and (not has_alife_info("jup_novikov_quest_zaton_scanner_have_1")) and db.actor:object("zat_spec_anomaly_scanner_1") then    
           db.actor:give_info_portion("jup_novikov_quest_zaton_scanner_have_1")              
        end
        if has_alife_info("jup_novikov_quest_zaton_scanner_have_1") and (not has_alife_info("jup_novikov_quest_zaton_scanner_create_2")) then    
           alife():create("zat_spec_anomaly_scanner_2",vector():set(-304.058,12.450,-159.233),339472,21)
           db.actor:give_info_portion("jup_novikov_quest_zaton_scanner_create_2")              
        end
        if has_alife_info("jup_novikov_quest_zaton_scanner_create_2") and (not has_alife_info("jup_novikov_quest_zaton_scanner_have_2")) and db.actor:object("zat_spec_anomaly_scanner_2") then    
           db.actor:give_info_portion("jup_novikov_quest_zaton_scanner_have_2")              
        end
        if has_alife_info("jup_novikov_quest_zaton_scanner_have_2") and (not has_alife_info("jup_novikov_quest_zaton_scanner_create_3")) then    
           alife():create("zat_spec_anomaly_scanner_3",vector():set(-68.024,1.398,-164.391),807200,235)        
           db.actor:give_info_portion("jup_novikov_quest_zaton_scanner_create_3")              
        end
        if has_alife_info("jup_novikov_quest_zaton_scanner_create_3") and (not has_alife_info("jup_novikov_quest_zaton_scanner_have_3")) and db.actor:object("zat_spec_anomaly_scanner_3") then    
           db.actor:give_info_portion("jup_novikov_quest_zaton_scanner_have_3")              
        end
        if has_alife_info("jup_novikov_quest_zaton_scanner_have_3") and (not has_alife_info("jup_novikov_quest_zaton_scanner_create_4")) then    
           alife():create("zat_spec_anomaly_scanner_4",vector():set(10.842,8.966,-394.252),964903,8)
           db.actor:give_info_portion("jup_novikov_quest_zaton_scanner_create_4")              
        end
        if has_alife_info("jup_novikov_quest_zaton_scanner_create_4") and (not has_alife_info("jup_novikov_quest_zaton_scanner_have_4")) and db.actor:object("zat_spec_anomaly_scanner_4") then    
           db.actor:give_info_portion("jup_novikov_quest_zaton_scanner_have_4")              
        end
        if has_alife_info("jup_novikov_quest_zaton_scanner_have_4") and (not has_alife_info("jup_novikov_quest_zaton_scanner_create_5")) then    
           alife():create("zat_spec_anomaly_scanner_5",vector():set(272.490,11.985,-289.525),1431789,43)
           db.actor:give_info_portion("jup_novikov_quest_zaton_scanner_create_5")              
        end
        if has_alife_info("jup_novikov_quest_zaton_scanner_create_5") and (not has_alife_info("jup_novikov_quest_zaton_scanner_have_5")) and db.actor:object("zat_spec_anomaly_scanner_5") then    
           db.actor:give_info_portion("jup_novikov_quest_zaton_scanner_have_5")              
        end
        if has_alife_info("jup_novikov_quest_zaton_scanner_have_5") and (not has_alife_info("jup_novikov_quest_zaton_scanner_create_6")) then    
           alife():create("zat_spec_anomaly_scanner_6",vector():set(400.209,-0.202,439.740),1630730,242)
           db.actor:give_info_portion("jup_novikov_quest_zaton_scanner_create_6")              
        end
        if has_alife_info("jup_novikov_quest_zaton_scanner_create_6") and (not has_alife_info("jup_novikov_quest_zaton_scanner_have_6")) and db.actor:object("zat_spec_anomaly_scanner_6") then    
           db.actor:give_info_portion("jup_novikov_quest_zaton_scanner_have_6")              
        end
        if has_alife_info("jup_novikov_quest_zaton_scanner_have_6") and (not has_alife_info("jup_novikov_quest_zaton_scanner_create_7")) then    
           alife():create("zat_spec_anomaly_scanner_7",vector():set(-347.855,40.160,-383.796),259035,29)          
           db.actor:give_info_portion("jup_novikov_quest_zaton_scanner_create_7")              
        end
        if has_alife_info("jup_novikov_quest_zaton_scanner_create_7") and (not has_alife_info("jup_novikov_quest_zaton_scanner_have_7")) and db.actor:object("zat_spec_anomaly_scanner_7") then    
           db.actor:give_info_portion("jup_novikov_quest_zaton_scanner_have_7")              
        end
      end    
    end

    Основная особенность скрипта это последовательный спавн квестовых предметов. Последующий будет создаваться только после того как был найден предыдущий. Также происходит выдача инфопоршней используемых в структуре самого квеста. Еще одна особенность это установка дополнительной проверки в зависимости от локации.

    Созданный нами скрипт необходимо обьявить в функции апдейта актора actor_binder:update(delta)в файле bind_stalker.script

    .....
    new_tasks.task_spec()
    .....

    Теперь собственно перейдем к созданию самого задания.
    Код секции квеста ([geonezis_jup_spec_scaner]) можно просмотреть в файле tm_jupiter.ltxв архиве с отработанным примером.
    Основные особенности это наличие двух кондишинов один на завершение задания, второй на его провал (в случае если сквад ученых бункера станет врагами по отношению к ГГ). По завершению задания будет повышена репутация у группировки экологов, а также выдана награда.
    Структура квеста последовательная. Одна секция тайтлов, дескрипшинов и меток заменаяет другую при получении соответсвующих им инфопоршней. Всего 7 таких этапов. Инфопоршни используемые в задании выдаются также последовательно. Определяемыми являются те которые обновляются при спавне (jup_novikov_quest_zaton_scanner_create_№), а не при взятии предмета.

    На этом урок завершен.
    Файл с отработанным заданием можно скачать здесь: http://narod.ru/disk....ar.html

    Изменено пользователем World_Stalker
    • Нравится 2

    - автор модов GA for SGM 1.7, серия "Смерти вопреки".
    - автор уроков квестостроения на X-Ray 1.6
    - работал в командах SGM, Spectrum Project (Путь во Мгле). 

    Ссылка на комментарий

    Создание квеста с добавлением дополнительных внутриэтапных подзаданий. Особенности- отсутствие диалогов, использование рестрикторов. Реализация на X-Ray 1.6

     

    Автор урока: GEONEZIS

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

     

    Само задание следующее: При старте ГГ на ПДА придет сообщение о необходимости установки схронов. Осущесвляется выдача квеста. Необходимо забрать утерянные рюкзаки и заложить их в трех указанных точках. После этого задание автоматически завершается. Выдача награды не предусмотрена.

     

    Необходимые для редактирования файлы:

     

    1. конфигурационные в (gamedata\configs\gameplay\)

    -character_desc_jupiter.xml

    -info_zaton.xml

    2. конфигурационные в (gamedata\configs\misc\)

    - tm_jupiter.ltx

    - quest_items.ltx

    - devices.ltx

    - death_generic.ltx

    3. конфигурационные в (gamedata\configs\text\rus\)

    - st_quests_zaton.xml

    - st_items_quest.xml

    - ui_st_screen.xml

    4. конфигурационные в (gamedata\configs\misc\trade\)

    - trade_generic.ltx

    5. конфигурационные в (gamedata\configs\ui\)

    - game_tutorials.xml

    6. конфигурационные в (gamedata\configs\scripts\zaton\)

    - файлы логик рестрикторов

    7. скриптовый в (gamedata\scripts\)

    - ui_si.script

    - bind_stalker.script

    - new_tasks.script

    - xr_effects.script

    8. all.spawn. (gamedata\spawns\)

    - alife_zaton.ltx

     

    На первоначальном этапе определимся с квестовыми предметами. Всего их шесть. Три будут отвечать за айтем рюкзака до его закладки. Они будут являться потомками основного родительского класса device_pda. Другие три будут определены иным классом, им будет соответствовать установленная логика и они отвечают за рюкзаки после установки схрона. Пропишем секции их конфигов в файле quest_items.ltx (Здесь и далее буду приводить конфиг только одной секции, остальные задаются аналогично только с изменением числовых значений в имени).

    [zat_example_taynik_1_item]:device_pda
    $spawn     = "quest_items\zat_example_taynik_1_item"
    description   = zat_example_taynik_item_descr
    inv_name   = zat_example_taynik_item_name
    visual    = dynamics\devices\dev_rukzak\dev_rukzak.ogf
    inv_weight   = 2
    story_id    = zat_example_taynik_1_item
    can_trade   = false
    quest_item       = true
    inv_grid_width  = 2
    inv_grid_height  = 2
    inv_grid_x      = 0
    inv_grid_y      = 38
    ..........
    [zat_example_taynik_1]:default_inventory_box
    custom_data         = scripts\zaton\inventory_boxs\zat_example_taynik_1.ltx
    ..........

    Первый конфиг не содержит в себе прикрепленного файла в дополнительной секции и определяется как простой квестовый предмет, второй же содержит прикрепленный конфиг с логикой его zat_example_taynik_1.ltx

    Для определении секции zat_example_taynik_1 необходимо определить родительский класс

    default_inventory_box в файле devices.ltx

    [default_inventory_box]
    GroupControlSection    = spawn_group
    discovery_dependency    =
    $spawn    = "devices\default_inventory_box"
    class   = O_INVBOX
    cform   = skeleton
    visual   = dynamics\devices\dev_rukzak\dev_rukzak.ogf
    script_binding          = bind_physic_object.init
    radius                  = 3
    inv_grid_width  = 2
    inv_grid_height  = 2
    inv_grid_x  = 0
    inv_grid_y  = 38
    cost   = 3500
    can_take  = true
    inv_weight  = 1.14
    description  =              
    inv_name  =              
    inv_name_short  =

    В этой секции указываются основные параметры такие как основной класс, форма, визуал.

    Кроме того определим его основную логику в конфигурационном файле zat_example_taynik_1.ltx

    logic]
    active = ph_idle@nothing
    
    [ph_idle@nothing]
    nonscript_usable = true
    tips = st_taynik_check_descr

     

    Здесь указывается активная секция это ph_idle@nothing, а также ее содержание.

    Тайник после установки можно использовать, т.е. возможно его наполнение различными предметами, также при наведении на него будет активна надпись из секции st_taynik_check_descr

     

    Зарегистрируем конфиги первой секции предмета тайник zat_example_taynik_..._item.

    В файле death_generic.ltx пропишем код

    .....
    zat_example_taynik_1_item = true
    zat_example_taynik_2_item = true
    zat_example_taynik_3_item = true

    В файле ui_si.script добавим

    "zat_example_taynik_1_item",
    "zat_example_taynik_2_item",
    "zat_example_taynik_3_item",

     

    Обозначим секции, логику и работу рестрикторов необходимых для выполнения внутренних подквестов.

     

    В файле alife_zaton.ltx обозначим три секции

    [zaton_999999011]
    ; cse_abstract properties
    section_name = space_restrictor
    name = zat_test_quest_restrictor_1
    position = 210.996811,15.980440,480.381104
    direction = 0,0.841602981090546,0
    
    ; cse_alife_object properties
    game_vertex_id = 6
    distance = 0
    level_vertex_id = 1323235
    object_flags = 0xffffff3e
    custom_data = <<END
    
    [story_object]            
    story_id = zat_restr_1_id
    
    [logic]
    cfg = scripts\zaton\zat_restr_logic_1.ltx
    END
    
    ; cse_shape properties
    shapes = shape0            
    shape0:type = box            
    shape0:axis_x = 4,0,0            
    shape0:axis_y = 0,3.13100147247314,0            
    shape0:axis_z = 0,0,2            
    shape0:offset = 0,0,0

    В секции указываются координаты и тип рестрикторов, их идентификатор, имя, тип и размер шейпа.

     

    В файле логики zat_restr_logic_1.ltx пропишем:

     

    [logic]            
    active = sr_idle@start            
    
    [sr_idle@start]            
    on_info  = {+zat_test_quest_rest_main_come =actor_in_zone(zat_test_quest_restrictor_1) =actor_has_item(zat_example_taynik_1_item)} sr_idle@tutorial %=run_tutorial(zat_test_quest_1_tutor)%            
    on_info2 = {+zat_test_quest_restr_1} sr_idle@nil            
    
    [sr_idle@tutorial]            
    on_info   = {+zat_test_quest_rest_main_come !actor_in_zone(zat_test_quest_restrictor_1)} sr_idle@start %=stop_tutorial%            
    on_info2 = {+zat_test_quest_restr_1} sr_idle@nil            
    on_info3 = {!has_active_tutorial} sr_idle@start            
    
    [sr_idle@nil]            

    Отметим особенности:

    Активная секция sr_idle@start переход на вторую происходит по достижению трех условий

    - наличие инфопоршня активности второго этапа основного задания (zat_test_quest_rest_main_come)

    - актор находиться в зоне действия рестриктора

    - наличие в его инвентаре zat_example_taynik_1_item

    При выполнении всех этих условий выполняется работа рестриктора определяемая в туториале zat_test_quest_1_tutor

    При получении инфопоршня zat_test_quest_restr_1 происходит переход в третью нулевую секцию логики рестриктора sr_idle@nil

    При выхода актора из зоны рестриктора его работа прекращается и логика переключается во второе состояние sr_idle@tutorial из которого она может снова перейти в первое или в третье.

     

    Объявим в файле game_tutorials.xml туторы выполняемые в работе рестрикторов

    <zat_test_quest_1_tutor>          
                  <global_wnd/>          
                     <item>          
                         <disabled_key>quit</disabled_key>          
                         <length_sec/>          
                         <action id="use" finalize="1">xr_effects.zat_test_quest_1</action>          
                         <guard_key>use</guard_key>          
                         <grab_input>0</grab_input>          
                             <main_wnd>          
                             <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="graffiti22" r="225" g="225" b="250" a="255" align="c">zat_test_quest_tips</text>          
                             </auto_static>          
                             </main_wnd>          
                     </item>          
                 </zat_test_quest_1_tutor>

    Основные параметры это функция скрипта обработчика действия xr_effects.zat_test_quest_1 и активная надпись из секции zat_test_quest_tips

    В файле xr_effects.scripts определим функции

    function zat_test_quest_1(actor, npc)          
                 if xr_conditions.actor_in_zone(actor, npc, {"zat_test_quest_restrictor_1"})          
                    then                
                    remove_item(actor, npc, {"zat_example_taynik_1_item"})             
                    alife():create("zat_example_taynik_1",vector():set(210.996811,15.980440,480.381104),1323235,6)
                    db.actor:give_info_portion("zat_test_quest_restr_1")             
                 end          
    end

    Опишем ее:

    - если выполнено условие нахождение актора в зоне рестриктора zat_test_quest_restrictor_1

    то происходит удаление из инвентаря ГГ айтема первого конфига тайника zat_example_taynik_1_item, создается по заданным координатам второй zat_example_taynik_1 и выдается инфопоршень zat_test_quest_restr_1

     

    Выдача задания будет происходит при старте ГГ одновременно с квестами основного сюжета. Для этого добавим инфопоршень выдачи и сам квест в секцию логики [sr_idle] оригинального рестриктор zat_b101_logic.ltx

    =give_task(geonezis_zat_test_example_task) +zat_test_quest_begin

    Выдача подквестов будет осуществлять в логике другого рестриктора zat_restr_logic_main.ltx Его секция прописывается в all.spawn по аналогии с предыдущими. Сама логика имеет следующий вид:

    [logic]       
    active = sr_idle@start       
    
    [sr_idle@start]
    on_info = {+zat_test_quest_begin -zat_test_quest_rest_main_come =actor_in_zone(zat_test_quest_restrictor_main)} %=give_task(geonezis_zat_test_example_task_1) =give_task(geonezis_zat_test_example_task_2) =give_task(geonezis_zat_test_example_task_3) +zat_test_quest_rest_main_come%
    on_info2 = {+zat_test_quest_rest_main_come} sr_idle@nil
    
    [sr_idle@nil]

    В активной секции при попадании актора в зону рестриктора происходит выдача внутренних подквестов и переход логики в нулевое состояние.

     

    Определим сам квест с подзаданиями:

    [geonezis_zat_test_example_task]      
    icon = ui_inGame2_Osobiy_zakaz      
    prior = 1      
    storyline = false      
    title = {+zat_test_quest_rest_main_come} zat_test_example_title1, {-zat_test_quest_rest_main_come} zat_test_example_title0      
    descr = {+zat_test_quest_rest_main_come} zat_test_example_text1, {-zat_test_quest_rest_main_come} zat_test_example_text0      
    target ={+zat_test_quest_rest_main_come} nil, {-zat_test_quest_rest_main_come} zat_restr_main_id         
    condlist_0 = {+zat_test_quest_complete} complete      
    on_complete = %=inc_faction_goodwill_to_actor(stalker:50)%

    Подквесты:

    [geonezis_zat_test_example_task_1]
    icon = ui_inGame2_Osobiy_zakaz
    prior = 1
    storyline = false
    title =  zat_test_example_1_title     
    descr =  zat_test_example_123_text     
    target = zat_restr_1_id
    condlist_0 = {+zat_test_quest_restr_1} complete
    on_complete = %=inc_faction_goodwill_to_actor(stalker:50)%

    Особенности:

    - При старте задания необходимо посетить зону основного рестриктора, устанавливается тагет на zat_restr_main_id. В момент посещения активируются подквесты, выдается инфопоршень zat_test_quest_rest_main_come, задание обновляется, его тагет уходит в nill. после взятия всех квестовых айтемов- необходимо завершение всех трех подквестов для получения инфопоршня zat_test_quest_complete

     

    Скриптовая функция которая отвечает за создание трех основных квестовых предметов и выдачу завершающего основное задание инфопоршня прописывается в файл new_tasks.script, и объявляется в апдейте актора файла bind_stalker.script

    new_tasks.task_spec()

    сама функция

    --/Квест Example
    function task_spec()
    local level_name=level.name()
         if level_name=="zaton" then
            if has_alife_info("zat_test_quest_begin") and not has_alife_info("zat_test_quest_spawn_items") then         
               alife():create("zat_example_taynik_1_item",vector():set(248.498016,14.915686,484.567932),1391296,6)
               alife():create("zat_example_taynik_2_item",vector():set(247.778076,14.872326,484.085999),1390040,6)
               alife():create("zat_example_taynik_3_item",vector():set(247.055069,14.796996,483.116058),1388814,6)
            news_manager.send_tip(db.actor, "Чтобы выполнить тестовое задание необходимо установить все тайники. Подбери рюкзаки оставленные сталкерами", nil, nil, 14000)
            db.actor:give_info_portion("zat_test_quest_spawn_items")               
            end
         if has_alife_info("zat_test_quest_restr_1") and has_alife_info("zat_test_quest_restr_2") and has_alife_info("zat_test_quest_restr_3") and     
         not has_alife_info("zat_test_quest_complete") then
            db.actor:give_info_portion("zat_test_quest_complete")
         end
         end
    end

    Описание:

    При нахождении ГГ на локации Затон и наличии инфопоршня zat_test_quest_begin создаются квестовые айтемы и отправляется мессадж на пда ГГ.

    При завершении всех трех подквестов выдается инфопоршень zat_test_quest_complete завершения основного.


    Все инфопоршни необходимые нам пропишем в файле info_zaton.xml

    .....
    <info_portion id="zat_test_quest_restr_1"></info_portion>
    <info_portion id="zat_test_quest_restr_2"></info_portion>
    <info_portion id="zat_test_quest_restr_3"></info_portion>    
    <info_portion id="zat_test_quest_spawn_items"></info_portion>
    <info_portion id="zat_test_quest_begin"></info_portion>
    <info_portion id="zat_test_quest_complete"></info_portion>
    <info_portion id="zat_test_quest_rest_main_come"></info_portion>
    .....

    Всю текстовую транскрипцию определим в соответствующий xml-файлах. Квестовые айтемы тайников можно занести в файлы торговли.

    На этом урок завершен.

    Файл с отработанным задание можно скачать тут: http://narod.ru/disk....ar.html

     

     

     

     

    • Нравится 2

    - автор модов GA for SGM 1.7, серия "Смерти вопреки".
    - автор уроков квестостроения на X-Ray 1.6
    - работал в командах SGM, Spectrum Project (Путь во Мгле). 

    Ссылка на комментарий

    Создание квеста с добавлением дополнительных внутриэтапных заданий. Особенности- отсутствие диалогов, использование физических объектов класса physic_destroyable_object в качестве квестовых предметов. Реализация на X-Ray 1.6

     

    В данном уроке речь пойдет о реализации задания подобного тому что было рассмотрено в предыдущем уроке. В отличие от него теперь добавление внутриэтапных заданий будет завязано не на применение рестрикторов, а на использование физических объектов специального класса. Задание секций этих объектов будет осуществлено также как и в моде SGM (автор GeJorge) Еще одной особенностью будет добавление класса метки объекта (также по аналогии с SGM) что позволит отказаться от применения рестрикторов в определенных моментах. Выдача задания осуществляется при старте игры. Диалогов нет.

     

    Само задание:

     

    ГГ на ПДА приходит сообщение о необходимости обыска трех точек с установленными там объектами. Необходимо выяснить что это за объекты и вернуться в стартовую точку. После этого задание автоматически завершается. Выдача награды не предусмотрена.

     

    Необходимые для редактирования файлы:

     

    1. конфигурационные в (gamedata\configs\gameplay\)

    -info_zaton.xml

    2. конфигурационные в (gamedata\configs\misc\)

    - tm_zaton.ltx

    - quest_items.ltx

    3. конфигурационные в (gamedata\configs\text\rus\)

    - st_quests_zaton.xml

    - ui_st_screen.xml

    4. конфигурационные в (gamedata\configs\models\)

    - dynamic_objects.ltx

    5. конфигурационные в (gamedata\configs\scripts\zaton\)

    - файлы логик рестрикторов и объектов

    6. скриптовый в (gamedata\scripts\)

    - bind_stalker.script

    - new_tasks.script

    7. all.spawn. (gamedata\spawns\)

    - alife_zaton.ltx

    8. физическая модель в (gamedata\meshes\dynamics\box\)

    - konteyner.ogf

     

    Некоторые этапы добавления изменений будут приведены с сокращением, ввиду их схожести с аналогичными в других уроках. Акцент будет сделан на впервые вносимые изменения и аспекты.

     

    Изначально создадим новые классы квестовых предметов.

     

    Класс родительского предмета метка будет соответствовать стандартному квестовому device_pda, но будет иметь визуал "нулевого значения". поэтому при написания квестов и установки тагета в них можно будет воспользоваться именно этим приемом, а не добавлением цели на индивидуальном айди отдельного рестриктора. пропишем в quest_items.ltx секцию

    [quest_spot]:device_pda
    $spawn  = "devices\quest_spot"
    visual    = dynamics\scene_objects\part\part_none.ogf
    can_take = false

     

    сами добавленные метки имеют следующие секции. как видим они являются потомками родительского класса quest_spot. также указывается айди метки по которому будет прописываться таргет story_id.

     

    [zat_test_stalker_container_1_spot]:quest_spot
    story_id = zat_test_stalker_container_1_spot
    
    [zat_test_stalker_container_2_spot]:quest_spot
    story_id = zat_test_stalker_container_2_spot
    
    [zat_test_stalker_container_3_spot]:quest_spot
    story_id = zat_test_stalker_container_3_spot

     

    Новый физический объект используемый нами в квесте объявим в файле dynamic_objects.ltx

    . Он будет иметь свой уникальный класс наследуемый от основного physic_destroyable_object Секции конфигов будут следующими:

     

    [box_quest_item]:physic_destroyable_object
    $spawn                      = "dynamic_objects\box\box_quest_item"
    visual              = dynamics\box\konteyner.ogf
    
    [zat_test_stalker_container_1]:box_quest_item
    custom_data       = scripts\zaton\inventory_boxs\zat_test_stalker_container_1.ltx
    
    [zat_test_stalker_container_2]:box_quest_item
    custom_data       = scripts\zaton\inventory_boxs\zat_test_stalker_container_2.ltx
    
    [zat_test_stalker_container_3]:box_quest_item
    custom_data       = scripts\zaton\inventory_boxs\zat_test_stalker_container_3.ltx

     

    В основной секции указывается физическая модель предмета visual. В уникальных секциях указываются секции конфигов custom_data

     

    Логика добавленных предметов будет задаваться в файлах zat_test_stalker_container_....ltx следующим образом:

     

    [logic]
    active = ph_idle@retranslator_take
    
    [ph_idle@retranslator_take]
    nonscript_usable = false
    tips = st_take_the_quest_item
    on_use = ph_idle@retranslator_heavy %+zat_test_quest_item_1_used%
    on_info = {+zat_test_quest_complete} sr_idle@nil
    
    [ph_idle@retranslator_heavy]
    nonscript_usable = false
    tips = st_quest_item_is_used
    on_info = {+zat_test_quest_complete} sr_idle@nil
    
    [sr_idle@nil]

     

    - активная секция логики ph_idle@retranslator_take

    - первоначальная активная надпись считывается из секции st_take_the_quest_item

    - при юзании предмета произойдет выдача инфопорции zat_test_quest_item_1_used и переход во вторую секцию логики ph_idle@retranslator_heavy

    - при этом изменяется активная надпись на st_quest_item_is_used

    - при получении инфопорции zat_test_quest_complete логика обнуляется.

     

    Теперь необходимо создать основной рестриктор на обход которого будет завязана основа квеста.

     

    Сам рестриктор создаем в all.spawn по аналоги с предыдущими уроками.

    Логика рестриктора из файла zat_restr_logic_main.ltx имеет следующий вид:

     

    [logic]     
    active = sr_idle@start     
    
    [sr_idle@start]
    on_info = {+zat_test_quest_begin -zat_test_quest_rest_main_come =actor_in_zone(zat_test_quest_restrictor_main)} %=give_task(geonezis_zat_test_example_task_1) =give_task(geonezis_zat_test_example_task_2) =give_task(geonezis_zat_test_example_task_3) +zat_test_quest_rest_main_come%
    on_info2 = {+zat_test_quest_rest_main_come} sr_idle@wait
    
    [sr_idle@wait]
    on_info = {+zat_test_quest_all_item_used -zat_test_quest_complete =actor_in_zone(zat_test_quest_restrictor_main)} %+zat_test_quest_complete%
    on_info2 = {+zat_test_quest_complete} sr_idle@nil
    
    [sr_idle@nil]

    разберем ее:

     

    - имеет три секции первая активная, во вторую переходит по совокупности полученных условий при обновлении квеста. - при этом происходит выдача трех подзаданий.

    - для перехода в нулевую секцию необходимо завершение задания.

     

    Выдача задания будет происходит при старте ГГ одновременно с квестами основного сюжета. Для этого добавим инфопоршень выдачи и сам квест в секцию логики [sr_idle] оригинального рестриктор zat_b101_logic.ltx

    =give_task(geonezis_zat_test_example_task) +zat_test_quest_begin    

     

    Определим сам квест с подзаданиями:

     

    основной квест:

    [geonezis_zat_test_example_task]    
    icon = ui_inGame2_Osobiy_zakaz    
    prior = 1    
    storyline = false    
    title = {+zat_test_quest_all_item_used} zat_test_example_title2, {+zat_test_quest_rest_main_come -zat_test_quest_all_item_used} zat_test_example_title1, {-zat_test_quest_rest_main_come} zat_test_example_title0    
    descr = {+zat_test_quest_all_item_used} zat_test_example_text2, {+zat_test_quest_rest_main_come -zat_test_quest_all_item_used} zat_test_example_text1, {-zat_test_quest_rest_main_come} zat_test_example_text0    
    target = {+zat_test_quest_all_item_used} zat_restr_main_id, {+zat_test_quest_rest_main_come -zat_test_quest_all_item_used} nil, {-zat_test_quest_rest_main_come} zat_restr_main_id       
    condlist_0 = {+zat_test_quest_complete} complete    
    on_complete = %=inc_faction_goodwill_to_actor(stalker:50)%

     

    внутренние подквесты (приведен только первый, два других по аналогии):

     

    [geonezis_zat_test_example_task_1]
    icon = ui_inGame2_Osobiy_zakaz    
    prior = 1
    storyline = false
    title =  zat_test_example_1_title0    
    descr =  zat_test_example_1_text0    
    target = zat_test_stalker_container_1_spot
    condlist_0 = {+zat_test_quest_item_1_used} complete

     

    Особенности:

    - При старте задания необходимо посетить зону основного рестриктора, устанавливается тагет на zat_restr_main_id. В момент посещения активируются подквесты, выдается инфопоршень zat_test_quest_rest_main_come, задание обновляется, его тагет уходит в nil. после юзания всех квестовых айтемов созданных в начале объектов проиходит завершение всех трех подквестов, основной квест обновляется снова. чтобы завершить его необходимо снова посетить точку основного рестриктора.

     

    Скриптовая функция которая отвечает за создание трех основных квестовых предметов и выдачу завершающего основное задание инфопоршня прописывается в файл new_tasks.script, и объявляется в апдейте актора файла bind_stalker.script

     

    new_tasks.task_spec()    

     

    сама функция

     

    --/Квест Example
    function task_spec()
    local level_name=level.name()
      if level_name=="zaton" then
         if has_alife_info("zat_test_quest_begin") and not has_alife_info("zat_test_quest_spawn_items") then          
           alife():create("zat_test_stalker_container_1_spot",vector():set(210.996811,15.980440,480.381104),1323235,6)
           alife():create("zat_test_stalker_container_2_spot",vector():set(267.914307,17.374102,483.001709),1424536,6)
           alife():create("zat_test_stalker_container_3_spot",vector():set(305.260254,18.979174,532.515625),1484018,287)      
           news_manager.send_tip(db.actor, "Для начала займи указанную точку", nil, nil, 14000)
           db.actor:give_info_portion("zat_test_quest_spawn_items")              
           end
         if has_alife_info("zat_test_quest_rest_main_come") and not has_alife_info("zat_test_quest_spawn_items_2") then        
           alife():create("zat_test_stalker_container_1",vector():set(210.996811,15.980440,480.381104),1323235,6)
           alife():create("zat_test_stalker_container_2",vector():set(267.914307,17.374102,483.001709),1424536,6)
           alife():create("zat_test_stalker_container_3",vector():set(305.260254,18.979174,532.515625),1484018,287)         
           news_manager.send_tip(db.actor, "Чтобы выполнить тестовое задание необходимо исследовать все контейнеры.", nil, nil, 14000)
           db.actor:give_info_portion("zat_test_quest_spawn_items_2")              
         end
         if has_alife_info("zat_test_quest_item_1_used") and has_alife_info("zat_test_quest_item_2_used") and has_alife_info("zat_test_quest_item_3_used") and    
         not has_alife_info("zat_test_quest_all_item_used") then
         db.actor:give_info_portion("zat_test_quest_all_item_used")
       end
      end
    end

    описание:

    - первоначально по выдаче задания происходит создания меток дополнительных подквестов.

    - при выдачи самих подквестов происходит создание самих предметов необходимых для их выполнения.

    - при наличии трех инфопорций полученных от юзания всех предметов выдается общий инфопоршень на обновление основного задания.

     

    Все инфопоршни необходимые нам пропишем в файле info_zaton.xml

    Всю текстовую транскрипцию определим в xml-файлах.

    На этом урок завершен.

    Файл с отработанным задание можно скачать тут: http://narod.ru/disk....ar.html

     

     

     

    Создание квеста с добавлением дополнительных внутриэтапных заданий. Особенности- отсутствие диалогов, добавление тайников в качестве квестовых предметов. Реализация на X-Ray 1.6

     

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

     

    Необходимые для изменения файлы:

     

    1. конфигурационные в (gamedata\configs\gameplay\)

    -info_zaton.xml

    2. конфигурационные в (gamedata\configs\misc\)

    - tm_zaton.ltx

    - quest_items.ltx

    3. конфигурационные в (gamedata\configs\text\rus\)

    - st_quests_zaton.xml

    4. конфигурационные в (gamedata\configs\scripts\zaton\)

    - файлы логик рестрикторов и объектов

    6. скриптовый в (gamedata\scripts\)

    - bind_stalker.script

    - new_tasks.script

    7. all.spawn. (gamedata\spawns\)

    - alife_zaton.ltx

     

    Определим в файле quest_items.ltx две родительские секции для создания предмета нового класса "квестовый рюкзак".

    [default_inventory_box]
    GroupControlSection    = spawn_group
    discovery_dependency    =
    $spawn    = "devices\default_inventory_box"
    class   = O_INVBOX
    cform   = skeleton
    visual   = dynamics\devices\dev_rukzak\dev_rukzak.ogf
    script_binding          = bind_physic_object.init
    radius                  = 3
    inv_grid_width  = 2
    inv_grid_height  = 2
    inv_grid_x  = 0
    inv_grid_y  = 38
    cost   = 3500
    can_take  = true
    inv_weight  = 1.14
    description  =   
    inv_name  =   
    inv_name_short  =   
    
    [quest_rukzak]:default_inventory_box
    $spawn    = "devices\quest_rukzak"
    visual   = dynamics\devices\dev_rukzak\dev_rukzak.ogf

     

    В дальнейшем нами будет использоваться переопределенный класс quest_rukzak с заданным нами визуалом dynamics\devices\dev_rukzak\dev_rukzak.ogf. В классе default_inventory_box определяются другие основные параметры.

     

    Вся остальная структура добавляемых изменений аналогично указанным ранее. По другом задается только основной квестовый скрипт в файле new_tasks.script

     

    --/Квест Example
    function task_spec()
    local level_name=level.name()
       if level_name=="zaton" then
          if has_alife_info("zat_test_quest_begin") and not has_alife_info("zat_test_quest_spawn_items") then         
             alife():create("zat_test_stalker_container_1_spot",vector():set(210.996811,15.980440,480.381104),1323235,6)
             alife():create("zat_test_stalker_container_2_spot",vector():set(267.914307,17.374102,483.001709),1424536,6)
             alife():create("zat_test_stalker_container_3_spot",vector():set(305.260254,18.979174,532.515625),1484018,287)     
             news_manager.send_tip(db.actor, "Для начала займи указанную точку", nil, nil, 14000)
             db.actor:give_info_portion("zat_test_quest_spawn_items")             
          end
          if has_alife_info("zat_test_quest_rest_main_come") and not has_alife_info("zat_test_quest_spawn_items_2") then       
             local x1_cell=alife():create("quest_rukzak",vector():set(210.996811,15.980440,480.381104),1323235,6)
                    parse_table=utils.parse_spawns("zat_test_quest_item_info_1,af_medusa,wpn_ak74,stalker_outfit,wpn_pm")
                      for k,v in pairs(parse_table) do
                        for i=1,v.prob do
                        alife():create(v.section,vector(),0,0,x1_cell.id)
                      end
             end
             local x2_cell=alife():create("quest_rukzak",vector():set(267.914307,17.374102,483.001709),1424536,6)
                    parse_table=utils.parse_spawns("zat_test_quest_item_info_2,af_ice,wpn_abakan,dolg_outfit,wpn_pm")
                      for k,v in pairs(parse_table) do
                        for i=1,v.prob do
                        alife():create(v.section,vector(),0,0,x2_cell.id)
                      end
             end
             local x3_cell=alife():create("quest_rukzak",vector():set(305.260254,18.979174,532.515625),1484018,287)
                    parse_table=utils.parse_spawns("zat_test_quest_item_info_3,af_fire,wpn_lr300,svoboda_light_outfit,wpn_pm")
                      for k,v in pairs(parse_table) do
                        for i=1,v.prob do
                        alife():create(v.section,vector(),0,0,x3_cell.id)
                      end
             end            
             news_manager.send_tip(db.actor, "Чтобы выполнить тестовое задание необходимо исследовать все тайники.", nil, nil, 14000)
             db.actor:give_info_portion("zat_test_quest_spawn_items_2")             
          end
          if (not has_alife_info("zat_test_quest_item_1_used")) and has_alife_info("zat_test_quest_spawn_items_2") and  db.actor:object("zat_test_quest_item_info_1") then       
            db.actor:give_info_portion("zat_test_quest_item_1_used")       
          end
          if (not has_alife_info("zat_test_quest_item_2_used")) and has_alife_info("zat_test_quest_spawn_items_2") and db.actor:object("zat_test_quest_item_info_2") then       
          db.actor:give_info_portion("zat_test_quest_item_2_used")       
          end
          if (not has_alife_info("zat_test_quest_item_3_used")) and has_alife_info("zat_test_quest_spawn_items_2") and db.actor:object("zat_test_quest_item_info_3") then       
          db.actor:give_info_portion("zat_test_quest_item_3_used")       
          end
          if has_alife_info("zat_test_quest_item_1_used") and has_alife_info("zat_test_quest_item_2_used") and has_alife_info("zat_test_quest_item_3_used") and   
          not has_alife_info("zat_test_quest_all_item_used") then
          db.actor:give_info_portion("zat_test_quest_all_item_used")
          end
     end
    end

    Особенности:

    - при старте задания создаются квестовые метки

    - при достижении позиции актора внутри основного рестриктора происходит создание трех квестовых тайников quest_rukzak по заданным координатам и их заполнение различными предметами.

    - при обыски тайника и взятии ГГ квестового предмета из него происходит выдача инфопоршеней на завершение внутренних подзаданий.

    - после обыска всех трех тайников выдается основной инфопоршень на обновление основного задания.

     

    Файл с отработанным заданием можно скачать тут: http://narod.ru/disk....ar.html

     

     

     

     

    Автор уроков: Geonezis

    • Нравится 1

    - автор модов GA for SGM 1.7, серия "Смерти вопреки".
    - автор уроков квестостроения на X-Ray 1.6
    - работал в командах SGM, Spectrum Project (Путь во Мгле). 

    Ссылка на комментарий

    Создание однотипного квеста на одновременный поиск двух разных предметов. Особенности- использование элементарных скриптовых функций actor_has_item() Реализация на X-Ray 1.6

     

    Итак, предположим нам необходимо создать простой квест для Зова Припяти на одновременный поиск двух различных предметов.

    Пусть идея квеста будет такой: Сыч дает ГГ поручение найти два артефакта Снежинка и Пламя.

     

    Необходимые для редактирования файлы:

    1. конфигурационные в (gamedata\configs\gameplay\)

    -character_desc_zaton.xml

    -dialogs_zaton.xml

    -info_zaton.xml

    -character_desc_general.xml (необязательно)

    2. конфигурационные в (gamedata\configs\misc\)

    - tm_zaton.ltx

    3. конфигурационные в (gamedata\configs\text\rus\)

    - st_dialogs_zaton.xml

    - st_quests_zaton.xml

    4. скриптовый в (gamedata\scripts\)

    - dialogs_zaton.script


    Для начала создадим два простеньких диалога для выдачи и завершения квеста.

     

    В файл dialogs_zaton.xml в самом низу добавим два диалога:

     

    На выдачу квеста:

    <dialog id="zat_b30_owl_stalker_trader_small_quests_begin">             
                 <dont_has_info>zat_b30_owl_stalker_trader_quest_init</dont_has_info>
                 <dont_has_info>zat_b30_owl_stalker_trader_quest_no_quest</dont_has_info>
                 <precondition>dialogs_zaton.zat_b30_owl_stalker_trader_not_have_arts</precondition>
                 <phrase_list>
                         <phrase id="0">
                            <text>zat_b30_owl_stalker_trader_small_quests_0</text>
                            <next>1</next>
                         </phrase>        
                         <phrase id="1">
                            <text>zat_b30_owl_stalker_trader_small_quests_1</text>
                            <next>2</next>
                            <next>3</next>
                         </phrase>
                         <phrase id="2">
                            <text>zat_b30_owl_stalker_trader_small_quests_2</text>
                            <give_info>zat_b30_owl_stalker_trader_quest_no_quest</give_info>
                         </phrase>
                         <phrase id="3">
                            <text>zat_b30_owl_stalker_trader_small_quests_3</text>
                            <action>dialogs_zaton.zat_b30_owl_stalker_trader_give_quest</action>                     
                            <next>4</next>
                          </phrase>
                          <phrase id="4">
                             <text>zat_b30_owl_stalker_trader_small_quests_4</text>
                             <give_info>zat_b30_owl_stalker_trader_quest_init</give_info>                     
                          </phrase>                 
                 </phrase_list>
    </dialog>

     

    На завершение квеста:

     

    <dialog id="zat_b30_owl_stalker_trader_small_quests_end">
                 <has_info>zat_b30_owl_stalker_trader_quest_init</has_info>      
                 <dont_has_info>zat_b30_owl_stalker_trader_quest_end</dont_has_info>
                 <precondition>dialogs_zaton.zat_b30_owl_stalker_trader_have_arts</precondition>       
                 <phrase_list>
                      <phrase id="0">
                             <text>zat_b30_owl_stalker_trader_small_quests_5</text>
                             <give_info>zat_b30_owl_stalker_trader_quest_end</give_info>         
                             <next>1</next>
                       </phrase>
                       <phrase id="1">
                            <text>zat_b30_owl_stalker_trader_small_quests_6</text>         
                            <next>2</next>
                       </phrase>      
                       <phrase id="2">
                            <text>zat_b30_owl_stalker_trader_small_quests_7</text>         
                            <action>dialogs_zaton.zat_b30_owl_stalker_trader_relocates_arts</action>
                            <next>3</next>
                         </phrase>        
                         <phrase id="3">
                            <text>zat_b30_owl_stalker_trader_small_quests_8</text>
                            <action>dialogs_zaton.zat_b30_owl_stalker_trader_relocates_money_to_actor</action>
                            <next>4</next>                         
                         </phrase>
                         <phrase id="4">
                            <text>zat_b30_owl_stalker_trader_small_quests_9</text>
                            <action>dialogs.break_dialog</action>
                         </phrase>                            
                 </phrase_list>
    </dialog>

     

    Пропишем их русскую транскрипцию в файле st_dialogs_zaton.xml

     

    Теперь разберем по порядку то что добавили.

     

    Диалог на выдачу квеста имеет следующую элементарную структуру:

     

    - ГГ предлагают задание и он на выбор может отказаться от него, тогда второй раз диалог уже не будет доступен. Либо же согласиться на исполение.

    - Соответсвенно происходит выдача инфопоршней zat_b30_owl_stalker_trader_quest_init (при старте квеста) и zat_b30_owl_stalker_trader_quest_no_quest (при отказе от выполнения).

    - Наличие в диалоге тегов <dont_has_info>имя поршня</dont_has_info> обеспечивает его блокировку при выборе одной из веток.

    - Наличие прекондишина <precondition>dialogs_zaton.zat_b30_owl_stalker_trader_have_arts</precondition> также блокирует стартовый диалог при наличии квестовых предметов (в данном случае это артефакты) в рюкзаке ГГ.

    - акшион <action>dialogs_zaton.zat_b30_owl_stalker_trader_give_quest</action> обеспечивает выдачу квеста.

     

    поясню особенности второго диалога:

     

    - наличие тега <has_info>zat_b30_owl_stalker_trader_quest_init</has_info> обеспечивает возможность инициализации диалога после выдачи квеста.

    - наличие <dont_has_info>zat_b30_owl_stalker_trader_quest_end</dont_has_info> обеспечивает блокировку диалога после завершение квеста.

    - прекондишн <precondition>dialogs_zaton.zat_b30_owl_stalker_trader_have_arts</precondition> обеспечивает блокирование диалога до момента наличия в инвентаре ГГ нужных квестовых предметов.

    - акшионы <action>dialogs_zaton.zat_b30_owl_stalker_trader_relocates_arts</action> и <action>dialogs_zaton.zat_b30_owl_stalker_trader_relocates_money_to_actor</action> обеспечивают передачу квестовых предметов от ГГ к НПС, и последующего денежного вознаграждения для ГГ от него.

     

     

    Объявим используемые инфопоршни в info_zaton.xml Добавим в конце файла код:

     

    <!-- New quest -->      
          <info_portion id="zat_b30_owl_stalker_trader_quest_no_quest"></info_portion>
          <info_portion id="zat_b30_owl_stalker_trader_quest_init"></info_portion>
          <info_portion id="zat_b30_owl_stalker_trader_quest_end"></info_portion>

     

    Добавим наши диалоги НПС (В данном случае Сычу) для этого в файл character_desc_zaton.xml в его профиль <specific_character id="zat_b30_owl_stalker_trader" team_default="1"> добавим две строки диалогов

     

    .....
          <actor_dialog>zat_b30_owl_stalker_trader_small_quests_begin</actor_dialog>
          <actor_dialog>zat_b30_owl_stalker_trader_small_quests_end</actor_dialog>
    .....

     

     

    С диалогами и инфопоршнями разобрались теперь раccмотрим необходимые скриптовые функции:

     

    В файл dialogs_zaton.script добавим код

    function zat_b30_owl_stalker_trader_give_quest()      
             task_manager.get_task_manager():give_task("geonezis_zat_b30_owl_quest")         
    end
    
    function zat_b30_owl_stalker_trader_have_arts(first_speaker, second_speaker)
          return ((db.actor:object("af_ice") ~= nil) and (db.actor:object("af_fire") ~= nil))
    end
    
    function zat_b30_owl_stalker_trader_not_have_arts(first_speaker, second_speaker)
          return ((db.actor:object("af_ice") == nil) and (db.actor:object("af_fire") == nil))
    end
    
    function zat_b30_owl_stalker_trader_relocates_arts(first_speaker, second_speaker)
          dialogs.relocate_item_section_from_actor(first_speaker, second_speaker, "af_ice")
          dialogs.relocate_item_section_from_actor(first_speaker, second_speaker, "af_fire")
    end      
    
    function zat_b30_owl_stalker_trader_relocates_money_to_actor(first_speaker, second_speaker)
          dialogs.relocate_money_to_actor(first_speaker, second_speaker, 30000)
    end

     

    Теперь по порядку разберем эти функции:

     

    - zat_b30_owl_stalker_trader_give_quest - выдача квеста

    - zat_b30_owl_stalker_trader_have_arts - возвращает true при проверки на наличие в инвентаре ГГ двух необходимвх предметов (в данном случае артефактов af_ice и af_fire)

    - zat_b30_owl_stalker_trader_not_have_arts- возвращает false при аналогичной проверке.

    - zat_b30_owl_stalker_trader_relocates_arts- передача НПС артефактов

    - zat_b30_owl_stalker_trader_relocates_money_to_actor- выдача денежной награды ГГ.


     

    Ну и самое основное это квест.

     

    В файле tm_zaton.ltx прописываем

     

    [geonezis_zat_b30_owl_quest]
    icon = ui_inGame2_Kontrakt_s_uchenimi
    prior = 2
    storyline = false
    title = {=actor_has_item(af_ice) =actor_has_item(af_fire)} zat_b30_owl_stalker_trader_small_quest_title_3, {=actor_has_item(af_ice) !actor_has_item(af_fire)} zat_b30_owl_stalker_trader_small_quest_title_2, {!actor_has_item(af_ice) =actor_has_item(af_fire)} zat_b30_owl_stalker_trader_small_quest_title_1, zat_b30_owl_stalker_trader_small_quest_title_0      
    descr = {=actor_has_item(af_ice) =actor_has_item(af_fire)} zat_b30_owl_stalker_trader_small_quest_text_3, {=actor_has_item(af_ice) !actor_has_item(af_fire)} zat_b30_owl_stalker_trader_small_quest_text_2, {!actor_has_item(af_ice) =actor_has_item(af_fire)} zat_b30_owl_stalker_trader_small_quest_text_1, zat_b30_owl_stalker_trader_small_quest_text_0
    target = {=actor_has_item(af_ice) =actor_has_item(af_fire)} zat_b30_owl_stalker_trader_id, nil
    condlist_0 = {+zat_b30_owl_stalker_trader_quest_end} complete

     

    Разберем то что происходит в процессе выполнения квеста и собственно его структуру.

     

    - [geonezis_zat_b30_owl_quest] - название задение в таск менеджере

    - icon = ui_inGame2_Kontrakt_s_uchenimi - иконка квеста (в данном случае от задания Контракт с Учеными)

    - prior = 2 - приоретет задания

    - storyline = false - сюжеткный ли квест или нет

    - title = - заголовки при обновлении задания

    - descr = - дескрипшины при обновлении задания

    - target = - цели, метки квеста при его обьнавлении.

    - condlist_0 =- кондишн (спец. условия) в квесте (в данном случае один на завершение)

     

    Основная особенность задания это последовательная проверка структурных условий посредством функции actor_has_item(...). Это вызываемая из xr_conditions.script функция на проверку наличия у актора того или иного предмета. Соответсвенно в структуре этого квеста используют два варианта когда значениее функции false (!actor_has_item(...)) и true (=actor_has_item(...))

     

    В квесте рассматриваются все возможные сочетания вариантов наличия или отсутсвия найденного того или иного предмета.

     

    1. когда нет ни одного.

    2. первый (арт снежинка) есть, второго (арт пламя) нет.

    3. первого нет, второй есть

    4. оба есть.

     

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

    По выдачи инфопоршня zat_b30_owl_stalker_trader_quest_end квест будет завершен.

     

    Пропишим рускую транскрипцию дескрипшинов и тайтлов квеста в st_quests_zaton.xml

     

    По желанию для проверки в character_desc_general.xml при старте ГГ пропишем нужный арты.

     

    На этом урок завершен.

    Файл с отработанным заданием можно скачать здесь- http://narod.ru/disk....ar.html

     

     

     

     

    Создание примитивного квеста на поиск двух различных предметов, с выдачей ачивмента.

    Особенности- способ написания задание с его обновлением по инфопорциям, добавление по завершении простого достижения (ачивмента). Реализация на X-Ray 1.6

     

    Поставленная в данном уроке задача схожа с той что была в предыдущем. Основным отличием от него будет являться способ реализации заданий такого типа. Если ранее основным обработчиком на обновление этапов квеста служило использование функций actor_has_item(...), то сейчас последовательное обновление будет осуществляться через выдачу соответствующих инфопорций. Будет подробно рассмотрена структура диалога в котором будет происходить их выдача. Также среди особенностей отметим добавление по завершении задания специального достижения.

     

    Необходимые для редактирования файлы:

     

    1. конфигурационные в (gamedata\configs\gameplay)

    -character_desc_zaton.xml

    -dialogs_zaton.xml

    -info_zaton.xml

    -character_desc_general.xml (необязательно)

    2. конфигурационные в (gamedata\configs\misc\)

    - tm_zaton.ltx

    - achievements.ltx

    3. конфигурационные в (gamedata\configs\text\rus\)

    - st_dialogs_zaton.xml

    - st_quests_zaton.xml

    - st_achievement.xml

    - ui_st_screen.xml

    4. скриптовые в (gamedata\scripts\)

    - dialogs_zaton.script

    - xr_statistic.script

     

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

     

    В файле achievements.ltx в самом низу добавим следующую секцию:

    [sich_helper]
    icon  = ui_inGame2_Iskatel
    hint  = st_sp_achievement_22_hint
    name  = st_sp_achievement_22_name
    desc  = st_sp_achievement_22_descr
    functor  = xr_statistic.sich_helper_functor

     

    -[sich_helper]- уникальное имя секции ачивмента. его же необходимо зарегистрировать в начале файла в списке всех достижений.

    -icon- имя секции иконки достижения. берется из файла ui_actor_achivments.xml (\configs\ui\textures_descr\) в свою очередь сама иконка прописывается в ui_actor_achivments.dds (\textures\ui\) В данном случае возьмем стандартную иконку из другого достижения.

    - hint- описание в ПДА при наведении на ачивку.

    - name- название (имя) достижения.

    - desc- описание самого достижения.

    - functor- имя функции из xr_statistic.script отвечающей за срабатывания условий на получение достижения и собственно его выдача.

     

    Описание русской транскрипции добавим в файл st_achievement.xml

    <string id="st_sp_achievement_22_name">
         <text>Помошник торговца</text>
    </string>
    <string id="st_sp_achievement_22_hint">
         <text>Бандиты стали лучше к Вам относится.</text>
    </string>
    <string id="st_sp_achievement_22_descr">
         <text>Вы нашли и принесли артефакты скряге Сычу. Тем самым Вы заслужили уважение бандитов.</text>
    </string>

    и в ui_st_screen.xml

    <string id="st_ach_sich_helper">
         <text>Получено достижение «Помошник торговца».</text>
    </string>

     

    В xr_statistic.script добавляем исполняемую функцию:

        
    function sich_helper_functor()
        if not has_alife_info("sich_helper_achievement_gained") then
         if has_alife_info("zat_geonezis_example_quest_complete") then
          news_manager.send_tip(db.actor, "st_ach_sich_helper", nil, "seeker", nil, nil)
          xr_effects.inc_faction_goodwill_to_actor(db.actor, nil, {"bandit", 100})
          db.actor:give_info_portion("sich_helper_achievement_gained")
         end
        end
        return has_alife_info("sich_helper_achievement_gained")
    end

     

    более подробно разберем работу данной функции:

    - происходит проверка, а не было ли уже получено данное достижение (отсутствие инфопоршня sich_helper_achievement_gained)

    - срабатывание условия выдачи достижения

    в данном случае условие только одно- это получение инфопоршня zat_geonezis_example_quest_complete (который будет выдаваться по завершению квеста)

    - далее происходит отправка на пда ГГ сообщения с текстом что достижение было получено.

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

    - выдается инфопоршень получения достижения (в рассматриваемом примере это sich_helper_achievement_gained)

     

    Так, теперь приступим к процессу формирования задания.

     

    Опишем подробно только второй диалог, который будет активен после взятия задания.

    Первый, на получения квеста можно будет посмотреть в файле dialogs_zaton.xml имя диалога- jup_azot_sborkiquest_init_dialog

    Соответственно русскую транскрипцию диалогов и квестов также не будем приводить. Ее можно будет увидеть в файлах st_quests_zaton.xml и st_dialogs_zaton.xml

     

    Код второго диалога следующий:

    <dialog id="jup_azot_sborkiquest_find_dialog">    
           <has_info>jup_azot_quest_sborki_give</has_info>    
           <precondition>dialogs_zaton.actor_has_first_or_second_grenader_item</precondition>    
               <phrase_list>
               <phrase id="0">    
                       <text>jup_azot_quest_sborki_find_begin</text>    
                       <next>1</next>
               </phrase>
               <phrase id="1">
                       <text>jup_azot_quest_sborki_find_what</text>
                       <next>11</next>
                       <next>12</next>
                       <next>13</next>
                       <next>14</next>
               </phrase>
               <phrase id="11">     
                       <text>jup_azot_quest_sborki_find_first_item</text>
                       <precondition>dialogs_zaton.if_actor_has_zat_grenader_stalker_flash</precondition>
                       <action>dialogs_zaton.transfer_zat_grenader_stalker_flash</action>
                       <action>dialogs_jupiter.jup_b43_reward_for_first_artefact</action>                   
                       <give_info>jup_azot_quest_sborki1_done</give_info>
                       <next>111</next>
                       <next>112</next>                   
               </phrase>
         <phrase id="111">
                       <text>jup_azot_quest_sborki_find_item_flash</text>                   
                       <dont_has_info>jup_azot_quest_sborki2_done</dont_has_info>
               </phrase>
               <phrase id="112">
                       <text>jup_azot_quest_sborki_find_item_all</text>
                       <has_info>jup_azot_quest_sborki2_done</has_info>
                       <has_info>jup_azot_quest_sborki1_done</has_info>
               </phrase>
               <phrase id="12">     
                       <text>jup_azot_quest_sborki_find_second_item</text>
                       <precondition>dialogs_zaton.if_actor_has_zat_grenader_stalker_gran_instrument</precondition>
                       <action>dialogs_zaton.transfer_zat_grenader_stalker_gran_instrument</action>
                       <action>dialogs_jupiter.jup_b43_reward_for_second_artefact</action>                   
                       <give_info>jup_azot_quest_sborki2_done</give_info>
                       <next>121</next>
                       <next>122</next>                   
               </phrase>
        <phrase id="121">
                       <text>jup_azot_quest_sborki_find_item_instr</text>                   
                       <dont_has_info>jup_azot_quest_sborki1_done</dont_has_info>
               </phrase>
               <phrase id="122">
                       <text>jup_azot_quest_sborki_find_item_all</text>
                       <has_info>jup_azot_quest_sborki2_done</has_info>
                       <has_info>jup_azot_quest_sborki1_done</has_info>
               </phrase>
               <phrase id="13">     
                       <text>jup_azot_quest_sborki_find_first_or_second_item</text>
                       <precondition>dialogs_zaton.actor_has_first_and_second_grenader_item</precondition>
                       <action>dialogs_zaton.transfer_zat_grenader_stalker_flash</action>
                       <action>dialogs_zaton.transfer_zat_grenader_stalker_gran_instrument</action>
                       <action>dialogs_jupiter.jup_b43_reward_for_both_artefacts</action>                   
                       <give_info>jup_azot_quest_sborki1_done</give_info>
                       <give_info>jup_azot_quest_sborki2_done</give_info>
                       <next>131</next>
               </phrase>
         <phrase id="131">
                       <text>jup_azot_quest_sborki_find_end</text>
               </phrase>            
         <phrase id="14">
                       <text>jup_azot_quest_sborki_find_nothing</text>
                       <action>dialogs.break_dialog</action>
               </phrase>                
           </phrase_list>    
           </dialog>

    начнем по-порядку разбирать особенности этого диалога:

     

    - обязательными условиями его активации будет наличие инфопоршня выдачи задания jup_azot_quest_sborki_give, а также функции прекондишина actor_has_first_or_second_grenader_item

    - будет происходить выбор четырех последующих фраз для генерации в зависимости от наличия у ГГ квестовых предметов.

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

    - первая и вторая- когда у ГГ есть один из двух необходимых предметов активны при наличии выполнения соответствующих прекондишинов if_actor_has_zat_grenader_stalker_flash и if_actor_has_zat_grenader_stalker_gran_instrument. при этом проиходит передача этого предмета НПС функции (transfer_....),получении от НПС награды на каждом этапе и выдача инфопорции на обновление задания. первый и второй этапы- взаимоисключающие. одновременно они не могут быть активны.

    - третья- когда у ГГ есть оба необходимых предмета. происходит их передача и завершение квеста.

     

    добавим все скриптовые функции в файл dialogs_zaton.script

    function jup_azot_quest_sborki_give()    
           task_manager.get_task_manager():give_task("geonezis_azot_quest_sborki_give")    
    end    
    
    function zat_b33_relocate_money_to_azot(first_speaker, second_speaker)    
        dialogs.relocate_money_from_actor(first_speaker, second_speaker, 500)    
    end
    
    function actor_has_first_or_second_grenader_item(first_speaker, second_speaker)
        return first_speaker:object("af_baloon") ~= nil or first_speaker:object("af_gold_fish") ~= nil
    end
    
    function actor_has_first_and_second_grenader_item(first_speaker, second_speaker)
        return first_speaker:object("af_baloon") ~= nil and first_speaker:object("af_gold_fish") ~= nil
    end
    
    function if_actor_has_zat_grenader_stalker_flash(first_speaker, second_speaker)
        return first_speaker:object("af_baloon") ~= nil and first_speaker:object("af_gold_fish") == nil    
    end
    
    function if_actor_has_zat_grenader_stalker_gran_instrument(first_speaker, second_speaker)
        return first_speaker:object("af_gold_fish") ~= nil and first_speaker:object("af_baloon") == nil
    end
    
    function transfer_zat_grenader_stalker_flash(first_speaker, second_speaker)
         dialogs.relocate_item_section_from_actor(first_speaker, second_speaker, "af_baloon")
    end
    
    function transfer_zat_grenader_stalker_gran_instrument(first_speaker, second_speaker)
         dialogs.relocate_item_section_from_actor(first_speaker, second_speaker, "af_gold_fish")
    end

    Описывать их нет смысла- они все элементарные.

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

     

    Отметим особенности квеста.

     

    В файле tm_zaton.ltx добавим код задания

     

    --|>
    [geonezis_azot_quest_sborki_give]
    icon = ui_inGame2_Kontrakt_s_uchenimi
    prior = 1    
    storyline = false
    title = {+jup_azot_quest_sborki2_done -jup_azot_quest_sborki1_done} zat_sich_bring_1_name, {+jup_azot_quest_sborki1_done -jup_azot_quest_sborki2_done} zat_sich_bring_2_name, {+jup_azot_quest_sborki1_done +jup_azot_quest_sborki2_done} zat_sich_thanks_for_2_items_name, {-jup_azot_quest_sborki1_done -jup_azot_quest_sborki2_done} zat_sich_sborki_started_name
    descr = {+jup_azot_quest_sborki2_done -jup_azot_quest_sborki1_done} zat_sich_bring_1_text, {+jup_azot_quest_sborki1_done -jup_azot_quest_sborki2_done} zat_sich_bring_2_text, {+jup_azot_quest_sborki1_done +jup_azot_quest_sborki2_done} zat_sich_thanks_for_2_items_text, {-jup_azot_quest_sborki1_done -jup_azot_quest_sborki2_done} zat_sich_sborki_started_text
    target = zat_b30_owl_stalker_trader_id
    condlist_0 = {+jup_azot_quest_sborki1_done +jup_azot_quest_sborki2_done} complete
    condlist_1 = {+jup_azot_quest_sborki_give =is_squad_enemy_to_actor(zat_b30_owl_stalker_trader_squad)} fail    
    on_complete = %+zat_geonezis_example_quest_complete%    
    reward_money = 10000    

     

    Тайтлы и дескрипшины задания будут обновляться после второго разговора с НПС, при получении соответствующих инфопоршней. То есть основное отличие от задания из урока № 33 это его обновление после передачи предметов, а не при их получении и наличии в инвентаре ГГ. По завершении задания будет выдаваться инфопоршень zat_geonezis_example_quest_complete необходимый для выдачи ачивмента, который в свою очередь будет теперь необходим для разблокировки следующего смыслового диалога zat_b30_owl_stalker_trader_buy_info

     

    На этом урок завершен. Скачать пример можно тут: http://narod.ru/disk....ar.html

     

     

     

     

    Автор уроков: Geonezis

     

    Добавлено через 9 мин.:

    Создание сложного квеста с использованием объекта класса inventory_box. Особенности- отсутствие диалогов, использование рестрикторов, выдача тайника в качестве награды. Реализация на X-Ray 1.6

     

    Поставленная задача в данном уроке будет заключаться в обучении основным принципам создания сложного квеста в игре Сталкер Зов Припяти с добавление объекта класса inventory_box. Выдача задания будет осуществляться автоматически, в данном случае зададим ее при старте игры. Также будет показан пример задания сложной логики добавленного объекта и ее возможная привязка в процессе реализации квестов.

     

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

     

    Необходимые для редактирования файлы:

     

    1. конфигурационные в (gamedata\configs\gameplay\)

    -info_zaton.xml

    2. конфигурационные в (gamedata\configs\misc\)

    - tm_zaton.ltx

    - quest_items.ltx

    - secret_zaton.ltx

    3. конфигурационные в (gamedata\configs\text\rus\)

    - st_quests_zaton.xml

    - st_items_quest.xml

    - ui_st_screen.xml

    4. конфигурационные в (gamedata\configs\scripts\zaton\)

    - файлы логик рестрикторов

    5. скриптовый в (gamedata\scripts\)

    - bind_stalker.script

    - new_tasks.script

    6. all.spawn. (gamedata\spawns\)

    - alife_zaton.ltx

     

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

     

    Первоначально создадим новый тайник который будет выдан нам в качестве награды по завершению квеста.

     

    - в файле secret_zaton.ltx добавим тайник в общий список zat_hiding_place_56 и объявим его секцию

    [zat_hiding_place_56]
    wpn_vintorez = 1, 1

    в нем будет находиться один предмет- винторез.

     

    - создадим секцию рестриктора тайника и сам предмет через all.spawn

    [zaton_1867]
    ; cse_abstract properties
    section_name = space_restrictor
    name = zat_hiding_place_56
    position = -443.072845458984,11.5764598846436,-51.894603729248
    direction = 0.000881000014487654,-0.242430001497269,-0.0560249984264374
    ; cse_alife_object properties
    game_vertex_id = 253
    distance = 0
    level_vertex_id = 118142
    object_flags = 0xffffef3e
    custom_data = <<END
    [secret]
    cfg = misc\secret_zaton.ltx
    END
    ; cse_shape properties
    shapes = shape0
    shape0:type = sphere
    shape0:offset = 0,0,0
    shape0:radius = 1
    ; cse_alife_space_restrictor properties
    restrictor_type = 3

    указывается уникальное имя, координаты спанва и файл конфига.

    [zaton_1868]
    ; cse_abstract properties
    section_name = wpn_vintorez
    name = zaton_hiding_wpn_vintorez_1
    position = -443.072845458984,11.5764598846436,-51.894603729248
    direction = -0.0467090010643005,0.650978982448578,1.5079699754715
    ; cse_alife_object properties
    game_vertex_id = 253
    distance = 0
    level_vertex_id = 118142
    object_flags = 0xffffff0f
    custom_data = <<END
    [secret]
    name = zat_hiding_place_56
    END
    ; cse_visual properties
    visual_name = dynamics\weapons\wpn_vintorez\wpn_vintorez
    ; cse_alife_item properties
    condition = 1
    upgrades =               
    ; cse_alife_item_weapon properties
    ammo_current = 90
    upd:condition = 255
    upd:weapon_flags = 0
    upd:ammo_elapsed = 0
    upd:addon_flags = 0
    upd:ammo_type = 0
    upd:weapon_state = 0
    upd:weapon_zoom = 0
    upd:current_fire_mode = 0
    upd:grenade_mode = 0

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

     

    Теперь создадим квестовый объект класса inventory_box

     

    В файле алл спавна alife_zaton.ltx добавим секцию

     

    [zaton_1866]
    ; cse_abstract properties
    section_name = inventory_box
    name = zat_test_container
    position = 415.890075683594,-3.38021898269653,231.797317504883
    direction = 0.000230999998166226,-0.715035021305084,-0.000265999988187104
    
    ; cse_alife_object properties
    game_vertex_id = 7
    distance = 0
    level_vertex_id = 1647866
    object_flags = 0xffffff3f
    custom_data = <<END
    [story_object]
    story_id = zat_test_cont_id
    
    [logic]
    cfg = scripts\zaton\zat_test_conteiner.ltx
    END
    
    ; cse_visual properties
    visual_name = dynamics\equipments\quest\safe_container
    
    ; cse_alife_inventory_box properties
    tip = inventory_box_use

    указывается:

    - класс объекта section_name

    - уникальное имя секции name

    - координаты точки спавна

    - прикрепленный файл логики cfg

    - идентификатор для установления метки таргета квеста story_id

    - визуал модели объекта

    - тип объекта

     

    зададим логику нашего объекта в файле zat_test_conteiner.ltx следующим образом:

    [logic]
    active = ph_idle@full_locked
    
    [ph_idle@full_locked]
    nonscript_usable = false
    tips = zat_test_conteiner_full_locked
    on_info = {=actor_has_item(zat_test_key_1) =actor_has_item(zat_test_key_2)} ph_idle@has_two_key, {=actor_has_item(zat_test_key_1) !actor_has_item(zat_test_key_2)} ph_idle@has_one_key, {=actor_has_item(zat_test_key_2) !actor_has_item(zat_test_key_1)} ph_idle@has_one_key
    on_info2 = {+zat_test_conteiner_open} ph_idle@open, {+zat_test_one_lock_open} ph_idle@locked
    on_use = {!actor_has_item(zat_test_key_2) !actor_has_item(zat_test_key_1)} %+zat_test_quest_find_to_open =spawn_object_in(zat_test_container_item:zat_test_cont_id)%
    
    [ph_idle@has_one_key]
    nonscript_usable = false
    tips = zat_test_conteiner_has_one_key
    on_use = {=actor_has_item(zat_test_key_1) !actor_has_item(zat_test_key_2)} ph_idle@locked %=remove_item(zat_test_key_1) =play_sound(power_switch) +zat_test_one_lock_open%, {=actor_has_item(zat_test_key_2) !actor_has_item(zat_test_key_1)} ph_idle@locked %=remove_item(zat_test_key_2) =play_sound(power_switch) +zat_test_one_lock_open%
    on_info = {=actor_has_item(zat_test_key_1) =actor_has_item(zat_test_key_2)} ph_idle@has_two_key, {!actor_has_item(zat_test_key_2) !actor_has_item(zat_test_key_1)} ph_idle@full_locked
    on_info2 = {+zat_test_conteiner_open} ph_idle@open, {+zat_test_one_lock_open} ph_idle@locked
    
    [ph_idle@locked]
    nonscript_usable = false
    tips = zat_test_conteiner_locked
    on_info = {=actor_has_item(zat_test_key_1) !actor_has_item(zat_test_key_2)} ph_idle@locked_has_second_key, {=actor_has_item(zat_test_key_2) !actor_has_item(zat_test_key_1)} ph_idle@locked_has_second_key
    on_info2 = {+zat_test_conteiner_open} ph_idle@open
    
    [ph_idle@locked_has_second_key]
    nonscript_usable = false
    tips = zat_test_conteiner_has_one_key
    on_use = {=actor_has_item(zat_test_key_1) !actor_has_item(zat_test_key_2)} ph_idle@open %=remove_item(zat_test_key_1) =play_sound(power_switch) +zat_test_conteiner_open%, {=actor_has_item(zat_test_key_2) !actor_has_item(zat_test_key_1)} ph_idle@open %=remove_item(zat_test_key_2) =play_sound(power_switch) +zat_test_conteiner_open%
    on_info = {!actor_has_item(zat_test_key_2) !actor_has_item(zat_test_key_1)} ph_idle@locked
    on_info2 = {+zat_test_conteiner_open} ph_idle@open
    
    [ph_idle@has_two_key]
    nonscript_usable = false
    tips = zat_test_conteiner_has_two_key
    on_use = {=actor_has_item(zat_test_key_1) =actor_has_item(zat_test_key_2)} ph_idle@open %=play_sound(power_switch) =remove_item(zat_test_key_1) =remove_item(zat_test_key_2) +zat_test_conteiner_open%
    on_info = {=actor_has_item(zat_test_key_1) !actor_has_item(zat_test_key_2)} ph_idle@has_one_key, {=actor_has_item(zat_test_key_2) !actor_has_item(zat_test_key_1)} ph_idle@has_one_key, {!actor_has_item(zat_test_key_2) !actor_has_item(zat_test_key_1)} ph_idle@full_locked
    on_info2 = {+zat_test_conteiner_open} ph_idle@open
    
    [ph_idle@open]
    nonscript_usable = true
    tips = zat_test_conteiner_open
    on_info = {-zat_test_conteiner_open} %+zat_test_conteiner_open%

     

    Теперь более подробно ее разберем. имеющийся у нас схрон (предмет с данной логикой) будет иметь 6 секций возможного состояния. Нам необходимо открыть его используя два ключа. Поэтому возможны следующие варианты:

    - ящик закрыт. ph_idle@full_locked

    - использован один из ключей ph_idle@locked

    - у актора есть один из ключей ph_idle@has_one_key

    - у актора есть второй ключ при условии что был уже использован любой из первых. ph_idle@locked_has_second_key

    - у актора сразу есть два ключаph_idle@has_two_key

    - ящик вскрыт.ph_idle@open

     

    Общая конструкция секций логики:

    - состоянии запрета использования обработчика nonscript_usable будет true только в одном случае когда ящик открыт.

    - строка с используемой секции надписи указывается в tips сама транскрипция задается в ui_st_screen.xml

    - вызываемое действие определяется в on_use- происходит переход в одно из последующих состояний и удаление предметов.

    - активное состояние определяется из условий on_info

     

    Теперь по порядку разберем каждую из секций. В принципе сложного в построении такой логике ничего нет, решается обыкновенная комбинаторная задача сочетания двух объектов, когда первый ключ есть, второго нет: наоборот второй есть, первого нет; обо есть; ни одного нет.

     

    - активное состояние ph_idle@full_locked- ящик закрыт.

    изначально необходимо его использовать чтобы произошло обновление квеста (выдача инфопорции +zat_test_quest_find_to_open) и спавн внутрь него необходимого нам предмета (=spawn_object_in(zat_test_container_item:zat_test_cont_id)). это действие возможно только когда ключей у актора нет (!actor_has_item(zat_test_key_2) !actor_has_item(zat_test_key_1)).

    если мы сразу нашли оба ключа (=actor_has_item(zat_test_key_1) =actor_has_item(zat_test_key_2)) то происходит переход в секцию ph_idle@has_two_key

    если у гг есть один ключ, но нет другого (не важно какого) то активируется секция ph_idle@has_one_key

    вторые условия on_info2 следующие:

    при получении инфопорции zat_test_conteiner_open происходит переход в ph_idle@open, соответственно при получении zat_test_one_lock_open становиться активной ph_idle@locked

     

    - у актора есть один из ключей ph_idle@has_one_key

    вне зависимости от того какой из ключей был найден при юзании ящика происходит вскрытие одного замка, переход в секцию ph_idle@locked и выполняются следующие действия %=remove_item(zat_test_key_....) =play_sound(power_switch) +zat_test_one_lock_open%

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

     

    - один из ключей уже использован, второй нет. ph_idle@locked

    это переходная секция юзание ящика при этом невозможно.

    вне зависимости от того какой ключ есть у ГГ (=actor_has_item(zat_test_key_1) !actor_has_item(zat_test_key_2)) или (=actor_has_item(zat_test_key_2) !actor_has_item(zat_test_key_1)) будет осуществлен переход в секцию ph_idle@locked_has_second_key

    дополнительное условие наличие инфопорции zat_test_conteiner_open переход в ph_idle@open

     

    - один из ключей использован, второй в наличии. ph_idle@locked_has_second_key

    при наличии одного из двух ключей =actor_has_item(zat_test_key_...) !actor_has_item(zat_test_key_...) во время юзания происходит переход в секцию ph_idle@open,удаляется один из ключей, проигрывается звук вскрытия, выдается соответствующий инфопоршень.

    основное условие нет ни одного ключа- !actor_has_item(zat_test_key_2) !actor_has_item(zat_test_key_1)происходит переход в состояние ожидания ph_idle@locked

    дополнительное условие аналогично.

     

    - есть оба ключа. ph_idle@has_two_key

    при наличии обоих ключей =actor_has_item(zat_test_key_1) =actor_has_item(zat_test_key_2)

    оба они удаляются. происходит переход в ph_idle@open

    условия при этом- возвращения в необходимые секции когда либо ключей нет, либо есть по одному.

     

    - ключи заюзаны. ph_idle@open

    ящик вскрыт- можно забирать инвентарное содержимое.

     

    Квестовые предметы- ключи (zat_test_key_1, zat_test_key_2) и необходимый для получения из схрона предмет zat_test_container_item добавим в quest_items.ltx

    [zat_test_key_1]:dev_flash_1
    $spawn     = "quest_items\zat_test_key_1"
    visual    = dynamics\equipments\quest\key.ogf
    description   = st_zat_test_key_1_descr
    inv_name   = st_zat_test_key_1
    inv_name_short  = st_zat_test_key_1
    can_trade   = false
    quest_item       = true
    cost    = 0
    inv_grid_width  = 1
    inv_grid_height  = 1
    inv_grid_x   = 4
    inv_grid_y   = 15
    
    [zat_test_key_2]:dev_flash_2
    $spawn     = "quest_items\zat_test_key_2"
    visual    = dynamics\equipments\quest\key.ogf
    description   = st_zat_test_key_2_descr
    inv_name   = st_zat_test_key_2
    inv_name_short  = st_zat_test_key_2
    can_trade   = false
    quest_item       = true
    cost    = 0
    inv_grid_width  = 1
    inv_grid_height  = 1
    inv_grid_x   = 4
    inv_grid_y   = 15
    
    [zat_test_container_item]:device_pda
    $spawn     = "quest_items\zat_test_container_item"
    visual    = dynamics\equipments\quest\notes_document_case_3.ogf
    inv_weight   = 0.05
    inv_grid_width  = 2
    inv_grid_height  = 1
    inv_grid_x   = 18
    inv_grid_y   = 20
    $prefetch    = 16
    description   = st_zat_test_container_item_descr
    inv_name   = st_zat_test_container_item
    inv_name_short  = st_zat_test_container_item
    can_trade   = false
    quest_item       = true
    cost    = 0

     

    Сам квест имеет следующий вид:

    --|>
    [geonezis_test_quest]
    icon = ui_inGame2_Karti_mestnosti
    prior = 1   
    storyline = false
    title = {+zat_test_quest_find_to_open} zat_test_quest_title1, {-zat_test_quest_find_to_open} zat_test_quest_title0
    descr = {+zat_test_quest_find_to_open} zat_test_quest_text1, {-zat_test_quest_find_to_open} zat_test_quest_text0
    target = {+zat_test_quest_find_to_open} zat_test_cont_id, {-zat_test_quest_find_to_open} zat_test_cont_id
    condlist_0 = {=actor_has_item(zat_test_container_item)} complete
    on_complete = %+zat_test_quest_complete%
    ;=give_treasure(zat_hiding_place_31:zat_hiding_place_49

     

    В принципе он элементарный. До первого юзания ящика активна первая секция, после активна секция на поиск ключей. Квест завершается при наличии у ГГ необходимого и взятого из ящика предмета =actor_has_item(zat_test_container_item)

     

    Скрипт на спавн ключей будет иметь следующий вид:

    --/Квест Example
    function task_spec()
    local level_name=level.name()
       if level_name=="zaton" then
        if has_alife_info("zat_test_quest_find_to_open") and not has_alife_info("zat_test_quest_spawn_items") then       
          local rnd_quest_items_1=math.random(1,2)      
          if rnd_quest_items_1==1 then
            alife():create("zat_test_key_1",vector():set(369.470,-5.291,281.921),1579200,67)
            alife():create("zat_test_key_2",vector():set(368.114,-5.228,281.887),1577301,67)
            news_manager.send_tip(db.actor, "Чтобы выполнить тестовое задание необходимо вскрыть заблокированный модуль. Для этого необходимо найти два ключа оставленные в тайниках сталкерами.", nil, nil, 14000)
            db.actor:give_info_portion("zat_test_quest_spawn_items")
            elseif rnd_quest_items_1==2 then
            alife():create("zat_test_key_1",vector():set(366.925,-5.202,281.718),1575412,67)
            alife():create("zat_test_key_2",vector():set(365.569,-5.450,281.175),1573410,67)      
            news_manager.send_tip(db.actor, "Чтобы выполнить тестовое задание необходимо вскрыть заблокированный модуль. Для этого необходимо найти два ключа оставленные в тайниках сталкерами.", nil, nil, 14000)
            db.actor:give_info_portion("zat_test_quest_spawn_items")
            end             
          end
        if has_alife_info("zat_test_quest_complete") and not has_alife_info("zat_test_quest_tainik_give") then
          treasure_manager.get_treasure_manager():give_treasure("zat_hiding_place_56")
          db.actor:give_info_portion("zat_test_quest_tainik_give")
        end
      end
    end

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

     

    Включение квестового скрипта в обработку аналогично как и в других уроках. Выдача самого квеста на старте игры также по аналогии.

    Скачать файл с уроком можно по ссылке http://narod.ru/disk....ar.html

     

     

     

    Автор уроков: Geonezis

    • Нравится 1

    - автор модов GA for SGM 1.7, серия "Смерти вопреки".
    - автор уроков квестостроения на X-Ray 1.6
    - работал в командах SGM, Spectrum Project (Путь во Мгле). 

    Ссылка на комментарий

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

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

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

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

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

    Войти

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

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

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

    AMK-Team.ru

    ×
    ×
    • Создать...