Перейти к контенту
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

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