Это популярное сообщение. Malandrinus 615 Опубликовано 8 Июля 2009 Это популярное сообщение. Поделиться Опубликовано 8 Июля 2009 (изменено) В данной теме собраны сведения по скриптовой модели сталкера: функции и классы, методы и свойства, взаимосвязь классов и последовательность работы с ними, связь работы классов и файлов конфигураций. К наполнению темы приглашаются все желающие. В наполнении темы непосредственно участвовали и существенно мне помогли: @Monnoroch, @Kolmogor, @Unnamed Black Wolf, @меченый(стрелок), @IQDDD, @Kirag, @Taroz, @dan, @7.9, @Garry_Galler, @AKKK1, @Bak и много других людей. Скрытый текст Скрытый текст класс alife_simulator. Базовые операции с серверными объектами. Пространства имён. Глобальные функции для большого числа задач. "Создание своего класса" и "Наследование от экспортированных классов". Базовые сведения об объектно-ориентированном программировании для сталкера. Необходимо прочитать, для понимания темы про биндер и некоторых других. В одном посте: Общие слова об архитектуре и скриптовой модели сталкера "Класс object_binder" расширение онлайновых объектов, колбеки, сохранение состояния. "Класс net_packet" Регистрация скриптовых классов с помощью object_factory Серверные классы. Часть 1 Иерархия серверных классов, описание не закончено. Серверные классы. Часть 2 Картинка структуры наследования и несколько заключительных слов Клиентские классы Скрытый текст Класс game_object Интерфейс ко всем онлайновым (клиентским объектам) Класс hit для нанесения урона скриптом и другая информация (IQDDD) Некоторая информация по управлению путями патрулирования здесь (Kirag) и здесь (Taroz) Неполная информация по управлению памятью неписей с примером здесь (Bak) Физическая оболочка объектов (Garry_Galler) Пост о выборе (подборе) оружия НПС и стрельбы (*Shoker*) Скрытый текст Управление заданиями Класс CGameTask и другие вспомогательные классы и функции. Управление инфопорциями Функции, колбеки, форматы файлов Список специальных системных инфопорций (Unnamed Black Wolf) Система профилей и алгоритм генерации имён. Форматы файлов, функции Дополнительная информация по параметрам профилей terrain_sect (Kolmogor) Диалоги. Часть 1 Форматы файлов, базовые сведения Диалоги. Часть 2 Скриптовые диалоги Диалоги. Часть 3 Тематическая подборка функций управления диалогами Скрытый текст Функции времени Тематическая подборка функций, связанных с управлением игровым временем. Класс CTime Вспомогательный класс для управления игровым временем Полезная скриптовая функция с использованием CTime (Garry_Galler) Скрытый текст class ini_file (меченый(стрелок)) Класс FS и CSavedGameWrapper Бинарный доступ к файлам, в том числе в игровых архивах, управление сохранёнными играми. Скрипт уровня. Забытая фишка с колбеком на заход на уровень Класс vector Некоторая полезная информация о разных вещах (меченый(стрелок)) "Класс render_device" Направление и положение камеры, характеристики экрана, программная пауза игры и др. Некоторая информация о различиях между ТЧ и ЗП в системе оконных классов и колбеков. (lekzd) Неплохо бы развить эту тему! Некоторая полезная информация о скриптовых функциях из модуля _g.script. (lekzd) Также требует развития! Полезные функции для работы с графом игры (Garry_Galler) В одном посте: Класс profile_timer Отладочные измерения скорости работы фрагментов программы Класс client_spawn_manager Колбек на выход в онлайн без использования биндера. Работа с консолью. Класс CConsole Анимации цвета. Класс color_animator Всякие моргающие элементы в окнах и пр. Управление постэффектами. Скриптовые постэффекты. Класс effector Класс sound_object. Проигрывание звуков в игре в произвольном месте, от произвольного объекта, в голове актора. (Shadows) Пост удалён автором (прим. Kirgudu) Скрытый текст Оконные классы Некоторая общая информация о создании окон Список методов, XML-тегов и событий для оконных классов (ТЧ/ЧН/ЗП) (Norman Eisenherz) Представление материала в моих статьях оптимизировано для онлайнового просмотра. Если кому не хочется лазить по спойлерам, а нужно просмотреть текст какого-либо поста "потоком", то могу рекомендовать просмотр в режиме "текстовая версия". В этом же режиме удобно сохранять содержимое темы на диск. (прим. Malandrinus) Изменено 30 Июля пользователем Kirgudu 5 5 16 Плагины Total Commander для работы с игровыми архивами: Архиваторный плагин (для работы с одиночным архивом): link1 link2 Системный плагин (для распаковки установленной игры): link1 link2 Ссылка на комментарий
Malandrinus 615 Опубликовано 1 Октября 2010 Автор Поделиться Опубликовано 1 Октября 2010 Garry_Galler, А действительно никак нельзя переинициализировать диалог вручную - принудительно? Ведь граф диалога куда то записывается при инициализации диалога Нельзя. Принцип работы системы такой. Там внутри есть нечто вроде хранилища - массив инициализированных диалогов. Все диалоги при старте игры не грузятся, грузятся они по первому запросу, при этом инициализируются и помещаются в это хранилище, откуда при дальнейших запросах выбираются по ключу (идентификатору диалога). При этом способ инициализации (через XML или скриптом) принципиально не важен. Диалог (или точнее граф диалога) по-любому создаётся один раз. Это хранилище инициализированных диалогов не принадлежит какой-либо конкретной сохранённой игре. Время его жизни - сеанс работы программы. Относительно графа диалога. Я разумею под ним полный граф, включающий все возможные фразы (игнорируя предусловия). Представьте себе лабиринт с дверями. В какие-то двери войти можно, в какие-то нельзя. Это предусловия. А сам лабиринт - это граф. Граф менять нельзя, а предусловия можно. Кстати, а что полезного дает строковое айди диалога - кроме того, что оно используется при выводе в лог в случае ошибки при построении диалога? Мы же его указываем в профиле персонажа. Для этого и нужен, чтобы ссылаться на диалог. Или я не понял вопроса? Плагины Total Commander для работы с игровыми архивами: Архиваторный плагин (для работы с одиночным архивом): link1 link2 Системный плагин (для распаковки установленной игры): link1 link2 Ссылка на комментарий
Garry_Galler 7 Опубликовано 1 Октября 2010 Поделиться Опубликовано 1 Октября 2010 (изменено) malandrinus Окей, насчет инициализации и хранения диалогов понял. (примерно так и думал, что есть какой то движковый storage\ массив для них). Кстати вот и ответ на мой вопрос про айди диалогов - я имел ввиду, когда мы его получаем как входящий аргумент например из прекондишена или экшена - то какая польза от этого параметра? видимо никакой, но диалоги ...помещаются в это хранилище, откуда при дальнейших запросах выбираются по ключу (идентификатору диалога). То бишь назначение айди диалогов - для внутреннего использования функциями игры. Для модмейкера получается ничего не дает. Изменено 1 Октября 2010 пользователем Garry_Galler Ссылка на комментарий
Malandrinus 615 Опубликовано 1 Октября 2010 Автор Поделиться Опубликовано 1 Октября 2010 Garry_Galler, Всё же самое главное использование идентификаторов для модостроителя - это указание с их помощью диалогов в профилях персонажей. В указанных функциях их можно использовать тогда, когда одна функция используется для нескольких диалогов. Типа оптимизация. Есть некая функция в одном диалоге и в другом. Очень похожи, но отличаются на пару строк. Объединяем в одну, а разницу реализуем в зависимости от имени диалога. Как-то так. Вообще, чтобы понять задумку разрабов в полной мере надо смотреть их примеры. Обычно сразу становится ясно, за каким им потребовалась та или иная странная фишка. Вот к пример скриптовые диалоги они сами использовали для того, чтобы создавать диалог на базе информации из файла ltx. Но проблема бывает в том, что фишка могла быть сделана для какого-то билда, который давно ушёл в историю, и примеров использования не сыскать, и не актуально это давным-давно. А мы тут сидим, умные разговоры ведём =) Плагины Total Commander для работы с игровыми архивами: Архиваторный плагин (для работы с одиночным архивом): link1 link2 Системный плагин (для распаковки установленной игры): link1 link2 Ссылка на комментарий
Это популярное сообщение. Malandrinus 615 Опубликовано 4 Ноября 2010 Автор Это популярное сообщение. Поделиться Опубликовано 4 Ноября 2010 (изменено) Привожу описание системы классов для построения оконного интерфейса. Описание приводится для ТЧ и ЗП. Для ЧН специально не выделял, но следует учесть, что в этой части ЧН ближе к ТЧ, нежели к ЗП. Описание есть только для некоторых методов, но чаще всего о назначении и так можно догадаться. Точные типы аргументов и возвращаемых значений приведены для всех без исключений методов. Скрытый текст При описании унаследованных классов перечисляются только новые методы для этого класса. Методы из унаследованного опускаются. Помните об этом. Методов в каждом классе выходит довольно много, но есть большое количество классов, которые практически ничего не добавляют к базовым. Если класс вообще ничего не добавляет, то просто привожу его имя Иерархию классов прячу под вложенными спойлерами, как и длинные описания. Иначе пост будет совершенно немерянной длины и найти там что-то будет просто невозможно. В целом для описания используется "псевдо С++", некая смесь, в целом следующая синтаксису С++, но с упрощениями и отступлениями в сторону Lua. Прошу не пугаться по этому поводу =) Скрытый текст CUIWindow - базовый класс для всех остальных оконных классов, в связи с чем описан наиболее подробно. Скрытый текст class CUIWindow { CUIWindow (); // конструктор, как всегда доступен в виде глобальной функции void SetPPMode(); // включение события двойного клика void ResetPPMode(); // выключение события двойного клика void AttachChild(CUIWindow*); // присоединение дочернего окна void DetachChild(CUIWindow*); // отсоединение дочернего окна void SetWindowName(string); // установка имени окна, тег "window_name" string WindowName(); // получение имени окна void SetFont(CGameFont*); // только ТЧ, атрибут "font" CGameFont* GetFont(); // только ТЧ void Enable(bool); // включить/выключить возможность взаимодействовать с пользователем bool IsEnabled(); // получить статус активности void SetAutoDelete(bool); bool IsAutoDelete(); void Show(bool); // показать/скрыть окно bool IsShown(); // получить статус видимости void Init(float x, float y, float width, float height); // только ТЧ void Init(Frect*); // только ТЧ // установить положение верхнего левого угла окна относительно родительского void SetWndPos(float x, float y); // вариант ТЧ void SetWndPos(vector2*); // вариант ЗП vector2* GetWndPos(CUIWindow*); // только ЗП, получить положение окна // установить размеры окна void SetWndSize(float w, float h); // вариант ТЧ void SetWndSize(vector2); // вариант ЗП // установить положение и размеры окна void SetWndRect(Frect); void SetWndRect(float x, float y, float width, float height); // только ТЧ void SetHeight(float h); // только ТЧ, установить высоту окна float GetHeight(); // получить высоту окна void SetWidth(float w); // только ТЧ, установить ширину окна float GetWidth(); // получить ширину окна }; Производные от CUIWindow: Скрытый текст Список игровых серверов. Очевидно, для синглового режима мало применим. class CServerList : CUIWindow { CServerList (); void SetPlayerName(string); void SetFilters(SServerFilters&); void RefreshList(bool); void SetSortFunc(string, bool); void NetRadioChanged(bool); void ShowServerInfo(); void RefreshQuick(); void ConnectToSelected(); }; к нему прилагается служебный класс SServerFilters class SServerFilters { SServerFilters (); bool empty; bool full; bool listen_servers; bool with_pass; bool without_ff; bool without_pass; bool without_pb; // только ТЧ }; Скрытый текст CUIComboBox - выпадающий список. В ТЧ есть, но недоэкспортирован, в связи с чем применять его можно только в ЗП class CUIComboBox : CUIWindow { CUIComboBox (); void Init(float x, float y, float width); // только ТЧ void Init(float x, float y, float width, float height); // только ТЧ void ClearList(); // только ЗП void SetListLength(int length); void SetVertScroll(bool v); void SetText(string s); // только ЗП string GetText(); // только ЗП void enable_id(int id); // только ЗП void disable_id(int id); // только ЗП CUIListBoxItem* AddItem(string s, int value); // только ЗП void SetCurrentID(int id); int CurrentID(); string GetTextOf(int id); // только ЗП void SetCurrentValue(); // только ЗП }; Скрытый текст CUICustomEdit - поле редактирования текста class CUICustomEdit : CUIWindow { void SetNumbersOnly(bool v); // только ТЧ void SetTextPosX(float x); // только ТЧ void SetTextPosY(float y); // только ТЧ void SetTextAlignment(enum CGameFont::EAligment); // только ТЧ CGameFont::EAligment GetTextAlignment(); // только ТЧ void SetTextColor(DWORD color); // только ТЧ DWORD GetTextColor(); // только ТЧ void SetText(string); string GetText(); void SetNextFocusCapturer(CUICustomEdit*); // только ЗП void CaptureFocus(bool v); // только ЗП }; от него унаследованы: class CUIEditBox : CUICustomEdit { CUIEditBox (); void InitTexture(string texture); }; и class CUIEditBoxEx : CUICustomEdit { CUIEditBoxEx (); void InitTexture(string texture); }; Скрытый текст CUICustomSpin - поле прокрутки значений. Не совсем понятно, можно ли его полноценно использовать по причине крайне скудного набора собственных свойств class CUICustomSpin : CUIWindow { string GetText(); }; От CUICustomSpin наследуются несколько классов, которые к нему вообще ничего не добавляют: class CUISpinFlt : CUICustomSpin class CUISpinNum : CUICustomSpin class CUISpinText : CUICustomSpin Скрытый текст CUIDialogWnd - класс диалогового окна. Сам по себе редко используется, но является базовым для чрезвычайно важного класса CUIScriptWnd class CUIDialogWnd : CUIWindow { void SetHolder(CDialogHolder*); // только ТЧ CDialogHolder* GetHolder(); void HideDialog(); // только ЗП void ShowDialog(bool <скрывать индикаторы>); // только ЗП // вместо этих функций в ТЧ надо использовать глобальную функцию level.start_stop_menu }; Скрытый текст Скрытый текст CUIMessageBoxEx - диалоговое окно по функциональности схожее с CUIMessageBox class CUIMessageBoxEx : CUIDialogWnd { CUIMessageBoxEx (); void Init(string template); // только ТЧ void InitMessageBox(string template); // только ЗП void SetText(string text); // только ЗП string GetPassword(); string GetHost(); }; Описание применения: Окно создаётся наподобие обычного контрола в процессе инициализации главного окна (как правило в типовом методе InitControls) self.msg_box = CUIMessageBoxEx() и регистрируется для возможности обрабатывать события нажатия на кнопки self:Register(self.msg_box, "msg_box") затем в методе InitCallBacks на кнопки этого окна устанавливают колбеки self:AddCallback("msg_box", ui_events.MESSAGE_BOX_OK_CLICKED, self.OnMsgOk, self) Скрытый текст MESSAGE_BOX_CANCEL_CLICKED MESSAGE_BOX_COPY_CLICKED MESSAGE_BOX_NO_CLICKED MESSAGE_BOX_OK_CLICKED MESSAGE_BOX_QUIT_GAME_CLICKED MESSAGE_BOX_QUIT_WIN_CLICKED MESSAGE_BOX_YES_CLICKED в нужный момент окно можно вызывать так: для ТЧ self.msg_box:Init(<строка_инициализации_окна>) self:GetHolder():start_stop_menu(self.msg_box, true) для ЗП self.msg_box:InitMessageBox(<строка_инициализации_окна>) self.msg_box:SetText(<сообщение>) // необязательное действие self.msg_box:ShowDialog(true) <строка_инициализации_окна> ссылается на одно из описаний диалогов из файла config\ui\message_box.xml примеры и подробности смотреть там. Только несколько комментариев. Там можно создать своё окно, но требуется придерживаться шаблонных имён частей этого окна. Можно менять текстуры собственно окна, добавлять типовые кнопки "да, нет, ок, отмена", можно менять иконку окна. Также можно добавлять строки ввода. После выхода из окна, что можно отследить колбеками, введённые значения можно получить с помощью методов GetPassword и GetHost. Скрытый текст CUIScriptWnd - скриптовый диалог. Необычайно важный класс, основа для построения всего пользовательского интерфейса. Это единственный из всех оконных классов, позволяющий скриптовое наследование от себя. Это даёт возможность создавать окна с реакцией на события мыши и клавиатуры. class CUIScriptWnd : CUIDialogWnd,DLL_Pure { CUIScriptWnd (); DLL_Pure* _construct(); // от DLL_Pure, назначение неизвестно bool Load(string xml); // непонятно зачем - нет ни одного примера использования. Возможно, колбек на загрузку void Register(CUIWindow*, string name); // регистрация контрола для возможности обработки событий void Register(CUIWindow*); // делает тоже самое, но не устанавливает имя, в ЗП убрана void AddCallback(string name, int event, const function<void>&, object); // установка колбека на действия пользователя // event - константа из класса-перечисления ui_events void AddCallback(string name, int event, const function<void>&); // в ЗП убрана bool OnKeyboard(int dic, enum EUIMessages); // обработка событий от клавиатуры bool Dispatch(int cmd, int param); // ещё какой-то обработчик function Update(); // похоже на обновление окна в смысле обновления полей ввода, надо разбираться // перечисленные далее функции на практике не нужны и в ЗП удалены совсем CUIFrameLineWnd* GetFrameLineWnd(string); CUICheckButton* GetCheckButton(string); //function GetListWndEx(string); // этой возможно и в ТЧ нет CUIPropertiesBox* GetPropertiesBox(string); CUIButton* GetButton(string); CUIListWnd* GetListWnd(string); CUIStatic* GetStatic(string); CUITabControl* GetTabControl(string); CUIRadioButton* GetRadioButton(string); CUIFrameWindow* GetFrameWindow(string); CUIDialogWnd* GetDialogWnd(string); CUIEditBox* GetEditBox(string); CUIProgressBar* GetProgressBar(string); CUIMessageBox* GetMessageBox(string); }; Скрытый текст CUIFrameLineWnd - вроде как окно с рамкой. Сам по себе (вероятно) не интересен, но порождает несколько практически важных классов class CUIFrameLineWnd : CUIWindow { CUIFrameLineWnd (); void Init(string base_name, float x, float y, float w, float h, bool horiz = true); // только ТЧ void SetOrientation(bool horiz); // только ТЧ CUIStatic* GetTitleStatic(); // только ТЧ // SetWidth и SetHeight имеются и в ТЧ и в ЗП, но в ТЧ они унаследованы от родительского // окна, а в ЗП введены дополнительно void SetWidth(float w); void SetHeight(float h); void SetColor(DWORD color); }; от него наследуются: // только ТЧ class CUILabel : CUIFrameLineWnd { CUILabel (); string GetText(); void SetText(string); } // только ЗП class CUIListBoxItem : CUIFrameLineWnd { CUIListBoxItem(float heght); CUITextWnd* GetTextItem(); void SetTextColor(DWORD color); void AddIconField(float width); void AddTextField(string text, float width); }; от него в свою очередь (тоже только ЗП): class CUIListBoxItemMsgChain : CUIListBoxItem { CUIListBoxItemMsgChain(float heght); }; Скрытый текст CUIFrameWindow - тоже что-то с рамкой CUIFrameWindow : CUIWindow { CUIFrameWindow (); void Init(string name, int x, int y, int w, int h); // только ТЧ CUIStatic* GetTitleStatic(); // только ТЧ // как и в CUIFrameLineWnd SetWidth и SetHeight имеются и в ТЧ и в ЗП, но в ТЧ // они унаследованы от родительского окна, а в ЗП введены дополнительно void SetWidth(float w); void SetHeight(float h); void SetColor(DWORD color); }; от него унаследован: class CUIPropertiesBox : CUIFrameWindow { CUIPropertiesBox (); bool AddItem(string); void AutoUpdateSize(); void RemoveAll(); void RemoveItem(DWORD); void Hide(); void Show(int, int); //(Frect, vector2) ?????????? }; Скрытый текст CUIListWnd - список. Класс имеется только в ТЧ и активно там используется. В ЗП вместо него используется CUIListBox, который унаследован от CUIScrollView, который в ТЧ есть, но выглядит неработоспособным. class CUIListWnd : CUIWindow { CUIListWnd (); void SetTextColor(DWORD); void ActivateList(bool); bool IsListActive(); void EnableScrollBar(bool); bool IsScrollBarEnabled(); void ShowSelectedItem(bool); void ResetFocusCapture(); void ScrollToBegin(); void ScrollToEnd(); void ScrollToPos(int); void SetItemHeight(int); int GetLongestSignWidth(); int GetSize(); // количество элементов void SetVertFlip(bool); bool GetVertFlip(); int GetItemPos(CUIListItem*); CUIListItem* GetItem(int); bool AddItem(CUIListItem*); // всегда возвращает true int GetSelectedItem(); void SetFocusedItem(int); int GetFocusedItem(); void RemoveAll(); void RemoveItem(int); }; к этому классу прилагаются два служебных CUIListItem и CUIListItemEx, которые будут описаны далее в разделе наследования от CUIStatic Скрытый текст CUIMMShniaga - этот контрол представляет собой комплексную конструкцию со списком элементов и ползунком с увеличительным стеклом. Это часть главного меню, если не забыли ещё. Одним словом это как-то не назвать, вот и у разработчиков видимо фантазии не хватило. Отсюда и такое имечко =) class CUIMMShniaga : CUIWindow { // enum CUIMMShniaga::enum_page_id // только ЗП const epi_main = 0; const epi_new_game = 1; const epi_new_network_game = 2; void ShowPage(enum CUIMMShniaga::enum_page_id); // только ЗП void SetPage(enum CUIMMShniaga::enum_page_id, string xml_file, string xml_path); // только ЗП void SetVisibleMagnifier(bool); }; Скрытый текст CUIMapList - видимо, список мультиплеерных карт. Как и в случае со списком серверов для сингла интереса не представляет class CUIMapList : CUIWindow { CUIMapList (); void LoadMapList(); viud SaveMapList(); bool IsEmpty(); void ClearList(); // только ЗП string GetCommandLine(string player); EGameTypes GetCurGameType(); void SetServerParams(string); void SetWeatherSelector(CUIComboBox*); void SetModeSelector(CUISpinText*); void SetMapPic(CUIStatic*); void SetMapInfo(CUIMapInfo*); void StartDedicatedServer(); void OnModeChange(); }; к нему прилагается дополнительный класс class CUIMapInfo : CUIWindow { CUIMapInfo(); void InitMap(string name); // вариант ТЧ void InitMap(string name, string version); // вариант ЗП void Init(vector2 pos, vector2 sz); // только ЗП }; Скрытый текст CUIProgressBar - ползунок прогресса. В ТЧ недоэкспортирован, в связи с чем практический интерес представляет только под ЗП class CUIProgressBar : CUIWindow { CUIProgressBar (); float GetRange_max(); float GetRange_min(); void SetRange(float min, float max); // только ТЧ void SetProgressPos(float); // только ЗП float GetProgressPos(); // только ЗП }; Скрытый текст CUIScrollView - класс имеется во всех версиях движка, но под ТЧ нигде не задействован. В ЗП напротив - заменяет класс CUIListWnd (если точнее, заменяет не он сам, а унаследованный от него) class CUIScrollView : CUIWindow { CUIScrollView (); void AddWindow(CUIWindow*, bool auto_delete); void RemoveWindow(CUIWindow*); void Clear(); void ScrollToBegin(); void ScrollToEnd(); int GetMinScrollPos(); int GetMaxScrollPos(); void SetScrollPos(int); int GetCurrentScrollPos(); }; в ЗП от него наследуется: class CUIListBox : CUIScrollView { CUIListBox(); void AddExistingItem(CUIListBoxItem*); CUIListBoxItem* AddTextItem(string text); void RemoveItem(CUIWindow*); CUIListBoxItem* GetItemByIndex(int); int GetSelectedIndex(); CUIListBoxItem* GetSelectedItem(); int GetSize(); void RemoveAll(); void ShowSelectedItem(bool); CUIWindow* GetItem(int); }; к этому классу прилагаются служебные классы CUIListBoxItem и CUIListBoxItemMsgChain, описанные ранее. Скрытый текст CUIStatic - очень важный класс. В ТЧ его возможности огромны. В ЗП - существенно меньше (это один из классов, пострадавших от изменений в наибольшей степени), однако по-прежнему остаётся очень важным. В связи с большой разницей версий описание приводится по отдельности для ТЧ и ЗП для ТЧ: CUIStatic : CUIWindow { CUIStatic (); void Init(float x, float y, float w, float h); void Init(string texture, float x, float y, float w, float h); void InitTexture(string texture); void SetColor(DWORD color); // фон DWORD GetColor() const; void SetOriginalRect(float x, float y, float w, float h); void SetTextureOffset(float x, float y); void SetStretchTexture(bool); bool GetStretchTexture(); void ClipperOn(); void ClipperOff(); bool GetClipperState(); void SetHeading(float angle); float GetHeading(); void SetText(string text); void SetTextST(string text); // дополнительно транслирует строку string GetText(); void SetTextX(float x); float GetTextX(); void SetTextY(float y); float GetTextY(); void SetTextColor(int a, int r, int g, int b); void SetTextAlign(CGameFont::EAligment ); CGameFont::EAligment GetTextAlign(); }; для ЗП: CUIStatic : CUIWindow { CUIStatic (); void InitTexture(string texture); void SetTextureRect(Frect*); Frect* GetTextureRect(); void SetStretchTexture(bool); CUILines* TextControl(); }; Частично потерянная функциональность класса для ТЧ вынесена в дополнительный класс (только ЗП) class CUILines { void SetText(string); void SetTextST(string); // с трансляцией string GetText(); void SetTextColor(DWORD color); void SetFont(CGameFont*); void SetElipsis(bool); }; CUIStatic важен не только сам по себе. От него ещё и наследуется много практически важных специализированных классов: Скрытый текст Кнопка: class CUIButton : CUIStatic { CUIButton (); void SetHighlightColor(DWORD color); // только ТЧ void EnableTextHighlighting(bool); // только ТЧ }; от него унаследованы: специальная кнопка для работы с контролом управления закладками: class CUITabButton : CUIButton // ничего не добавляет кнопка с тремя состояниями: class CUI3tButton : CUIButton // ничего не добавляет от неё в свою очередь унаследован переключатель: class CUICheckButton : CUI3tButton { CUICheckButton (); void SetCheck(boolean); bool GetCheck(); void SetDependControl(CUIWindow*); }; окно сообщения. Представляет собой фактически не контрол, а почти полноценный диалог с полем ввода: class CUIMessageBox : CUIStatic { CUIMessageBox (); void Init(string template); // только ТЧ void InitMessageBox(string template); // только ЗП void SetText(string text); // только ЗП string GetPassword(); string GetHost(); }; окно управления сном (только ЗП): class CUISleepStatic : CUIStatic // нет новых методов элемент списка (только ТЧ) class CUIListItem : CUIButton // нет новых методов продвинутый элемент списка (только ТЧ) class CUIListItemEx : CUIListItem { CUIListItemEx (); void SetSelectionColor(DWORD color); }; класс CUIListItemPair, упомянутый в lua_help и унаследованный от CUIListItemEx, похоже не существует. Может когда-то и был... Скрытый текст CUITabControl - класс для управления закладками CUITabControl : CUIWindow { CUITabControl (); void AddItem(CUITabButton*); void AddItem(string item, string texture, float x, float y, float h, float w); // вариант ТЧ void AddItem(string item, string texture, vector2 pos, vector2 size); // вариант ЗП void RemoveAll(); int GetTabsCount() const; CUIButton* GetButtonByIndex(int i); // только ТЧ void SetNewActiveTab(int i); // только ТЧ int GetActiveIndex(); // только ТЧ void RemoveItem(int i); // только ТЧ string GetActiveId(); // только ЗП void SetActiveTab(string tab); // только ЗП CUITabButton* GetButtonById(string id); // только ЗП }; Скрытый текст CUITrackBar - ползунок. Как и некоторые другие классы в ТЧ недоэкспортирован до применябельного состояния CUITrackBar : CUIWindow { CUITrackBar (); void SetCheck(bool); bool GetCheck(); float GetFValue(); // только ЗП int GetIValue(); // только ЗП void SetCurrentValue(); // только ЗП }; Скрытый текст CUITextWnd - какое-то текстовое поле. Есть только под ЗП. Видимо, частично компенсирует потерю аналогичных методов из других классов. class CUITextWnd : CUIWindow { CUITextWnd (); void SetText(string); void SetTextST(string); string GetText(); void SetTextColor(DWORD color); DWORD GetTextColor(); void SetFont(CGameFont*); CGameFont* GetFont(); void SetTextComplexMode(bool); void SetTextOffset(float x, float y); void SetTextAlignment(enum CGameFont::EAligment); void SetVTextAlignment(enum EVTextAlignment); void AdjustHeightToText(); void AdjustWidthToText(); void SetEllipsis(bool); // установка обрезания текста (используя троеточие) }; Надеюсь в скором времени дополнить данный пост дополнительной информацией в этом направлении: будет диаграмма классов для общего развития и несколько общих слов о применении всей этой системы в целом. Изменено 29 Июля пользователем Kirgudu 2 3 Плагины Total Commander для работы с игровыми архивами: Архиваторный плагин (для работы с одиночным архивом): link1 link2 Системный плагин (для распаковки установленной игры): link1 link2 Ссылка на комментарий
IQDDD 5 Опубликовано 4 Ноября 2010 Поделиться Опубликовано 4 Ноября 2010 Вот это дело! Теперь осталось только ui_events. Кстати, а какая константа обозначает коллбек флажка (checkbutton'а) на снятие/установку. Пробовал CHECK_BUTTON_SET, CHECK_BUTTON_RESET, PROPERTIES_CLICKED - не работают. И как сохранить значение флажка?) Ссылка на комментарий
Malandrinus 615 Опубликовано 4 Ноября 2010 Автор Поделиться Опубликовано 4 Ноября 2010 IQDDD, насчёт колбеков сейчас точно не могу сказать. Либо что-то не то делаешь, либо они не работают. Можешь ещё попробовать для чекбокса "кнопочные" события типа BUTTON_CLICKED. Насчёт сохранения, пошарь методы для CUICheckButton двумя постами выше =) Плагины Total Commander для работы с игровыми архивами: Архиваторный плагин (для работы с одиночным архивом): link1 link2 Системный плагин (для распаковки установленной игры): link1 link2 Ссылка на комментарий
IQDDD 5 Опубликовано 4 Ноября 2010 Поделиться Опубликовано 4 Ноября 2010 (изменено) Да я понимаю, что есть check:GetCheck(). но разрабы сохраняют в оригинальных скриптах через некий класс COptionsManager() (см. ui_mm_opt_main) BUTTON_CLICKED работает. Изменено 4 Ноября 2010 пользователем IQDDD Ссылка на комментарий
Malandrinus 615 Опубликовано 4 Ноября 2010 Автор Поделиться Опубликовано 4 Ноября 2010 (изменено) IQDDD, разрабы сохраняют в оригинальных скриптах через некий класс COptionsManager() Этот класс по-моему не имеет прямого отношения к состоянию отдельно взятого контрола. Что-то для работы с настройками. P.S.: Я может вопроса не понял. Сохранить - что означает? Сохранить до следующей игры? Изменено 4 Ноября 2010 пользователем malandrinus Плагины Total Commander для работы с игровыми архивами: Архиваторный плагин (для работы с одиночным архивом): link1 link2 Системный плагин (для распаковки установленной игры): link1 link2 Ссылка на комментарий
IQDDD 5 Опубликовано 4 Ноября 2010 Поделиться Опубликовано 4 Ноября 2010 да всё, вопрос исчерпан. Я просто хотел найти способ сохранять настройки мода иным способом, отличным от записи в pstor. в принципе, легче записать в него, чем копать потенциальный класс. Ссылка на комментарий
Malandrinus 615 Опубликовано 5 Ноября 2010 Автор Поделиться Опубликовано 5 Ноября 2010 (изменено) В связи с внезапным окончанием бета версии Visio красивая картинка с иерархией оконных классов откладывается =) Так что сейчас разберём общие вопросы, т.е. Скрытый текст Начнём с того, что все задачи по работе с интерфейсом сводятся к двум: вывод и ввод. Сразу разделим наши задачи на два принципиально разных режима, в которых может находиться игра. Первый режим назовём игровым. В этом режиме игрок управляет персонажем в трехмерном мире. При этом ввод от мыши и клавиатуры полностью работает на управление пресонажем. Соответственно, вопрос о задаче ввода в этом режиме не стоит вообще. К сожалению, разработчики не оставили возможности добавить в этом режиме скриптовую реакцию на свои кнопки. Как-то этот вопрос решается, но сейчас об этом не будем. Итак, в игровом режиме можно только создавать на экране поверх трёхмерного изображения свои элементы. Взаимодействовать с ними будет невозможно. Второй режим назовём диалоговым. Это режим для главного меню, встроенных диалогов вроде инвентаря и пользовательских диалогов. В этом режиме открывается окно, которое полностью перехватывает управление мышью и клавиатурой. Соответственно, в этом режиме можно организовать ввод своих данных и реагировать на действия с мышой. События в игровом мире при этом могут остановиться (в главном меню) или продолжаться своим чередом (во всех остальных случаях). Начнём с игрового режима и для начала определимся с терминологией. В этом режиме игрок видит перед собой трёхмерную картинку происходящего и так называемый худ (HUD = heads-up display, ведет происхождение от интерфейса военных самолетов, при котором информация отображается на стекле обзора, что позволяет не опускать голову на приборы, т.е. голова остается поднятой (англ. "head up")). Причём, элементами худа являются в том числе руки и предмет, который актор крутит в руках. Эти объекты по своей природе трёхмерны и в этом движке на них влиять нельзя (а было бы неплохо на самом-то деле управлять, скажем, изображением на экране детектора, который находится в руках у актора в ЧН и ЗП). Так что в дальнейшем мы будем говорить о худе, имея в виду только плоские элементы интерфейса: индикаторы здоровья, оружия, слотов, миникарта и прочее в этом роде. Если точнее, будем называть худом ту прозрачную плоскость на которой все эти элементы расположены. Если это движковые элементы, то управлять ими можно только в плане скрыть/показать, и только все разом. Однако, при этом можно добавить своих элементов и уже с ними делать что угодно. Так можно создавать всякие хитрые индикаторы, движущиеся прицельные метки и прочее в этом роде. Все такие (плоские) элементы создаются с помощью окон, описанных ранее. Создав окно как объект, его нужно разместить на худе. Для управления худом имеется класс CUIGameCustom. Подобно некоторым другим классам существует всего один глобальный объект такого класса и получить его можно с помощью глобальной функции get_hud() (см. описание пространств имён). Скрытый текст class CUIGameCustom { void AddCustomMessage(string id, float x, float y, float font_sz, CGameFont *font, unsigned short alignment, DWORD color); // только ТЧ void AddCustomMessage(string id, float x, float y, float font_sz, CGameFont *font, unsigned short alignment, DWORD color, float flicker); // только ТЧ void CustomMessageOut(string id, string msg, DWORD color); // только ТЧ void RemoveCustomMessage(string id); // только ТЧ SDrawStaticStruct* AddCustomStatic(string id, bool single_instance); SDrawStaticStruct* GetCustomStatic(string id); void RemoveCustomStatic(string id); void AddDialogToRender(CUIWindow* wnd); void RemoveDialogToRender(CUIWindow* wnd); void HidePdaMenu(); // только ЗП void HideActorMenu(); // только ЗП void show_messages(); // только ЗП void hide_messages(); // только ЗП }; Этот класс даёт два метода для размещения на худе своих элементов. Метод первый и исторически самый распространённый. Используются функции AddCustomStatic, RemoveCustomStatic и GetCustomStatic. Теперь по порядку: Имеется файл xml с описаниями создаваемых элементов. Это файл configs\ui\ui_custom_msgs.xml, имя которого прописано прямо в движке. Необходимо внести в этот файл описание своего элемента и дать ему имя. Смотрите там, как это делается. Вкратце, создаётся новый узел XML с атрибутами и подузлами, содержащими все необходимые описания. Имя тега и будет именем нашего элемента. Можно использовать включаемые файлы (с помощью #include <имя файла>), чтобы минимально менять оригинальный файл. теперь во время выполнения получаем объект худа так local hud = get_hud() и создаём наш элемент так local st = hud:AddCustomStatic(<имя элемента>, true) при этом создаётся окно типа CUIStatic по описанию из XML и автоматически размещается на худе. Возвращаемый объект имеет тип SDrawStaticStruct. Его описание class SDrawStaticStruct { float m_endTime; CUIStatic* wnd(); }; Здесь нам в основном интересен метод wnd, который возвращает указатель на созданный CUIStatic. Внимательно изучите возможности этого контрола, они довольно немаленькие. Удалить элемент можно так hud:RemoveCustomStatic(<имя элемента>) получить в любой момент можно так local st = hud:GetCustomStatic(<имя элемента>) хотя можно и просто запомнить ссылку на элемент, полученную при создании. Собственно всё. С помощью описания в XML можно изобразить что-то простое, но если вам нужна динамика или сложные элементы, то ничто не мешает разместить на созданном окне дополнительные дочерние окна с помощью AttachChild. При этом можно сделать описание в XML минимальным, фактически определив только координаты окна и более ничего, а всё, что требуется, сделать позже с помощью дочерних окон. Данный способ почти всем неплох, но у него есть один маленький недостаток. Все созданные таким образом элементы будут расположены под стандартными элементами худа. А иногда нужно создать элемент, который перекрывает стандартные индикаторы и диалоги. Для этого есть второй метод с использованием функций AddDialogToRender и RemoveDialogToRender. Последовательность работы такая: создаём любым методом окно любого типа wnd = <любое окно> размещаем его на худе так get_hud():AddDialogToRender(wnd) когда захотим, убираем с худа так get_hud():RemoveDialogToRender(wnd) Важное замечание: После помещения окна на худ таким способом обязательно надо как-то сохранить ссылку на объект окна вплоть до его удаления с худа. Если потерять ссылку, то сборщик мусора удалит окно, и игра рухнет. Ещё замечание: и первым и вторым способом можно размещать на худе сколь угодно сложные окна, в том числе с кнопками, полями ввода и прочим в этом роде. Но естественно, они не будут реагировать на пользователя, т.е. работать будут только на вывод. Теперь о диалоговом режиме. Здесь всё вертится вокруг класса CUIScriptWnd. Основная идея заключается в создании на основе этого класса своего скриптового. Не буду в подробностях это описывать (может потом как-нибудь). Есть масса примеров, то же главное меню сделано именно так (файл ui_main_menu.script). В качестве наиболее простого и наглядного примера рекомендую ui_numpad.script. Это - диалоговое окно с панелью ввода кода двери. Оно простое и вместе с тем имеет все необходимые элементы: кнопки, поле ввода, обработку мышиных событий и нажатий клавиатуры. В общем, стоит его для начала внимательно изучить. Я сейчас только рассмотрю вывод созданного окна на экран. В случае с главным меню его запускает сам движок. Прописывание пользовательского класса в этом случае делается через регистрацию клиентского класса в class_registrator.script. Это там всегда уже сделано и это единственное окно, которое открывается таким образом. Все остальные пользовательские окна надо открывать самому. Это делается по-разному в разных версиях движка. В ТЧ Допустим у вас есть скриптовый класс CMyDialog, сделанный на основе CUIScriptWnd. Сначала вы создаёте объект такого класса local dlg = CMyDialog() -- конструктор может быть и с параметрами, поскольку вы его сами написали затем запускаем диалог level.start_stop_menu(dlg, true/false) или так dlg:GetHolder():start_stop_menu(dlg, true/false) разницы никакой, это фактически одна и та же функция. Второй аргумент определяет, будут ли убраны стандартные элементы худа: индикаторы и прочее. закрыть диалог можно вызвав ту же функцию второй раз, второй булевский аргумент при этом значения не имеет. ЧН я не рассматриваю, но там вроде похоже на ТЧ. В ЗП всё ещё проще, у самого диалога есть нужные методы ShowDialog и HideDialog. Сначала как обычно создаём объект диалога local dlg = CMyDialog() затем запускаем его dlg:ShowDialog(true/false) -- аргумент как и раньше позволяет скрыть индикаторы закрываем диалог dlg:HideDialog() Вот и всё. Остальные подробности про диалоги смотри в примерах. В неохваченном осталась тема о создании окон на основе XML описания. Для этого есть класс CScriptXmlInit. Он сам по себе несложен, но к нему надо ещё и описывать форматы XML файлов для разных окон, а к этому я сейчас морально не готов =) Также есть ещё достаточно сложная тема о модификации стандартных окон: торговли, PDA и прочего. Здесь на помощь может прийти функция level.main_input_receiver(), которая возвращает текущее активное окно. Приемы работы в этом случае достаточно нетривиальны. Кроме того, в ЗП этой функции нет. Может как-нибудь и дойдут руки... Изменено 29 Июля пользователем Kirgudu 1 Плагины Total Commander для работы с игровыми архивами: Архиваторный плагин (для работы с одиночным архивом): link1 link2 Системный плагин (для распаковки установленной игры): link1 link2 Ссылка на комментарий
Malandrinus 615 Опубликовано 12 Ноября 2010 Автор Поделиться Опубликовано 12 Ноября 2010 В ТЧ и ЧН были глобальные функции GetTextureInfo, GetTextureName и GetTextureRect. Это значит по имени текстуры получить ее файл (вроде как это еще полотном называют) и координаты прямоугольника. Напоминаю, что в таком понимании текстура это то, что обычно указывается в XML описаниях разных окошек. Там как правило прописывается имя, которое ссылается на отдельное описание (в другом XML файле), где уже и задается имя файла и координаты прямоугольника. Эти функции как раз и позволяют получить эту информацию. Особой пользы от этих функций не было, поскольку не было ни одной функции, которая возвращала бы имя текстуры. И вот в ЧН такая функция появилась! Для онлайновых объектов сталкеров стало возможно получить иконку персонажа с помощью функции character_icon. Это очень нужная функция, поскольку дает информацию о реальном профиле сталкера. Так и что вы думаете! В ЗП разрабы взяли и убрали функции получения информации о текстурах. И какой теперь толк от той функции получения иконки? XML прочитать нельзя, а иначе логическое имя ни о чем не говорит. Нет слов, одни междометья. Плагины Total Commander для работы с игровыми архивами: Архиваторный плагин (для работы с одиночным архивом): link1 link2 Системный плагин (для распаковки установленной игры): link1 link2 Ссылка на комментарий
DimOriN 35 Опубликовано 14 Ноября 2010 Поделиться Опубликовано 14 Ноября 2010 Ребят, где можно почитать о классе reader ? Ссылка на комментарий
Malandrinus 615 Опубликовано 14 Ноября 2010 Автор Поделиться Опубликовано 14 Ноября 2010 DimOriN, reader похож на net_packet только без функций записи. net_packet я расписывал здесь. Но на самом-то деле класс ведь примитивный. По именам методов и так ясно, что они делают. А что за задача стоит? Плагины Total Commander для работы с игровыми архивами: Архиваторный плагин (для работы с одиночным архивом): link1 link2 Системный плагин (для распаковки установленной игры): link1 link2 Ссылка на комментарий
DimOriN 35 Опубликовано 14 Ноября 2010 Поделиться Опубликовано 14 Ноября 2010 Проблема понимания сего класса в следующем local game_difficulty = reader:r_u8() затем следом local stored_input_time = reader:r_u8() вот не укладывается у меня в голове - как так 2 разных переменных с разными значениями равны reader:r_u8() надо для "пробы" вскрытия файлов *.sav Ссылка на комментарий
Real Wolf 34 Опубликовано 14 Ноября 2010 Поделиться Опубликовано 14 Ноября 2010 Возник вопрос: Как правильно присоединить окно класса CuiScriptWnd к инвентарю через функцию level.main_input_receiver()? А то как ни пробывал, ничего вразумительного не получалось. Ссылка на комментарий
Kolmogor 5 Опубликовано 14 Ноября 2010 Поделиться Опубликовано 14 Ноября 2010 Проблема понимания сего класса в следующем local game_difficulty = reader:r_u8() затем следом local stored_input_time = reader:r_u8() вот не укладывается у меня в голове - как так 2 разных переменных с разными значениями равны reader:r_u8() нет-пакеты же ты понимаешь? или нет? Функция r_u8() читает один байт и передвигает текущую позицию на один байт вперед.Повторный вызов r_u8() прочитает следующий байт. Все точно также как с обычными файлами надо для "пробы" вскрытия файлов *.sav Там все просто - пожаты обычным сталкеровским методом - разжимаешь - там чанки с разным содержимым: ид чанка: 0x0 - хранится версия alife 0x1 - идет ссылка на all.spаwn, может еще что 0x2 - нет-пакеты спавн-объектов 0x5 - 8! байт время, текущий тайм-фактор, нормал таймфактор 0x9 - инфопоршни, отношение между ГГ и группировками, статьи в пда, лог в пда, метки на карте, задания, статистика Добавлено через 4 мин.: Возник вопрос: Как правильно присоединить окно класса CuiScriptWnd к инвентарю через функцию level.main_input_receiver()? А то как ни пробывал, ничего вразумительного не получалось. Алгоритм простой: - ждешь пока откроется инвентарь, ловишь ui_inventory в info_callback - получаешь его окно через level.main_input_receiver() - аттачишь свое окно AttachChild Лучше скажи, что именно и как именно не получалось. Возможно стоит перейти в ковырялку Ссылка на комментарий
Malandrinus 615 Опубликовано 14 Ноября 2010 Автор Поделиться Опубликовано 14 Ноября 2010 DimOriN, local game_difficulty = reader:r_u8() local stored_input_time = reader:r_u8() как так 2 разных переменных с разными значениями равны reader:r_u8() у reader есть некий указатель внутри, который смещается при каждом чтении. Всякий раз читает новое значение и смещается. При следующем чтении читается уже другое значение. Всё-таки почитай про net_packet. Там очень похоже. Real Wolf, Как правильно присоединить окно класса CuiScriptWnd к инвентарю через функцию level.main_input_receiver()? Хлопотное это дело. Потом, не уверен, что стоит пытаться присоединять к одному диалогу другой. Лучше отдельные контролы. Безвылетную технологию для этого я описывал здесь. Плагины Total Commander для работы с игровыми архивами: Архиваторный плагин (для работы с одиночным архивом): link1 link2 Системный плагин (для распаковки установленной игры): link1 link2 Ссылка на комментарий
Kolmogor 5 Опубликовано 14 Ноября 2010 Поделиться Опубликовано 14 Ноября 2010 Потом, не уверен, что стоит пытаться присоединять к одному диалогу другой. Лучше отдельные контролы. Без скриптового окна не получишь события от своих контролов(по крайней мере у меня не получалось - может и сам накосячил). То есть если нужен только вывод информации, можно напрямую контролы аттачить. Если еще и ввод, то без скриптового окна никак Ссылка на комментарий
Real Wolf 34 Опубликовано 14 Ноября 2010 Поделиться Опубликовано 14 Ноября 2010 Лучше скажи, что именно и как именно не получалось. Возможно стоит перейти в ковырялку Нужно к инвентарю приаттачить кнопку, при нажатии, которой происходит действие, соответственно. Вот только у класса кнопки нет действия на нажатие(по крайней мере я не нашёл), поэтому начал делать через класс CuiScriptWnd, вот только он остаётся активным, а инвентарь нет, или инвентарь работает и кнопка, но нет иконок в инвентаре и слотах, иконка ГГ в костюме работает. Описания тоже. Ссылка на комментарий
Malandrinus 615 Опубликовано 14 Ноября 2010 Автор Поделиться Опубликовано 14 Ноября 2010 (изменено) Kolmogor, я понимаю. Скриптовое окно в этом случае надо завести "рядом" и присоединять кнопки на движковй диалог, а колбеки перенаправить в это отдельное окно. Потом не забыть отсоединить кнопки от движкового окна и просединить к скриптовому для корректного удаления. Проблемы начнуться если "забыть" кнопку на движковом окне, поскольку она там останется вплоть до выхода из программы. Real Wolf, таки прочитай тот старый пост, что я привёл. Там именно твоя проблема и решалась. Изменено 14 Ноября 2010 пользователем malandrinus Плагины Total Commander для работы с игровыми архивами: Архиваторный плагин (для работы с одиночным архивом): link1 link2 Системный плагин (для распаковки установленной игры): link1 link2 Ссылка на комментарий
Рекомендуемые сообщения
Создайте аккаунт или авторизуйтесь, чтобы оставить комментарий
Комментарии могут оставлять только зарегистрированные пользователи
Создать аккаунт
Зарегистрировать новый аккаунт в нашем сообществе. Это несложно!
Зарегистрировать новый аккаунтВойти
Есть аккаунт? Войти.
Войти