Ну вот мы и пришли к этой части. Чтобы ее понять конечно необязательно быть скриптером, но если вы совсем ничего о скриптах не знаете, поверьте, будет не легко. Если же вы владеете простыми скриптами, понимаете общую структуру - молодцы. Будет легче. Создаем скрипт ui_gui_elements.script в папке scripts. Я дам вам наполнение файла, там к большинству строк комментарии. Читайте на здоровье. Не ленитесь прочитать еще раз, если не уловили весь смысл. Сразу все ухватить сложно...
Код
class "ui_medkit_ai2" (CUIScriptWnd) --Регистрация нового класса гуи-элемента от существующего класса CUIScriptWnd
function ui_medkit_ai2:__init(owner) super() --Иницилизируем класс, добавляем отсылки к функциям self.owner = owner self:InitControls() --Отсылка к функции регистрации элементов окна self:InitCallBacks() --Отсылка к функции регистрации коллбеков (условий) end
function ui_medkit_ai2:__finalize() --Функция завершения работы нового класса end
function ui_medkit_ai2:OnKeyboard(dik,keyboard_action) --Функция закрытия окна по нажатию на клавиатуре "Escape" CUIScriptWnd.OnKeyboard(self,dik,keyboard_action) --Инициализируем нажатие кнопки на клаве if keyboard_action == ui_events.WINDOW_KEY_PRESSED then --Условие: если нажата кнопка на клаве if dik == DIK_keys.DIK_ESCAPE then --Условие: если нажата конкретно кнопка "Escape" if has_alife_info("gui_medkit_got_cystamine") and has_alife_info("gui_medkit_got_kalium") and has_alife_info("gui_medkit_got_chlor") and has_alife_info("gui_medkit_got_antiemetic") and has_alife_info("gui_medkit_got_sulfad") then self:HideDialog() --То при нажатии на кнопку - закрываем окошко disable_info("gui_medkit_got_cystamine") --И деактивируем обратно инфы, чтобы потом не было глюков disable_info("gui_medkit_got_kalium") disable_info("gui_medkit_got_chlor") disable_info("gui_medkit_got_antiemetic") disable_info("gui_medkit_got_sulfad") else --В любом другом случае self:HideDialog() --При нажатии на кнопку закрытия, закрываем окошко give_object_to_actor("medkit_ai2") --Выдаем обратно аптечку end end end return true end
function ui_medkit_ai2:OnButton_cystamine_clicked() --Функция коллбека кнопки взятия цистамина db.actor:give_info_portion("gui_medkit_got_cystamine") --Инфопорция give_object_to_actor("antirad_cystamine", 6) --Выдаем цистамин self.button_cystamine:Enable(false) --После этих действий кнопка больше не работает end
function ui_medkit_ai2:OnButton_kalium_clicked() --Функция коллбека кнопки взятия калиума db.actor:give_info_portion("gui_medkit_got_kalium") --Инфопорция give_object_to_actor("antirad_kalium") --Выдаем калиум self.button_kalium:Enable(false) --После этих действий кнопка больше не работает end
function ui_medkit_ai2:OnButton_chlor_clicked() --Функция коллбека кнопки взятия хлора db.actor:give_info_portion("gui_medkit_got_chlor") --Инфопорция give_object_to_actor("antibio_chlor", 5) --Выдаем хлор self.button_chlor:Enable(false) --После этих действий кнопка больше не работает end
function ui_medkit_ai2:OnButton_antiemetic_clicked() --Функция коллбека кнопки взятия ПШ db.actor:give_info_portion("gui_medkit_got_antiemetic") --Инфопорция give_object_to_actor("antiemetic", 3) --Выдаем ПШ self.button_antiemetic:Enable(false) --После этих действий кнопка больше не работает end
function ui_medkit_ai2:OnButton_sulfad_clicked() --Функция коллбека кнопки взятия сульфада db.actor:give_info_portion("gui_medkit_got_sulfad") --Инфопорция give_object_to_actor("antibio_sulfad", 5) --Выдаем сульфад self.button_sulfad:Enable(false) --После этих действий кнопка больше не работает end
function ui_medkit_ai2:OnButton_close_clicked() --Функция коллбека кнопки закрытия --Если все медикаменты распакованы: if has_alife_info("gui_medkit_got_cystamine") and has_alife_info("gui_medkit_got_kalium") and has_alife_info("gui_medkit_got_chlor") and has_alife_info("gui_medkit_got_antiemetic") and has_alife_info("gui_medkit_got_sulfad") then self:HideDialog() --То при нажатии на кнопку - закрываем окошко disable_info("gui_medkit_got_cystamine") --И деактивируем обратно инфы, чтобы потом не было глюков disable_info("gui_medkit_got_kalium") disable_info("gui_medkit_got_chlor") disable_info("gui_medkit_got_antiemetic") disable_info("gui_medkit_got_sulfad") else --В любом другом случае self:HideDialog() --При нажатии на кнопку закрытия (в окошке), закрываем окошко give_object_to_actor("medkit_ai2") --Выдаем обратно аптечку end end
function run_ui_medkit_ai2(folder) folder:ShowDialog(true) end
Большинство наполнения - специфическое. Уже в функциях коллбеков встречаются всякие give_info. Что еще рассказать по этой части - не знаю. Ну, разве что, советую внимательно посмотреть на строки в роде:
medkit:caption_chlor означает, что берется элемент caption_chlor из формы medkit. Теперь вернитесь к конфигу гуи. Посмотрите на названия форм. Логично? Такой строкой:
мы еще раз утверждаем (регистрируем) кнопку по id. Все, приступаем к финальной части.
Ну что, последняя часть нашего урока. В первую очередь добавим новые глобальные функции в _g.script:
Код
--Запуск Gui function run_gui(gui, close_inv) if close_inv == true then gui:ShowDialog(true) game_hide_menu() level.show_weapon(false) else gui:ShowDialog(true) end end
-- 'Создание предмета в рюкзаке ГГ. function give_object_to_actor(obj,count) if count==nil then count=1 end for i=1, count do alife():create(obj,db.actor:position(),db.actor:level_vertex_id(),db.actor:game_vertex_id(),db.actor:id()) end end
Функцию give_object_to_actor мы используем при выдаче предметов в гуи. Кто-то скажет, что это бред и можно использовать стандартный alife:create. Но мне так создавать предметы приятней. А вы - как пожелаете. run_gui - запуск гуи. Первый аргумент - скрипт.класс_гуи. Второй аргумент - значение true/false - прятать/не прятать оружие и худ. По умолчанию - не прятать. Теперь создадим скрипт mod_callbacks.script и наполним его так:
Код
function on_use_item(sect) --Переменные (пусть будут на будущее, но можно и удалить) local actor=db.actor local item_name=sect:section() local actor_pos=db.actor:position() local active_slot=db.actor:active_slot() local active_item=db.actor:active_item() local pistol_in_slot=db.actor:item_in_slot(2) local rifle_in_slot=db.actor:item_in_slot(3) local outfit_in_slot=db.actor:item_in_slot(7) local helm_in_slot=db.actor:item_in_slot(12) --Коллбеки if item_name=="medkit_ai2" then --При использовании аптечки run_gui(ui_gui_elements.ui_medkit_ai2()) --Запускаем Gui end end
Откроем bind_stalker.script и в функцию actor_binder:use_inventory_item(obj) перед последним end добавим:
Код
if obj~=nil then mod_callbacks.on_use_item(obj) end
Выйдет вот так:
Код
function actor_binder:use_inventory_item(obj) if(obj) then local s_obj = alife():object(obj:id()) if(s_obj) and (s_obj:section_name()=="drug_anabiotic") then xr_effects.disable_ui_only(db.actor, nil) level.add_cam_effector("camera_effects\\surge_02.anm", 10, false, "bind_stalker.anabiotic_callback") level.add_pp_effector("surge_fade.ppe", 11, false) give_info("anabiotic_in_process") _G.mus_vol = get_console():get_float("snd_volume_music") _G.amb_vol = get_console():get_float("snd_volume_eff") get_console():execute("snd_volume_music 0") get_console():execute("snd_volume_eff 0") end end if obj~=nil then mod_callbacks.on_use_item(obj) end end
Смотрим результат
IP-адрес: Страна: Российская Федерация Город: Москва Дата регистрации: 25.10.2014
Дата: Воскресенье, 29.03.2015, 09:50 | Сообщение # 47
Агро-Разработчик
[ Легенда Зоны ]
Урок 59 Задача: GUI | Создание новой отметки НПС на карте. Подготовка к действу
- Paint Net (редактируем тестуры) - Notepad++ (рекомендую для редактирования текстовых файлов игры)
Практика
Для начала сделаем саму иконку. Все подобные иконки хранятся в текстуре textures/ui/ui_actor_hint_wnd.dds. Давайте и мы в этот раз не отойдем от шаблона. Запускаем Paint Net, который идеально подходит для и открываем данную текстуру. Теперь правее найдем всю эту текстурную группу иконок и выделим любую из "большой подгруппы". Поясню: существует две подгруппы. Это "большая" (для карты) и "маленькая" (для мини-карты на HUD). Лучше начать с большой. Вообщем, выделяем любую "большую" иконку.
Копируем ее, вставляем на новый слой и перемещаем на свободное место:
Теперь, не снимая выделения, запускаем Коррекция-->Оттенок и насыщенность, и перекрасим иконку в красные тона для разнообразия:
Конечно же нам нужно заменить центральную часть иконки на другое изображение, поэтому берем ластик и аккуратно стираем крест по центру:
Следующий шаг - берем инструмент "Текст". Им мы поставим по центру кружочка букву "L". Почему именно ее? Потому что лидер = leader Шрифт, цвет и размер по усмотрению. Я взял "Arial" с размером 8 и цветом, приближенном к цвету кружка:
Хорошо. Дальше нам нужно сделать уменьшенную копию для нашей иконки, чтоб было что поставить на мини-карту. Для этого копируем иконку и вставляем ее в документ с пустым фоном и размером 19x19 px. Просто размер всех "больших" иконок квестовых НПС именно 19x19. Если появится сообщение в роде "Не хватает места для вставленного изображения", игнорируйте, оставляйте как есть, полотно увеличивать не надо. Просто разместите иконку по центру полотна.
Дальше выбираем Изображение-->Изменить размер, и заменяем ширину на 15, а высоту на 14. Копируем уменьшенное изображение, вставляем обратно в текстуру, располагаем где-то рядом с "большой" иконкой. "Маленькая" немного утратила насыщенность. По желанию это можно подправить все тем же инструментом Коррекция-->Оттенок и насыщенность. С самой текстурой все. Но Paint Net не закрываем. Сохраняем текстуру.
Ок, мы прошли творческий этап. Прежде всего берем инструмент "Выделение" (белая стрелочка). Выделяем условный квадратик 19х19 (смотрим размер внизу левее) и перемещаем его к "большой" иконке
Внизу слева появятся координаты x и y. Открываем сразу файл configs/ui/texrures_desc/ui_actor_pda_icons.xml. Там зарегистрированы оригинальные иконки (там указываются координаты по текстуре, где они находятся + им задается уникальный ID; как и во всех файлах texrures_desc). Видим там такое:
Вот так регистрирутся иконки. Разберем элементы регистра. Файл, в котором находятся иконки. В данном случае - ui\ui_actor_hint_wnd.dds. Нам подходит! texture id="ID_иконки" - задается уникальный ID x="6" y="543" width="19" height="19" - координаты, ширина, высота...смотрите детальней в прошлом туторе Итак, у нас есть уже координаты для "большой". Запишем куда-то. Создаем выделением условный квадратик (технически - прямоугольник) 15х14 для "маленькой", снимаем координаты, записываем. Теперь создадим для них секции где-то среди регистра файла:
ui_inGame2_PDA_icon_Stalker_Leader - "большая" ui_inGame2_PDA_icon_Stalker_Leader_small- "маленькая" С регистром визуала метки закончили. Далее нужно регистрировать ее как Gui-элемент. Откроем configs/ui/map_spots.xml. Найдем там вот такое:
На самом деле, эта байда состоит из трех секций. Первая - ui_pda2_leader_location. В ней есть установка:
Код
hint="st_ui_pda_legend_leader"
Это означает, что при наведении на метки, которые указаны в этой секции, будет всплывать текст st_ui_pda_legend_leader. level_map spot указывается секция "большой" метка, которую мы видим далее. Соответственно, в mini_map_spot - секция "маленькой". Вот и сами эти секции:
Тут задается ширина и высота иконок-текстур, пара дополнительных параметров в роде растяжения, выравнивания и прочего. Не вижу смысла здесь долго мусолить Не забудьте - нужно скопировать новые секции и поместить их также в файл map_spots_16.xml. Осталось добавить в configs/text/rus/любой_файл.xml текстовую секцию:
Дата: Воскресенье, 29.03.2015, 09:51 | Сообщение # 48
Агро-Разработчик
[ Легенда Зоны ]
Предпоследняя часть. Нужно добавить секцию ui_pda2_leader_location в scripts/stalker_generic.script. В нескольких местах. В функциях reset_show_spot и remove_level_spot, которые обрабатывают метки. Под этим:
Код
elseif map_spot == "medic" then map_location = "ui_pda2_medic_location" hint = "st_ui_pda_legend_medic"
Этим:
Код
elseif level.map_has_object_spot(npc_id, "ui_pda2_medic_location") ~= 0 then level.map_remove_object_spot(npc_id, "ui_pda2_medic_location")
И этим:
Код
elseif map_spot == "medic" then map_location = "ui_pda2_medic_location"
На самом деле, тут не нужно много думать, если нету на то желания. Шаблон есть? Творческая работа уже была? Вперед, можно и немного "потупить", копипастя секции из скриптов Правда. Говорю как модмейкер с определенным опытом, иногда нужно покайфовать во время работы, не напрягаясь о значении каждой долбанной коммент-черточки в lua-скрипте Но поскольку у меня есть определенные традиции передачи знаний, я сделаю пометки в коде. Замечу, что в каждом случае будем использовать выражение elseif ("если не так, а так..."). Вообщем, вот так выглядят функции:
Код
function reset_show_spot(npc, scheme, st, section) local spot_section if scheme == nil or scheme == "nil" then --Проверка на работоспособность схемы spot_section = utils.cfg_get_string(st.ini, st.section_logic, "show_spot", npc, false, "") else spot_section = utils.cfg_get_string(st.ini, section, "show_spot", npc, false, "") end local map_spot = utils.cfg_get_string(st.ini, st.section_logic, "level_spot", npc, false, "") --Проверка наличия оверрайда в логике if map_spot == nil then --Если нету, то map_spot = utils.cfg_get_string(st.ini, section, "level_spot", npc, false, "") --то оставляем как есть end if map_spot ~= nil then --Если есть, то map_spot = xr_logic.parse_condlist(npc, section, "level_spot", map_spot) --Берем значение из логики НПС map_spot = xr_logic.pick_section_from_condlist(db.actor, npc, map_spot) --Или определяем, что это ГГ (выставляем метку ГГ) end --' printf("STALKER SPOT SECTION [%s]", utils.to_str(spot_section))
if spot_section == nil then --Если наличие метки стоит на "false", то spot_section = "true" --возвращаем наличие метки на "true" end
local spot = "false" -- if character_community(npc) ~= "zombied" then local spot_condlist = xr_logic.parse_condlist(npc, section, "show_spot", spot_section) spot = xr_logic.pick_section_from_condlist(db.actor, npc, spot_condlist) -- end
local sim = alife() if not sim then return end
local obj = sim:object(npc:id()) if obj and obj.online then local npc_id = npc:id() if spot == "false" then -- прячем obj:visible_for_map(false) else -- ставим obj:visible_for_map(true) end if map_spot ~= nil then --Если есть значение, то local map_location = "" local hint = "" if map_spot == "trader" then --Если значение "trader", то map_location = "ui_pda2_trader_location" --Работает секция "ui_pda2_trader_location" hint = "st_ui_pda_legend_trader" --И всплывает при наведении курсора текст "st_ui_pda_legend_trader" elseif map_spot == "mechanic" then --Дальше тому подобное map_location = "ui_pda2_mechanic_location" hint = "st_ui_pda_legend_mechanic" elseif map_spot == "guider" then map_location = "ui_pda2_scout_location" hint = "st_ui_pda_legend_scout" --[[ local smarts_tbl = sim_board.get_sim_board().smarts local npc_smrt_id = obj.m_smart_terrain_id if npc_smrt_id ~= 65535 and npc_smrt_id ~= nil then local npc_smart = smarts_tbl[npc_smrt_id].smrt if npc_smart then local smart_name = smart_names.get_smart_terrain_name(npc_smart) hint = game.translate_string(hint).."\\n"..game.translate_string("st_location").." "..smart_name end end ]] elseif map_spot == "quest_npc" then map_location = "ui_pda2_quest_npc_location" hint = "st_ui_pda_legend_vip" elseif map_spot == "medic" then map_location = "ui_pda2_medic_location" hint = "st_ui_pda_legend_medic" elseif map_spot == "leader" then map_location = "ui_pda2_leader_location" hint = "st_ui_pda_legend_leader" end if level.map_has_object_spot(npc_id, map_location) ~= 0 then level.map_remove_object_spot(npc_id, map_location) end if db.actor and npc and npc:general_goodwill(db.actor) > -1000 then level.map_add_object_spot(npc_id, map_location, hint) end else if level.map_has_object_spot(npc_id, "ui_pda2_trader_location") ~= 0 then --Похожая система, только для убора метки level.map_remove_object_spot(npc_id, "ui_pda2_trader_location") elseif level.map_has_object_spot(npc_id, "ui_pda2_mechanic_location") ~= 0 then level.map_remove_object_spot(npc_id, "ui_pda2_mechanic_location") elseif level.map_has_object_spot(npc_id, "ui_pda2_scout_location") ~= 0 then level.map_remove_object_spot(npc_id, "ui_pda2_scout_location") elseif level.map_has_object_spot(npc_id, "ui_pda2_quest_npc_location") ~= 0 then level.map_remove_object_spot(npc_id, "ui_pda2_quest_npc_location") elseif level.map_has_object_spot(npc_id, "ui_pda2_medic_location") ~= 0 then level.map_remove_object_spot(npc_id, "ui_pda2_medic_location") elseif level.map_has_object_spot(npc_id, "ui_pda2_leader_location") ~= 0 then level.map_remove_object_spot(npc_id, "ui_pda2_leader_location") end end end end
function remove_level_spot(npc, st) local map_spot = utils.cfg_get_string(st.ini, st.section_logic, "level_spot", npc, false, "") --Проверка наличия оверрайда в логике if map_spot == nil then --Если нету, то map_spot = utils.cfg_get_string(st.ini, st.active_section, "level_spot", npc, false, "") --то оставляем как есть end if map_spot ~= nil then --Если есть, то map_spot = xr_logic.parse_condlist(npc, st.active_section, "level_spot", map_spot) --Берем значение из логики НПС map_spot = xr_logic.pick_section_from_condlist(db.actor, npc, map_spot) --Или определяем, что это ГГ (выставляем метку ГГ) end local sim = alife() if not sim then return end
local obj = sim:object(npc:id()) if obj then --Если объект существует local npc_id = npc:id() --Локальная переменная "obj" if map_spot ~= "" and map_spot ~= nil then --Начинаем перечислять "Если значение...", если в значении вообще что-то есть local map_location = "" --Локальная переменная "map_location" = "выставляемое значение" if map_spot == "trader" then --Если значение оверрайда - "trader", то map_location = "ui_pda2_trader_location" --то убирается секция "ui_pda2_trader_location" elseif map_spot == "mechanic" then --Если "mechanik", то map_location = "ui_pda2_mechanic_location" --то секция "ui_pda2_mechanic_location" elseif map_spot == "guider" then --И так далее... map_location = "ui_pda2_scout_location" elseif map_spot == "quest_npc" then map_location = "ui_pda2_quest_npc_location" elseif map_spot == "medic" then map_location = "ui_pda2_medic_location" elseif map_spot == "leader" then map_location = "ui_pda2_leader_location" end if level.map_has_object_spot(npc_id, map_location) ~= 0 then level.map_remove_object_spot(npc_id, map_location) --Убираем метку end end end end
Вот и все. Последний шаг. Откроем логику любого нужного НПС, и пропишем в секции [logic] такое:
Код
show_spot = leader ;Значение "leader" мы зарегистрировали в скрипте
IP-адрес: Страна: Российская Федерация Город: Москва Дата регистрации: 25.10.2014
Урок 60 Задача: 3D моделирование | "Maya: вандализм или проламывание стены."
[ Для новичков ]
[ «Лофтим» эскиз дыры ]
Для начала нам нужно создать кривую для этого нам нужно перейти на полку Curves. На этой полке выбираем инструмент PencilCurve Tool.
Выбрав данный инструмент курсор изменится со стрелочки на карандаш. После нужно зажать клавишу x (привязка к сетки) нарисовать кривую окружность.
Дальше нам нужно создать копию данной кривой для этого выделяем нашу линию и жмём Ctrl + D (если нечего не произошло, то проверьте раскладку клавиатуры, а так же посмотрите, не включен ли у вас Caps Lock). После чего выделяем одну из кривой и переключаемся на инструмент move
(или клавиша W). Дальше с помощь появившегося контролера тянем одну из кривых наверх
Теперь переходим к самому интересному, создадим из этих двух кривых полигонную модель. Для этого выделяем обе кривые и жмём F4 (переключаемся на инструменты для работы со сплайтами и кривыми) после выбираем в панели главного меню (там где file, edit и т.д) кнопку Surfaces у нас «выкатится меню» и рядом с надписью Loft жмём на кубик. У нас появится окно под название Loft Options устанавливаем параметры как на скрииншоте который приведён ниже.
И жмём на кнопку "Loft" после чего у нас должно получится что-то вроде этого.
[ Само проламывание стены. ]
Теперь нам надо подогнать и отмасштабировать получившийся эскиз.
Ну и наконец, кульминация создаём отверстие для этого жмём на F3 после выделим нашу модель (в моём случай это забор) после наш эскиз. И применим к ним команду Mesh --> Booleans --> Difference (на название команды, а не на кубик.) В итоге мы получаем красивый пролом в стене, останется только положить на него X-Ray шейдер и затекстурировать.
Урок 61 Задача: 3D моделирование | "Maya: " Эксперименты над людьми или перенос модели из Сталкер Чень Чернобыля в Сталкер Чистое Небо и Сталкер Зов Припять без потери «весов»."
[ Часть первая подготовка модели ]
Для начала нам нужно импортировать (никоем случи не открыть!) модель которую мы будем переносить. (думаю мне не надо подробно разъяснять как экспортировать модель.) Теперь нам нужно её подготовить для жмём на две кнопки, которые показаны на скриншоте ниже.
Теперь нам нужно удалить старый character для этого нам нужно нажать на главной пенели window --> Outliner или так смотрим скриншот.
Теперь жмём на «синего человечка» (если он у вас не появился, то нужно в окне Outliner – ра нажать Show --> Show All) и нажимаем клавишу Delete. Всем модель подготовлена.
[ Создаём новые кости ]
Теперь нам надо создать и добавить к скелету две недостающие кости для этого переходим на полку Animation и там выбираем инструмент Joint Tool
Вместо курсора у нас появится прицел теперь зажав клавишу Х (привязка к сетке) жмем на сетку между ног нашей модели примерно так.
Теперь отпускаем клавишу Х и зажимаем V (привязка к вершинам в нашем случай к джоинтам (суставам) поэтому мы и отключили меш в самом начале)
Теперь нам осталось соединить два скелета для этого выделяем кость bip01_pelvis и joint1(выбираем первую кость зажимаем Сtrl и жмём на вторую кость. Именно так если сначала мы выберем joint1 а только потом bip01_pelvis то в СДК у нас будет вылет! ) после чего выполняем команду connect Joint
Кстати кости удобнее выбирать в окне Outliner. Теперь переименовываем кость joint1 в root_stalker а joint2 в bip01 для этого в окне Outliner – ра дважды жмем на надпись joint1 после вводим нужное название и нажимаем интер (именно интер иначе новое имя не сохранится) Теперь опять выделяем кость bip01_pelvis (всё в том же Outliner -ре) зажимаем колёсико мыши и тянем на кость bip01 в итоге у нас кость bip01_pelvis должна пропасть а слева от кости bip01 появится +. Все иерархия скелета восстановлена. Всё модель перенесена осталось её толь экспорировать.
[ Скрин Дока ]
Как видно я тут с бампом накосяцил :)
IP-адрес: Страна: Российская Федерация Город: Москва Дата регистрации: 25.10.2014
Первое: Создаём "болванку" скрипта в файле xr_effects.script Пусть функция будет называться create_helicopter В качестве аргумента передаём секцию пути, указанную в all.spawn, на которой будет создан вертолёт, эта же секция пути будет использована в логике вертолёта, как точка, над которой вертолёт будет "висеть"
Код
function create_helicopter( actor, obj, p ) if p and p[ 1 ] then --проверяем, что секция пути в функцию передана --проверяем, есть ли такая секция в all.spawn if not level.patrol_path_exists( p[ 1 ] ) then --если нет, то вылетаем на рабочий стол abort("Path %s doesnt exist. Function 'create_helicopter'", tostring( p[ 1 ] ) ) end local ptr = patrol( p[ 1 ] ) local position = ptr:point( 0 ) -- получаем позицию ( вектор ) точки спавна local lv_id = ptr:level_vertex_id( 0 ) -- получаем левел вертекс точки спавна local gv_id = ptr:game_vertex_id( 0 ) -- получаем гейм вертекс точки спавна local section = "helicopter" -- секцию берём из gamedata\configs\creatures\helicopter.ltx --создаём серверный объект вертолёта local s_obj = alife():create( section, position, lv_id, gv_id ) end end
Теперь подготовим логику вертолёта. Пусть вертолёт будет просто висеть на месте и нос вертолёта всегда будет направлен в сторону игрока. Запретим вертолёту стрелять ракетами и стрелять из пулемёта.
Теперь добавим логику в нашу функцию Наша функция теперь будет выглядеть так
Код
function create_helicopter( actor, obj, p ) if p and p[ 1 ] then --проверяем, что секция пути в функцию передана if not level.patrol_path_exists( p[ 1 ] ) then --проверяем есть ли такая секция в all.spawn --если нет, то вылетаем на рабочий стол abort("Path %s doesnt exist. Function 'create_helicopter'", tostring( p[ 1 ] ) ) end local logic_helicopter = "[logic]\n".. "active = heli_move@idle\n".. "[heli_move@idle]\n".. "path_move = "..tostring( p[ 1 ] ).."\n".. "path_look = actor\n".. "invulnerable = true\n".. "max_velocity = 50\n".. "enemy = nil\n".. "immortal = true\n".. "use_rocket = false\n".. "use_mgun = false\n".. "upd_vis = 3\n".. "engine_sound = true\n" local ptr = patrol( p[ 1 ] ) local position = ptr:point( 0 ) -- получаем позицию ( вектор ) точки спавна local lv_id = ptr:level_vertex_id( 0 ) -- получаем левел вертекс точки спавна local gv_id = ptr:game_vertex_id( 0 ) -- получаем гейм вертекс точки спавна local section = "helicopter" -- секцию берём из gamedata\configs\creatures\helicopter.ltx local s_obj = alife():create( section, position, lv_id, gv_id ) --создаём серверный объект вертолёта end end
Если всё оставить, как есть, то при вызове функции получим вылет на рабочий стол. Это связано с тем, что для "правильного" спавна вертолёта не хватает исходных данных.
Эти данные необходимо добавить в STATE часть нет-пакета вертолёта. Для этого сначала мы прочитаем нет-пакет вертолёта. Делается это так:
Код
local packet = net_packet() --берём пустой нет-пакет packet:w_begin( 0 ) -- указатель на начало записи s_obj:STATE_Write( packet ) -- пишем STATE часть нет-пакета вертолёта в наш пустой нет-пакет packet:r_seek( 2 ) -- начинаем читать наш пакет local game_vertex_id = packet:r_u16() local distance = packet:r_float() local direct_control = packet:r_s32() local level_vertex_id = packet:r_s32() local object_flags = packet:r_s32() local custom_data = packet:r_stringZ() local story_id = packet:r_s32() local spawn_story_id = packet:r_s32() local visual_name = packet:r_stringZ() local visual_flags = packet:r_u8() local motion_name = packet:r_stringZ() local skeleton_name = packet:r_stringZ() local skeleton_flags = packet:r_u8() local source_id = packet:r_u16() local startup_animation = packet:r_stringZ() local engine_sound = packet:r_stringZ()
Добавим этот код в нашу функцию Получим
Код
function create_helicopter( actor, obj, p ) if p and p[ 1 ] then --проверяем, что секция пути в функцию передана if not level.patrol_path_exists( p[ 1 ] ) then --проверяем есть ли такая секция в all.spawn --если нет, то вылетаем на рабочий стол abort("Path %s doesnt exist. Function 'create_helicopter'", tostring( p[ 1 ] ) ) end local logic_helicopter = "[logic]\n".. "active = heli_move@idle\n".. "[heli_move@idle]\n".. "path_move = "..tostring( p[ 1 ] ).."\n".. "path_look = actor\n".. "invulnerable = true\n".. "max_velocity = 50\n".. "enemy = nil\n".. "immortal = true\n".. "use_rocket = false\n".. "use_mgun = false\n".. "upd_vis = 3\n".. "engine_sound = true\n" local ptr = patrol( p[ 1 ] ) local position = ptr:point( 0 ) -- получаем позицию ( вектор ) точки спавна local lv_id = ptr:level_vertex_id( 0 ) -- получаем левел вертекс точки спавна local gv_id = ptr:game_vertex_id( 0 ) -- получаем гейм вертекс точки спавна local section = "helicopter" -- секцию берём из gamedata\configs\creatures\helicopter.ltx local s_obj = alife():create( section, position, lv_id, gv_id ) --создаём серверный объект вертолёта local packet = net_packet() --берём пустой нет-пакет packet:w_begin( 0 ) -- начинаем запись с нулевого байта s_obj:STATE_Write( packet ) -- пишем STATE часть нет-пакета вертолёта в наш пустой нет-пакет packet:r_seek( 2 ) -- начинаем читать наш пакет local game_vertex_id = packet:r_u16() local distance = packet:r_float() local direct_control = packet:r_s32() local level_vertex_id = packet:r_s32() local object_flags = packet:r_s32() local custom_data = packet:r_stringZ() local story_id = packet:r_s32() local spawn_story_id = packet:r_s32() local visual_name = packet:r_stringZ() local visual_flags = packet:r_u8() local motion_name = packet:r_stringZ() local skeleton_name = packet:r_stringZ() local skeleton_flags = packet:r_u8() local source_id = packet:r_u16() local startup_animation = packet:r_stringZ() local engine_sound = packet:r_stringZ() end end
Теперь нам нужно изменить некоторые значения, хранящиеся в нет пакете, чтобы наш вертолёт "заработал". Добавляем логику, параметры движения и анимации, звук, визуал вертолёта.
Мы использовали логику logic_helicopter, которая сразу записана в нашей функции. Если мы хотим "вынести" нашу логику в отдельный файл, то в нашей функции нужно прописать путь к файлу, в котором будет записана логика нашего вертолёта. Например логика находится в файле logic_helicopter.ltx, тогда в функцию пишем путь до файла.
Код
local logic_helicopter = "[logic]\ncfg = scripts\\zaton\\logic_helicopter.ltx"
Добавим наши изменения в функцию и запишем их в нет-пакет вертолёта
Код
function create_helicopter( actor, obj, p ) if p and p[ 1 ] then --проверяем, что секция пути в функцию передана if not level.patrol_path_exists( p[ 1 ] ) then --проверяем есть ли такая секция в all.spawn --если нет, то вылетаем на рабочий стол abort("Path %s doesnt exist. Function 'create_helicopter'", tostring( p[ 1 ] ) ) end local logic_helicopter = "[logic]\n".. "active = heli_move@idle\n".. "[heli_move@idle]\n".. "path_move = "..tostring( p[ 1 ] ).."\n".. "path_look = actor\n".. "invulnerable = true\n".. "max_velocity = 50\n".. "enemy = nil\n".. "immortal = true\n".. "use_rocket = false\n".. "use_mgun = false\n".. "upd_vis = 3\n".. "engine_sound = true\n" local ptr = patrol( p[ 1 ] ) local position = ptr:point( 0 ) -- получаем позицию ( вектор ) точки спавна local lv_id = ptr:level_vertex_id( 0 ) -- получаем левел вертекс точки спавна local gv_id = ptr:game_vertex_id( 0 ) -- получаем гейм вертекс точки спавна local section = "helicopter" -- секцию берём из gamedata\configs\creatures\helicopter.ltx local s_obj = alife():create( section, position, lv_id, gv_id ) --создаём серверный объект вертолёта local packet = net_packet() --берём пустой нет-пакет packet:w_begin( 0 ) -- указатель записи -- пишем STATE часть нет-пакета вертолёта в наш пустой нет-пакет s_obj:STATE_Write( packet ) packet:r_seek( 2 ) -- начинаем читать наш пакет local game_vertex_id = packet:r_u16() local distance = packet:r_float() local direct_control = packet:r_s32() local level_vertex_id = packet:r_s32() local object_flags = packet:r_s32() local custom_data = packet:r_stringZ() local story_id = packet:r_s32() local spawn_story_id = packet:r_s32() local visual_name = packet:r_stringZ() local visual_flags = packet:r_u8() local motion_name = packet:r_stringZ() local skeleton_name = packet:r_stringZ() local skeleton_flags = packet:r_u8() local source_id = packet:r_u16() local startup_animation = packet:r_stringZ() local engine_sound = packet:r_stringZ() -- меняем параметры, прочитанные из нет-пакета custom_data = logic_helicopter motion_name = "idle" skeleton_name = "idle" startup_animation = "idle" visual_name = "dynamics\\vehicles\\mi24\\veh_mi24_u_01" engine_sound = "vehicles\\helicopter\\helicopter" -- начинаем писать в наш пакет изменённые параметры packet:w_begin( 0 ) packet:w_u16( game_vertex_id ) packet:w_float( distance ) packet:w_s32( direct_control ) packet:w_s32( level_vertex_id ) packet:w_s32( object_flags ) packet:w_stringZ( custom_data ) packet:w_s32( story_id ) packet:w_s32( spawn_story_id ) packet:w_stringZ( visual_name ) packet:w_u8( visual_flags ) packet:w_stringZ( motion_name ) packet:w_stringZ( skeleton_name ) packet:w_u8( skeleton_flags ) packet:w_u16( source_id ) packet:w_stringZ( startup_animation ) packet:w_stringZ( engine_sound ) packet:r_seek( 2 ) -- пишем STATE часть из нашего нет-пакета в нет-пакет вертолёта s_obj:STATE_Read( packet, packet:w_tell() ) end end
Теперь мы хотим увидеть наш вертолёт в игре. Сделаем это для оригинально ЗП. Создадим в корневой папке игры папку gamedata В папке gamedata создадим две папки configs и scripts В папке configs создадим папку scripts, а в ней папку zaton Из распакованных ресурсов игры возьмём файл xr_effects.script и поместим его в папку gamedata\scripts В сам файл в самый его конец запишем нашу функцию. Теперь возьмём файл gamedata\configs\scripts\zaton\zat_a1_logic.ltx из ресурсов игры и поместим его в нашу папку. Путь тот же gamedata\configs\scripts\zaton\ Откроем файл zat_a1_logic.ltx и вместо строчки on_info = sr_idle@timer %+zat_a1_game_start% напишем on_info = sr_idle@timer %+zat_a1_game_start =create_helicopter(zat_sim_15_spawn_for_a1)%
Мы добавили выполнение нашей функции в логику рестриктора, которая работает при старте игры. В качестве точки спавна мы использовали точку спавна сталкеров, которые появляются в самом начале игры и идут навстречу игроку. Запускаем ЗП, начинаем новую игру и, если сделали всё правильно, то слышим звук вертолёта, а, пробежав, метров 100 вперёд уже видим его.
IP-адрес: Страна: Российская Федерация Город: Москва Дата регистрации: 25.10.2014
Урок 63 Задача: Вызов различных функций или визуальных эффектов при использовании бустеров без использования проверок на секцию ( if_then_elseif ).
Задача: сделать, чтобы при использовании предмета срабатывал колбэк, которой жёстко привязан к этому предмету. В качестве предметов, к которым привяжем колбэк возьмём три аптечки. Секции аптечек: [medkit], [medkit_army], [medkit_scientic]
В файл bind_stalker.script в метод function actor_binder:use_inventory_item(obj) пишем
xr_s.use_inventory_item( obj:section() ) -- здесь мы вызываем колбэк
Теперь открываем файл xr_s.script и в таблицу callbacks допишем следующее
Теперь добавляем две функции регистрирующие колбэк и удаляющие колбэк.
Код
function reg_use_inv_item_callback( name, sect, func, userobj ) callbacks[name][sect][func]={userobj=userobj} end
function unreg_use_inv_item_callback( name, sect, func ) callbacks[name][sect][func]=nil end
И сама функция, которая обрабатывает колбэк.
Код
function use_inventory_item( section ) if callbacks.use_inventory_item[section] == nil then return end for func,o in pairs( callbacks.use_inventory_item[section] ) do func( section, o.userobj ) end end
Пусть наши функции-колбэки хранятся в файле use_item_callbacks.script Добавим наш файл в функцию init()
Код
function init() init_module_if_exists("use_item_callbacks") end
Теперь переходим к файлу use_item_callbacks.script В нём пишем функцию регистации колбэка и саму функцию, которая будет выполнена при вызове
function medkit( section ) -- здесь мы обрабатываем событие - использование аптечки end function medkit_army( section ) -- здесь мы обрабатываем событие - использование армейской аптечки end function medkit_scientic( section ) -- здесь мы обрабатываем событие - использование научной аптечки end
В этот файл по аналогии можно впихнуть хоть все бустеры в игре и прописать их по аналогии в xr_s.script в таблицу callbacks, тогда при использовании каждого бустера будет вызываться функция , которая жёстко привязана к этому предмету.
Всё тоже можно сделать и для on_drop_item и для on_take_item
Как видите никаких проверок по секциям if_then_elseif не проводится. Секция предмета - это название функции, которая сразу же вызывается при использовании бустера.
IP-адрес: Страна: Российская Федерация Город: Москва Дата регистрации: 25.10.2014
Всем привет. Пожалуй, есть вопросы по модостроению, которые мучили меня месяцами. Один из них - список доступных для использования игровых шрифтов. Некоторые ресурсы в гугле предлагают открыть файл configs/fonts.ltx, но я так и не понял, каким образом эта вещь читается движком: названия "фонтов" не совпадают с тем, что используются в интерфейсе. Итого, данный вопрос будет пока что раскрыт наполовину. Тем не менее, благодаря исходникам движка 1.6.02, мне удалось докопаться до того самого места, где "регистрируются" реально работающие шрифты! Предлагаю ознакомиться с этим небольшим справочником
Регистрация шрифтов
Собственно, "регистрация" шрифтов проходит в файле UIXmlInit.cpp. Строки 29-43 содержат определение переменных для большой части названий шрифтов (чуть ниже мы увидим, как эти переменные используются):
Урок 67 Задача: Действие на рандомной позиции эксклюзивного НПС
Поясню: иногда нужно просчитать позицию эксклюзивного НПС со своей логикой (кстати, мутанты сюда тоже входят), чтобы потом по данным координатам запустить скриптовое действие. К примеру, по определенному условию мы создаем на позиции НПС оружие. Хорошо, если мы знаем, что НПС стоит на одном месте со схемой "remark" или "walker". А если он может передвигаться по вейпоинтам или по alife-сигналам в роде замеченого трупа или противника? Тут уже нужно логически-скриптово просчитать позицию нашего НПС.
Логика
Вызываем функцию непосредственно из логики самого объекта:
%=test_position_spawn%
Скриптовая часть
Функции, разумеется, пишем в xr_effects.script
Для НПС и мутантов:
Код
function test_position_spawn(actor, npc) local spawn_place = npc:position() alife():create("wpn_abakan", spawn_place) end
Для физических объектов:
Код
function test_position_spawn(actor, npc) local obj = get_story_object("story_id_предмета") alife():create("wpn_abakan", obj:position()) end
Пояснения: Как видите, здесь мы используем оборот-функцию position() В первом случае - скриптовое выражение "npc:position()", которое используется исключительно для НПС и мобов, передаем выражение через локальную переменную "spawn_place". Во втором - мы берем story_id физического объекта через глобальную функцию "get_story_object", передаем это через локальную переменную "obj" (можно и другую взять, а можно и без переменной обойтись), приписываем к ":position()". В обоих случаях выражения заменяют инициализацию координат x,y,z,lvid,gvid.
IP-адрес: Страна: Российская Федерация Город: Москва Дата регистрации: 25.10.2014
1. Откроем в Paint.net файл ui_actor_newsmanager_icons.dds, он лежит по пути gamedata\textures\ui Там видим все иконки заданий и достижений, которые используются в игре
Под иконкой "Особого заказа" рисуем свою иконку
Далее выделяем иконку с помощью "выделить прямоугольную область
И в самом низу будут координаты и размер иконки. Далее сохраняем файл и идем дальше. 2. В файле ui_actor_newsmanager_icons.xml по пути gamedata\configs\ui\textures_descr в самом низу, под
Теперь разберем ui_inGame2_Metall_box - ваше имя иконки, потом его и нужно будет писать в icon квеста. x="332" y="846" width="83" height="48" - это координаты, которые я взял в красную рамку в Paint.net 3. В файле tm_локация по пути gamedata\configs\misc в секции любого квеста ставим свою иконку, я взял секцию квест на исследование места падения Ската-2
Дата: Воскресенье, 01.05.2016, 22:20 | Сообщение # 57
Агро-Разработчик
[ Легенда Зоны ]
Урок 69 Задача: GUI-элементы.
Что такое gui-элементы? Это вызов статической картинки, на которой имеются активные кнопки, при нажатии на которые можно вызвать различные эффекты. Итак, начнем: Первым делом займемся скриптовой прописью: gamedata\scripts Создаем файл ui_gui_element.script И заполняем его:
Код
class "ui_test_gui" (CUIScriptWnd)
function ui_test_gui:__init(owner) super() self.owner = owner self:InitControls() self:InitCallBacks() end
function ui_test_gui:__finalize() end
function ui_test_gui:InitControls() self:SetWndRect (Frect():set(0,0,1024,768)) local xml, ctrl = CScriptXmlInit(), CUIWindow() xml:ParseFile ("ui_gui_elements.xml") self.main_panel = xml:InitStatic("test_gui",self) xml:InitStatic ("test_gui:test_gui_text",self.main_panel)
function ui_test_gui:InitCallBacks() self:AddCallback("button_exit", ui_events.BUTTON_CLICKED, self.OnButton_exit_clicked, self) end
function ui_test_gui:OnButton_exit_clicked() self:HideDialog() end
function ui_test_gui:OnKeyboard(dik,keyboard_action) CUIScriptWnd.OnKeyboard(self,dik,keyboard_action) if keyboard_action == ui_events.WINDOW_KEY_PRESSED then if dik == DIK_keys.DIK_ESCAPE then self:HideDialog() end end return true end
function run_ui_test_gui(folder) folder:ShowDialog(true) end
Разберем несколько моментов: xml:ParseFile ("ui_gui_elements.xml") - регистрация файла, в котором происходит пропись окна в игре. self.main_panel = xml:InitStatic("test_gui",self) - "test_gui" имя секции в .xml xml:InitStatic ("test_gui:test_gui_text",self.main_panel) - это строка создает любой текст в нашем gui-окне. Просто дублируем эту секцию, меняя имя "test_gui_text" (имя секции в .xml), чтобы не было совпадений, и тогда мы можем размещать текст в разных точках окна. self.button_exit = xml:Init3tButton ("test_gui:btn_exit",self.main_panel) self:Register (self.button_exit, "button_exit") self:AddCallback("button_exit", ui_events.BUTTON_CLICKED, self.OnButton_exit_clicked, self) Эти строки регистрируют саму кнопку, также дублируем по аналогии и меняем имена: "btn_exit" - имя в файле .xml; "button_exit" - имя кнопки в скрипте; "OnButton_exit_clicked" - регистрация эффектов при нажатии, - в этой секции прописываем то, что необходимо (эффекты берутся, либо из _g, либо из xr_effects). Наша gui-функция называется "ui_test_gui", поэтому если необходимо создать несколько функций в одном файле просто копируем все элементы скрипта и запускаем функцию поиска с заменой, берем имя "test_gui" и ставим в строку поиска, а в строке замены прописываем новое (я специально не учел в имени значение "ui" для того, чтобы разом можно было отредактировать всю функцию без лишних заморочек. Но! вам виднее). Здесь же. Теперь заходим в файл _g и в конце добавляем функцию:
Код
function run_gui(gui, close_inv) if close_inv == true then gui:ShowDialog(true) game_hide_menu() level.show_weapon(false) else gui:ShowDialog(true) end end
GUI-окно запускаем с помощью функции в xr_effects:
Код
function run_gui_effects(actor, npc) _g.run_gui(ui_gui_element.ui_test_gui()) end
Со скриптами кончено. Пора заняться конфигами: gamedata\configs\text\rus В любом текстовом документе создаем пару секций: Любой текст
Закрыть
Здесь (gamedata\configs\ui) создаем тот самый файл ui_gui_elements.xml И заполняем его:
Пояснение: ui\ui_name_texture - имя и местонахождение окна (запомните! в текстурах координаты окна должны быть на значении "0" - так будет проще размещать объекты). И чтобы это окно появилось в центре экрана, решаем задачку: (1024-827):2 и (768-573):2 - соответственно, получаем новые координаты: x="98" y="87". Значения "1024" и "768" постоянные, а вот ширина и высота уже зависят от размеров окна. !Желательно, чтобы размеры самого файла .dds были 1024х1024 Теперь регистрируем наш текст. Чтобы вычислить координаты для текста достаточно будет программы Paint.NET: открываем текстурку окна, выделяем размеры 250х25 (размеры окна для текста могут быть любыми в зависимости от объема текста) и передвигаем по площади окна, выбирая место, где должен будет размещаться текст; полученные координаты (находятся они в пункте "Позиция") прописываем в этой строке: Наша кнопка регистрируется также. Саму текстуру кнопки регистрируем по необходимости ("ui_inGame2_Mp_bigbuttone" - является игровой текстурой, дальнейшие действия показаны для наглядной прописи своих собственных кнопок): gamedata\configs\ui\textures_descr Любой файл, либо создаем свой:
Обязательно прописываем в четырех экземплярах с этими буковками ("e" - текстура в обычном режиме; "h" - при наведении курсором; "t" - при нажатии; "d" - кнопка в заблокированном виде), но при использовании кнопки буквы эти не учитываются, то есть будет выглядеть так: ui_inGame2_name_button_closet На этом всё.
IP-адрес: Страна: Российская Федерация Город: Москва Дата регистрации: 25.10.2014
Дата: Воскресенье, 26.06.2016, 03:59 | Сообщение # 58
Агро-Разработчик
[ Легенда Зоны ]
Урок 70 Задача: Создание зарядов взрывчатки в стиле СГМ.
В СГМ имеются дистанционные заряды, которые можно устанавливать в разных местах. Затем подрывать с помощью пульта. У меня возникло желание сделать подобное в чистом Зове Припяти. Полного подобия добиться не удалось. Но результат оказался не хуже.
Необходимо уметь распаковывать ресурсы Зова Припяти.
Будем создавать закладываемый заряд взрывчатки с возможностью установки таймера задержки взрыва от 1 до 10 секунд. С возможностью подрыва 3-х зарядов с одного пульта.
1. Открываем файл gamedata\configs\gameplay\character_desc_general. Прописываем ГГ в стартовый набор 4 заряда - remote_explosive_charge. После начала новой игры они окажутся в рюкзаке игрока. Добавляем в секции actor (она первая в этом файле) под строкой conserva = 2 \n строку remote_explosive_charge = 4 \n. Сохраняем файл.
2. Откроем файл gamedata\configs\misc\devices. Добавляем в него в конец файла следующие секции.
Пульт является квестовым предметом. Его нельзя продать или выкинуть из инвентаря.
Не буду останавливаться на прописывании зарядов в торговлю или настройке интерфейсных иконок для заряда и пульта. На эту тему есть другие уроки. В приложенной к уроку геймдате иконки настроены.
Сохраняем файл.
4. Откроем файл gamedata\configs\text\rus\st_items_equipment. Добавим в него текстовые описания бустеров.
Код
<string id="st_remote_explosive_charge"> <text>Заряд РС-15 с блок-детонатором</text> </string> <string id="st_remote_explosive_charge_descr"> <text>Подрывной заряд. Идет в комплекте с пультом управления. Для установки заряда его необходимо использовать. После установки заряда необходимо установить таймер взрывателя. Задержку взрыва можно выставить в диапазоне от одной до десяти секунд.</text> </string> <string id="st_remote_explosive_pda"> <text>Пульт управления зарядом РС-15</text> </string> <string id="st_remote_explosive_pda_descr"> <text>Для детонации установленных зарядов РС-15 пульт необходимо использовать. Для надёжного срабатывания установленных зарядов они должны нахлдиться не далее 150 метров от игрока.</text> </string>
Сохраняем файл.
5. Откроем файлы gamedata\configs\ui\map_spots и map_spots_16. Находим в них секцию
Мы зарегистрировали текстуру метки заряда на карте. И задали её вид. Метка заряда аналогична метке тайника. Если вы умеете править dds файлы, то можете открыть файл gamedata\textures\ui\ui_actor_hint_wnd и выбрать другой значок для метки тайника. Или добавить свой собственнцй значок. В приложенной к уроку геймдате это сделано. На редактировании dds файлов я останавливаться не буду.
Сохраняем файл.
7. Откроем файл gamedata\configs\text\rus\ui_st_pda. Добавим в него метку заряда
и так далее мы выбираем время задержки подрыва заряда. При попытке юзания заряда появится кодовое окно, в котором мы выберем число от 1 до 10. Время задержки взрыва в секундах. Если таймер не установлен, то взрыв произойдёт немедленно после команды на подрыв.
и так далее отсчитывают время до подрыва заряда. И производят сам подрыв.
В файлах remote_explosive_box_2.ltx и remote_explosive_box_3.ltx прописываем однотипную логику. Меняем функцию подрыва remote_explosive_box_1_activate на remote_explosive_box_2_activate и remote_explosive_box_3_activate соответственно.
Инфопорции таймеров remote_1_1_explosive, remote_1_2_explosive, remote_1_3_explosive и т.д. меняем на remote_2_1_explosive, remote_2_2_explosive, remote_2_3_explosive и т.д. для файла remote_explosive_box_2.ltx и remote_3_1_explosive, remote_3_2_explosive, remote_3_3_explosive и т.д. для файла remote_explosive_box_3.ltx.
Сохраняем файлы.
1. Открываем файл gamedata\scrips\_g.script. Добавим в него следующие функции.
Код
-- 'Удаление нескольких инфопортаций по возрастающим номерам. function disable_several_info(l_part,r_part,count_a,count_b) if count_b==nil then count_b=count_a count_a=1 end for i=count_a,count_b do disable_info(l_part..i..r_part) end end
-- 'Удалить все обьекты с указанной секцией. function release_objects_by_section(find_string) for a=1,65534 do local obj = alife():object(a) if obj then if obj:section_name()~=nil and string.find(obj:section_name(),find_string) then local sect=obj:section_name() remove_object_by_id(obj.id) end end end end
-- 'Удалить все обьекты с указанным именем. function release_objects_by_name(find_string) for a=1,65534 do local obj = alife():object(a) if obj then if obj:name()~=nil and string.find(obj:name(),find_string) then local sect=obj:name() remove_object_by_id(obj.id) end end end end
-- 'Удаление обьекта по его ID. function remove_object_by_id(item_id) if item_id~=nil and alife():object(item_id) then alife():release(alife():object(item_id),true) end end
-- 'Закрыть инвентарь/КПК. function game_hide_menu(type) if type==1 then get_hud():HideActorMenu() elseif type==2 then get_hud():HidePdaMenu() else get_hud():HideActorMenu() get_hud():HidePdaMenu() end end
-- 'Создание предмета в рюкзаке ГГ. function give_object_to_actor(section,count) if count==nil then count=1 end for i=1, count do alife():create(section,db.actor:position(),db.actor:level_vertex_id(),db.actor:game_vertex_id(),db.actor:id()) end end
function actor_binder:use_inventory_item(obj) if(obj) then local s_obj = alife():object(obj:id()) if(s_obj) and (s_obj:section_name()=="drug_anabiotic") then xr_effects.disable_ui_only(db.actor, nil) level.add_cam_effector("camera_effects\\surge_02.anm", 10, false, "bind_stalker.anabiotic_callback") level.add_pp_effector("surge_fade.ppe", 11, false) give_info("anabiotic_in_process") _G.mus_vol = get_console():get_float("snd_volume_music") _G.amb_vol = get_console():get_float("snd_volume_eff") get_console():execute("snd_volume_music 0") get_console():execute("snd_volume_eff 0") end end end
Дописываем в неё колбэки на использование наших бустеров. Так
Код
function actor_binder:use_inventory_item(obj) if(obj) then local s_obj = alife():object(obj:id()) if(s_obj) and (s_obj:section_name()=="drug_anabiotic") then xr_effects.disable_ui_only(db.actor, nil) level.add_cam_effector("camera_effects\\surge_02.anm", 10, false, "bind_stalker.anabiotic_callback") level.add_pp_effector("surge_fade.ppe", 11, false) give_info("anabiotic_in_process") _G.mus_vol = get_console():get_float("snd_volume_music") _G.amb_vol = get_console():get_float("snd_volume_eff") get_console():execute("snd_volume_music 0") get_console():execute("snd_volume_eff 0") end if(s_obj) and s_obj:section_name()=="remote_explosive_charge" then addon_callbacks.remote_explosive_charge_init() end if(s_obj) and s_obj:section_name()=="remote_explosive_pda" then addon_callbacks.remote_explosive_pda_init() end end end
Сохраняем файл.
3. Создаем в папке gamedata\scrips пустой файл addon_callbacks.script. Добавим в него наши функции.
Код
function remote_explosive_charge_init() local actor = db.actor if has_alife_info("remote_explosive_pda_init") then release_objects_by_section("remote_explosive_box_") release_objects_by_section("remote_explosive_bomb_") if has_alife_info("remote_explosive_1_install") then disable_info("remote_explosive_1_install") end if has_alife_info("remote_explosive_2_install") then disable_info("remote_explosive_2_install") end if has_alife_info("remote_explosive_3_install") then disable_info("remote_explosive_3_install") end disable_info("remote_explosive_pda_init") end if db.actor:object("remote_explosive_pda") == nil then give_object_to_actor("remote_explosive_pda") end if not has_alife_info("remote_explosive_1_install") then disable_several_info("remote_1_","_explosive",1,10) local sobj=alife():create("remote_explosive_box_1",actor:position(),actor:level_vertex_id(),actor:game_vertex_id()) give_info("remote_explosive_1_install") level.map_add_object_spot_ser(sobj.id,"explosive","") xr_effects.send_tip(db.actor,nil,{"st_remote_explosive_install","got_ammo"}) elseif not has_alife_info("remote_explosive_2_install") and has_alife_info("remote_explosive_1_install") then disable_several_info("remote_2_","_explosive",1,10) local sobj=alife():create("remote_explosive_box_2",actor:position(),actor:level_vertex_id(),actor:game_vertex_id()) give_info("remote_explosive_2_install") level.map_add_object_spot_ser(sobj.id,"explosive","") xr_effects.send_tip(db.actor,nil,{"st_remote_explosive_install","got_ammo"}) elseif not has_alife_info("remote_explosive_3_install") and has_alife_info("remote_explosive_2_install") then disable_several_info("remote_3_","_explosive",1,10) local sobj=alife():create("remote_explosive_box_3",actor:position(),actor:level_vertex_id(),actor:game_vertex_id()) give_info("remote_explosive_3_install") level.map_add_object_spot_ser(sobj.id,"explosive","") xr_effects.send_tip(db.actor,nil,{"st_remote_explosive_install","got_ammo"}) else game.start_tutorial("remote_explosive_no_use") give_object_to_actor("remote_explosive_charge") end game_hide_menu() end
--Данная функция выполняет следующие задачи:
--Проверка наличия инфопорции подрыва - remote_explosive_pda_init. Если инфопорция имеется - (после предыдущего подрыва новых зарядов не ставили) - то локации проверяются на наличии установленных и не сработавших зарядов и бомб. Все несработавшие объекты удаляются. Инфопорции сбрасываются.
--Проверка наличия у игрока пульта для подрыва. Выдача пульта, если его нет.
--Проверка на кол-во установленных зарядов. Установка зарядов в определенном порядке. 1, 2 и 3. Установка меток на карте. Выдача служебных сообщений. Сброс инфопорций таймеров от предыдущих зарядов. Отказ в установке 4 заряда.
Код
function remote_explosive_pda_init() give_info("remote_explosive_pda_init") xr_effects.send_tip(db.actor,nil,{"st_remote_explosive_pda_init","got_ammo"}) game_hide_menu() end
--Эта функция посылает служебное сообщение и выдает инфопорцию на подрыв.
Сохраняем файл.
4. Открываем файл gamedata\scrips\ph_code.
Находим функцию.
Код
function codepad:update(delta) end
Добавляем в неё возможность перехода на другой тип логики. Это нужно для нормальной работы зарядов. Так.
Код
function codepad:update(delta) if xr_logic.try_switch_to_another_section(self.object, self.st, db.actor) then return end end
Сохраняем файл.
5. Открываем файл gamedata\scrips\xr_effects. Добавим в неё исполняемые функции.
Код
function remote_explosive_box_1_activate(actor,obj) alife():create("remote_explosive_bomb_1",vector():set(obj:position()),obj:level_vertex_id(),obj:game_vertex_id()) level.add_call( function() if get_story_object("remote_explosive_bomb_1") ~= nil then return true end end, function() expl_obj = get_story_object("remote_explosive_bomb_1") expl_obj:explode(0) end ) if xr_conditions.object_exist(nil,nil,{"remote_explosive_box_1"}) then xr_effects.destroy_object(actor,npc,{"story","remote_explosive_box_1"}) end if xr_conditions.object_exist(nil,nil,{"remote_explosive_bomb_1"}) then xr_effects.destroy_object(actor,npc,{"story","remote_explosive_bomb_1"}) end end
function remote_explosive_box_2_activate(actor,obj) alife():create("remote_explosive_bomb_2",vector():set(obj:position()),obj:level_vertex_id(),obj:game_vertex_id()) level.add_call( function() if get_story_object("remote_explosive_bomb_2") ~= nil then return true end end, function() expl_obj = get_story_object("remote_explosive_bomb_2") expl_obj:explode(0) end ) if xr_conditions.object_exist(nil,nil,{"remote_explosive_box_2"}) then xr_effects.destroy_object(actor,npc,{"story","remote_explosive_box_2"}) end if xr_conditions.object_exist(nil,nil,{"remote_explosive_bomb_2"}) then xr_effects.destroy_object(actor,npc,{"story","remote_explosive_bomb_2"}) end end
function remote_explosive_box_3_activate(actor,obj) alife():create("remote_explosive_bomb_3",vector():set(obj:position()),obj:level_vertex_id(),obj:game_vertex_id()) level.add_call( function() if get_story_object("remote_explosive_bomb_3") ~= nil then return true end end, function() expl_obj = get_story_object("remote_explosive_bomb_3") expl_obj:explode(0) end ) if xr_conditions.object_exist(nil,nil,{"remote_explosive_box_3"}) then xr_effects.destroy_object(actor,npc,{"story","remote_explosive_box_3"}) end if xr_conditions.object_exist(nil,nil,{"remote_explosive_bomb_3"}) then xr_effects.destroy_object(actor,npc,{"story","remote_explosive_bomb_3"}) end end
Эти функции выполняют основную задачу - производят подрыв зарядов.
Сохраняем файл.
Начинаем новую игру и опробуем заряды.
IP-адрес: Страна: Российская Федерация Город: Москва Дата регистрации: 25.10.2014
Дата: Воскресенье, 01.10.2017, 22:20 | Сообщение # 60
Агро-Разработчик
[ Легенда Зоны ]
Урок 72 Задача: Как вывести на экран текстовые сообщения.
Чтобы вывести на экран одно или несколько текстовых сообщений, необходимо создать скрипт со специальной функцией и добавить её вызов. Создать скрипт можно любым текстовым редактором, просто сохраните текстовый файл в формате *.script
Путь:gamedata\scripts\script_name.script
В созданный скрипт, вставьте следующий код:
Код
function funct_name() news_manager.send_tip(db.actor, "ТЕКСТ", 0, "default", 10000) end
• funct_name — имя вашей функции, оно же используется для вызова. Пишется только по-английски и без пробелов. Вместо пробелов используйте знак подчеркивания (_). • news_manager.send_tip — стандартная функция использующаяся для вывода сообщений.
Аргументы функции:
1. db.actor — глобальная переменная. 2. text — текст сообщения. Рекомендуется указывать string id, который читается из *.xml файлов, находящихся по пути gamedata\configs\text указанной параметром language папки, в секции файла localization.ltx Иначе не будут работать дополнительные параметры (см. ниже) 3. 0 — число в секундах, которое задает задержку времени перед тем, как сообщение появится на экране (в данном случае равно 0, т.е без задержки). 4. default — имя иконки сообщения из скрипта news_manager.script (см. строку tips_icons) 5. 10000 — число (в миллисекундах), которое задает длительность отображения сообщения на экране до момента исчезновения(в данном случае равно 10 секундам).
Дополнительные параметры для текста:
• Чтобы изменить цвет текста, поместите нужную часть между тегами %c[255,255,128,128] и %c[default]. Значения в квадратных скобках [255,255,128,128], это RGB код цвета. • Чтобы перенести текст на следующую строку, поставьте перед ним тег \n
Множество сообщений подряд
Если возникла необходимость имитации переписки сталкеров по КПК, используйте подобную функцию:
Код
function funct_name() news_manager.send_tip(db.actor, "Ну как хабар?", nil, "default", 6000) news_manager.send_tip(db.actor, "Норм, нашел арт.", 4, "default", 6000) news_manager.send_tip(db.actor, "Гуд.", 8, "default", 6000) end
Итого, что происходит в переписке:
• у первого сообщения задержки нет • у второго задержка = 4 секунды от запуска функции • у третьего задержка = 8 секунд от запуска функции = 4 секунды после второго сообщения
IP-адрес: Страна: Российская Федерация Город: Москва Дата регистрации: 25.10.2014