Вступ
Отже, нам раптом захотілося оформити раніше описаний спосіб запуску скриптів. Порившись у текстурах можна підібрати елементи інтерфейсу, що сподобалися. Зараз спробуємо зробити своє вікно з рамкою, відеороликом, що програється, на задньому плані і кількома кнопками.
Спосіб виклику нашого скрипту залишиться колишнім, Esc - F1 , але викликати вікно можна і з діалогів, і за деякою подією, загалом простір для мододелів величезний. Я використовував вже наявні текстури та елементи керування, але ніхто не забороняє використовувати свої. Для рамки я вибрав текстуру ui\ui_dg_inventory , а кнопки брав з ui\ui_common .
Скрипт
Будемо використовувати той самий скрипт ui_cheat.script , але трохи видозмінений. Я наведу його зміст повністю, а потім почнемо його доповнювати.
Початок:
class "cheat" (CUIScriptWnd)
-- инициализируем элементы интерфейса и каллбаки
function cheat:__init(owner) super()
self.owner = owner
self:InitControls()
self:InitCallBacks()
end
function cheat:__finalize()
end
function cheat:InitControls()
-- здесь определяем координаты левого верхнего угла и ширину-высоту
self:Init(50,50,550,450)
-- файл-описатель наших элементов
local xml = CScriptXmlInit()
xml:ParseFile("ui_cheat_wnd.xml")
-- видео на заднем плане
xml:InitStatic("back_video", self)
-- рамка
xml:InitStatic("background", self)
-- кнопки
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")
-- кнопка выхода
self:Register(xml:Init3tButton("btn_quit", self),"btn_quit")
end
function cheat:InitCallBacks()
-- тут интерактивные элементы, при определенном действии выполняется заданная ф-ия
self:AddCallback("btn_1", ui_events.BUTTON_CLICKED, self.cheat1, self)
self:AddCallback("btn_2", ui_events.BUTTON_CLICKED, self.cheat2, self)
self:AddCallback("btn_3", ui_events.BUTTON_CLICKED, self.cheat3, self)
self:AddCallback("btn_quit", ui_events.BUTTON_CLICKED, self.on_quit, self)
end
Тепер на наявні кнопки прикрутимо ф-ії, які будуть щось робити.
function cheat:cheat1()
-- колдуем СВД
self:spawn_item("wpn_svd_m1", 3)
end
function cheat:cheat2()
-- патроны к ней
self:spawn_item("ammo_7.62x54_ap", 3)
end
function cheat:cheat3()
-- и того, кого будем из СВД мучать
self:spawn_item("dog_weak", 30)
end
function cheat:check_game()
-- возвращает true, если запущена игра
local check = false
if level.present() and (db.actor ~= nil) and db.actor:alive() then
check = true
end
return check
end
function cheat:on_quit()
-- убираем наше окно, показываем предыдущее (или возвращаемся в игру)
local console = get_console()
self:GetHolder():start_stop_menu (self.owner, true)
self:GetHolder():start_stop_menu (self,true)
self.owner:Show (true)
-- скрытие главного меню только если запущена игра
if self:check_game() then
console:execute("main_menu off")
end
end
function cheat:spawn_item(spawn_item, dist)
-- спавним только в игре
if self:check_game() then
self:on_quit()
local pos = db.actor:position()
local dir = db.actor:direction()
pos = pos:add(dir:mul(dist))
alife():create(spawn_item, pos, 1, db.actor:game_vertex_id())
end
end
Скриптову частину закінчили. Тепер треба "намалювати" інтерфейс. Інструмент для його створення поки що відсутній (принаймні у нас), тому робитимемо ручками, методом проб та помилок.
XML-описувач
Оскільки ми вже визначили файл, який міститиме розташування елементів ( xml:ParseFile("ui_cheat_wnd.xml") ), то створимо його. Повний шлях до файлу: config\ui\ui_cheat_wnd.xml.
Ось його зміст:
<?xml version="1.0" encoding="windows-1251" ?>
<cheat>
<back_video x="10" y="10" width="380" height="320" stretch="1">
<texture>ui\1_hyuv_sq</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>
<btn_1 x="20" y="30" width="117" height="29">
<texture_e>ui_button_ordinary_e</texture_e>
<text>wpn-svd</text>
</btn_1>
<btn_2 x="20" y="60" width="117" height="29">
<texture_e>ui_button_ordinary_e</texture_e>
<text>Патроны</text>
</btn_2>
<btn_3 x="20" y="90" width="117" height="29">
<texture_e>ui_button_ordinary_e</texture_e>
<text>Собака</text>
</btn_3>
<btn_quit x="270" y="300" width="117" height="29">
<texture_e>ui_button_ordinary_e</texture_e>
<text>ui_inv_exit</text>
</btn_quit>
</cheat>
Занурення
Відео
Розберемо рядково. Оскільки ф-ия cheat:InitControls() спочатку відображає відеоролик (щоб він опинився під усіма елементами, з нього і почнемо).
<back_video x="10" y="10" width="380" height="320" stretch="1">
Назва елемента повинна збігатися з ім'ям, яке є в xml:InitStatic("back_video", self)
x,y - координати лівого верхнього кута щодо оголошеного self:Init
width, height - ширина-висота
stretch="1" - вказує на необхідність розтягування елемента
<texture>ui\1_hyuv_sq</texture>
Використовується відеоролик, який знаходиться за адресою textures\ui\1_hyuv_sq.ogm . Його вихідні розміри – 512х512, тому нам і знадобилося розтягування, точніше так званий стретч.
</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 >
а ось тут посилання на текстуру, що використовується. Ми не стали малювати свою, а взяли вже наявну, тому координати і розміри, що задаються тут, означають, що потрібно взяти текстуру ui\ui_dg_inventory.dds і вирізати з неї потрібний нам шматок. Зверніть увагу, що розміри вирізаної частини та визначені нами не збігаються, замала текстура виявилася, тому довелося її розтягувати;)
</background >
кінець елемент.
Кнопки
<btn_1 x = "20" y = "30" width = "117" height = "29" >
координати, розміри, без розтягування, як і вище. Але тут це означає розміри інтерактивної області. Якщо вказати інші розміри, то кнопка буде реагувати лише у зазначеній зоні. Якщо вказати нульові розміри, то кнопка взагалі не буде інтерактивною.
<texture_e > ui_button_ordinary_e </texture_e >
а ось тут уже цікавіше. не намагайтеся шукати текстуру з ім'ям ui_button_ordinary_e. Вона описана в іншому файлі, config\ui\ui_common.xml . Посилання на цей файл входить до розділу [texture_desc] в system.ltx . Тобто, якщо ви створили свій файл-описувач інтерфейсу, потрібно проставити посилання на цей файл у вищеописаній секції.
<text > wpn-svd </text >
текст на кнопку. Тут також не все так просто. Спочатку гра шукає вираз wpn-svd у файлах заданих у секції [string_table] файлу localization.ltx , тобто залежить від встановленої мови. У цьому випадку посилання на wpn-svd є у файлі config\text\rus\string_table_enc_weapons.xml , і так само
<string id = "wpn-svd" > <text > СВДм 2 </text > </string >
При такому способі встановлення текстового значення ми не залежатимемо від мови гри і зможемо створювати не прив'язані до мови моди.
Якщо подивитися на другу кнопку, то її текстове значення дорівнює
<text > Патрони </text >
Такого значення гра не знайде і просто відобразить як є. Але англомовні користувачі навряд зрозуміють написане. Тому я особисто рекомендую використовувати вже наявні ресурси і мінімально втручатися в ресурси і додавати нові. Але, наприклад, файл з назвами машин ( string_table_enc_vehicles.xml ) не входить до файлу localization.ltx , тому доведеться його туди підключити, або вказати кінцевому користувачеві на необхідність додавання одного рядка до цього файлу.
Ну кнопочка "Вихід" зроблена ось так:
<text > ui_inv_exit </text >
Продовження
Всі. Зберігаємо, запускаємо гру, тиснемо Esc - F1 і бачимо наше віконце. Можна натискати на кнопки і побачити, що вони якісь неінтерактивні. Тобто ніяк не реагують на наведення миші та натискання. Але це легко можна виправити. У грі все для цього є. Достатньо оформити кнопку ось так (приклад для однієї, інші аналогічно):
<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 ui_inv_exit</text>
</btn_quit>
Позначення:
- texture_e – вид кнопки за замовчуванням
- texture_t – вид кнопки при натисканні
- texture_h - вид кнопки при наведенні миші
є ще один стан texture_d , воно означає текстуру вимкненої кнопки. Можна скриптами задавати стан кнопки (ввімкнено-вимкнено), але про це в інший раз.
Вивчайте файл ui_common.xml на предмет інших елементів, там ще багато цікавого.
Увага
Оскільки скрипт спавна змінено порівняно з першою статтею (додано виклик self:on_quit() перед самим спавном), то функцію прив'язки до клавіш слід оформити так:
function cheat:OnKeyboard(dik, keyboard_action)
CUIScriptWnd.OnKeyboard(self,dik,keyboard_action)
if keyboard_action == ui_events.WINDOW_KEY_PRESSED then
-- отсюда убран вызов self:on_quit()
if dik == DIK_keys.DIK_ESCAPE then self:on_quit()
elseif dik == DIK_keys.DIK_NUMPAD1 then self:cheat1()
elseif dik == DIK_keys.DIK_NUMPAD2 then self:cheat2()
elseif dik == DIK_keys.DIK_NUMPAD3 then self:cheat3()
elseif dik == DIK_keys.DIK_NUMPAD4 then self:cheat4()
elseif dik == DIK_keys.DIK_NUMPAD5 then self:cheat5()
elseif dik == DIK_keys.DIK_NUMPAD6 then self:cheat6()
elseif dik == DIK_keys.DIK_NUMPAD7 then self:cheat7()
elseif dik == DIK_keys.DIK_NUMPAD8 then self:cheat8()
elseif dik == DIK_keys.DIK_NUMPAD9 then self:cheat9()
end
end
return true
end