Hardtmuth 5 525 Опубликовано 21 июля, 2020 Справочник по функциям и классам Такая тема уже давно существует на АМК форуме, и курирует ее malandrinus, но по выводам из ответов/вопросов в теме Модострой: Вопросница (и не только), я понял, что у многих не доходят руки покопать в интернете и найти всем известный АМК форум... потому решил создать такую же тему, здесь... Но так как там вся информация идет не организована и в разброс, здесь я сделаю всю информацию в шапке темы и под спойлерами: Слова автора темы на AMK: Цитата В данной теме собраны сведения по скриптовой модели сталкера: функции и классы, методы и свойства, взаимосвязь классов и последовательность работы с ними, связь работы классов и файлов конфигураций. К наполнению темы приглашаются все желающие. В наполнении темы непосредственно участвовали и существенно мне помогли: Monnoroch, Kolmogor, Unnamed Black Wolf, меченый (стрелок), IQDDD, Kirag, Taroz, dan, lekzd, 7.9, Garry_Galler, AKKK1, Bak и много других людей. Оглавление Основы: Класс alife_simulator. Базовые операции с серверными объектами: Спойлер Класс нужен для выполнения самых базовых задач на серверной стороне: создание и удаление объектов, поиск объектов по идентификаторам, перевод в онлайн/оффлайн, проверка инфопорций. Из этого ряда странным образом выбивается получение номера текущего уровня. Объект такого класса всего один и может быть получен глобальной функцией alife(). Используем примерно так: local sim = alife() -- получаем сам объект класса alife_simulator local sactor = sim:actor() -- получаем серверный объект для актора Формальное описание: class alife_simulator { float switch_distance(); // получить дистанцию переключения онлайн/оффлайн void switch_distance(float dist); // установить дистанцию. Не работает! int level_id(); // номер текущего уровня string level_name(int level_id) // возвращает имя уровня по его id cse_abstract* create(string <имя секции объекта>, vector* position, int level_vertex_id, int game_vertex_id) // создание объектов на уровне cse_abstract* create(string <имя секции объекта>, vector* position, int level_vertex_id, int game_vertex_id, int parent_id) // создание объектов в инвентаре cse_abstract* create_ammo(string <имя секции патронов>, vector* position, int level_vertex_id, int game_vertex_id, int parent_id, int amount) // создание пачек с патронами cse_alife_dynamic_object* create(int <индекс объекта в all.spawn> ) // создание объекта на основе секции в all.spawn int spawn_id(int id) // индекс секции в all.spawn для объекта с заданным id void release(cse_abstract* obj, bool); // удаление объекта. cse_alife_dynamic_object* object(int id, bool no_assert); // получение объекта по id. cse_alife_dynamic_object* object(int id); // эквивалентно предыдущей функции с no_assert == true. cse_alife_dynamic_object* object(string name); // получение объекта по имени. В ЗП нет! cse_alife_dynamic_object* story_object(int story_id); // получения объекта по сюжетному идентификатору cse_alife_creature_actor* actor(); // получение серверного объекта актора. Можно и просто получить его по id, равному 0 bool valid_object_id(int id); // проверяет, что аргумент не равен 65535 (-1). На редкость бесполезная функция. void set_switch_online(int id, bool v); // устанавливает флажок flSwitchOnline, который определяет возможность перехода в онлайн void set_switch_offline(int id, bool v); // устанавливает флажок flSwitchOffline, который определяет возможность перехода в оффлайн void set_interactive(int id, bool v); // устанавливает флажок flInteractive bool has_info(int id, string info_portion); // проверяет наличие инфопоршена bool dont_has_info(int id, string info_portion); // проверяет отсутствие инфопоршена void add_out_restriction(cse_alife_monster_abstract* obj, int restrictor_id); // установка ограничения на выход void add_in_restriction(cse_alife_monster_abstract* obj, int restrictor_id); // установка ограничения на вход void remove_out_restriction(cse_alife_monster_abstract* obj, int restrictor_id); // снятие ограничения на выход void remove_in_restriction(cse_alife_monster_abstract* obj, int restrictor_id); // снятие ограничения на вход void remove_all_restrictions(int object_id, const enum RestrictionSpace::ERestrictorTypes type); // снятие всех ограничений либо на вход, либо на выход // Возможно, отвечают за убийство в оффлайне void kill_entity(cse_alife_monster_abstract* monster, int game_vertex_id, cse_alife_schedulable* obj); void kill_entity(cse_alife_monster_abstract* monster, int game_vertex_id); // эквивалентно первой функции с obj == 0 void kill_entity(cse_alife_monster_abstract* monster); // эквивалентно второй с game_vertex_id, равным gvid монстра, переданного в первом аргументе }; Комментарии к некоторым функциям: Спойлер void switch_distance(float dist); - функция для установки онлайн-радиуса. У меня всегда вызывает вылет. Впрочем, этот радиус можно изменить в файле конфигурации alife.ltx секции [alife]. Там параметр switch_distance. Там-же есть параметр гистерезиса перехода switch_factor.string level_name(int level_id) - функция возвращает системное имя уровня, например "L01_Escape" для Кордона. В списке строк для многих уровней есть внятные имена. Их можно получить так:local level_name = game.translate_string(string.lower(alife():level_name(level_id))) Функция create с аргументом parent_id, позволяет создавать только инвентарные предметы. Аргумент amount функции create_ammo задаёт количество патронов в пачке. Пачка всегда создаётся одна. Номер секции в файле all.spawn для функции create с одним аргументом и spawn_id - это просто порядковый номер расположения объекта в all.spawn. Имеет тенденцию меняться после перепаковки с помощью acdc. Функции create возвращают созданный объект. Однако он приведён к типу cse_abstract, и с ним возможны не все операции. Лучше после создания объекта получить объект заново, используя одну из функций поиска объектов. С функцией release требуется осторожность. Некоторые объекты перед удалением надо переводить в оффлайн. Второй булевский аргумент этой функции игнорируется. Функции set_switch_online, set_switch_offline и set_interactive позволяют менять соответствующие флажки из поля object_flags. Флажки flSwitchOnline и flSwitchOffline периодически проверяются для каждого объекта и определяют возможность перехода в онлайн или оффлайн соответственно. Если они оба true, то объект будет переходить в онлайн/оффлайн автоматически при пересечении онлайн-радиуса. Комбинации true/false и false/true соответственно форсируют одно из состояний вне зависимости от расстояния до актора. Естественно, это всё имеет смысл при нахождении объекта на одном уровне с актором. Для некоторых объектов проверка осуществляется не этими флажками, а функциями can_switch_online и can_switch_offline, которые надо перегрузить в скриптовом серверном классе и, таким образом, управлять переключением. Собственно для остальных объектов управление также осуществляется этими функциями, просто они по дефолту возвращают значения этих флажков. С флажком flInteractive я не экспериментировал, только выяснил, что функция interactive возвращает true, если установлены в 1 три флажка: flInteractive, flVisibleForAI и flUsefulForAI. Это имеет смысл для НПС, но какой именно - пока не выяснял. В функциях для управления ограничениями надо передавать id рестрикторов. У рестрикторов имеется собственное поле типа, но, как мне показалось, в данных функциях собственный тип рестриктора игнорируется. В функции remove_all_restrictions второй аргумент type определяет, какие именно ограничения надо удалить. Допустимые значения для этой функции: 4 - in, 5 - out. Подробнее о типах рестрикторов: Спойлер Их всего шесть, что определяется вот таким перечислением: enum RestrictionSpace::ERestrictorTypes { eDefaultRestrictorTypeNone, // 0 eDefaultRestrictorTypeOut, // 1 eDefaultRestrictorTypeIn, // 2 eRestrictorTypeNone, // 3 eRestrictorTypeIn, // 4 eRestrictorTypeOut, // 5 }; Можно обратить внимание, что в all.spawn никогда нет рестрикторов с типами 4 и 5. Не бывает также и типа 1. В целом можно сделать ряд предположений: - тип рестриктора 0 или 3 - это как бы "не рестриктор" вообще, и используются в основном для скриптовых зон, где движок ни за что не отвечает, а все проверки выполняются скриптами. - только типы рестриктора 1 и 2 имеют смысл для движка и, по всей видимости, приводят к созданию зон "куда все не ходят" - зоны "откуда всем ходу нет" очевидно лишены смысла, поэтому и не встречается в природе тип 1 - что касается типов 4 и 5, то это выходит не типы рестрикторов, а специальные константы для функции. Зачем их поместили в это-же перечисление, не знаю. Ещё раз, выглядит так, использовать можно рестрикторы с любым типом (поскольку, как я говорил, тип их не проверяется). Обратите также внимание, что у класса game_object имеются функции, также отвечающие за управление ограничениями. Назначение всех вариантов функции kill_entity неясно. Вроде бы отвечают за убийство в оффлайне, но у меня стабильно вызывали вылет. Пространства имён. Глобальные функции для большого числа задач: Вступление: Спойлер Глобальные фунции или иначе функции из пространств имён. Такая функция в любом месте вызывается следующим образом:<пространство имён>.<имя функции>(<список аргументов>) Пространства имён - это всего лишь способ сгруппировать функции по некоторому признаку. Хотя надо заметить, что логика группировки функций в сталкере иной раз не поддаётся объяснению. Всего есть несколько пространств имён: безымянное (т.е. функции из него вызываются просто по именам как обычные глобальные функции), game, level, relation_registry, actor_stats. В ЧН (и ЗП) появилось пространство имён main_menu, кроме того есть незначительные изменения в остальных: некоторые функции исчезли, некоторые добавлены. Изменения однако незначительны. Сейчас рассматриваем только три основных пространства имён (безымянное, game, level) и только для ТЧ. Безымянное пространство имён: Спойлер Функции, которые не работают, вызывают вылеты или непонятно их назначение: function log(string) -- видимо для дебаговой версии function error_log(string) -- видимо для дебаговой версии function flush() -- видимо для дебаговой версии bool app_ready() -- готовность чего-то к чему-то ? пока игра не загружена, у возвращает false, после загрузки - true bool editor() -- под редактором??? Это то, чего нам как ушей не видать??? int script_server_object_version() -- число, знать бы что означает function verify_if_thread_is_running() function xrRender_test_r2_hw() Получение некоторых глобальных объектов: alife_simulator* alife() -- см. описание alife_simulator render_device* device() -- см. описание render_device CGameGraph* game_graph() -- получение глобального графа игры CConsole* get_console() -- получение объекта для управления консолью. Это и так все знают CUIGameCustom* get_hud() -- получение объекта для управления худом. Можно добавлять к худу свои окошки и элементы управления. Так делают всякие индикаторы. FS* getFS() -- файловые операции. см. описание FS string command_line() -- командная строка, включая полный путь к исполняемому файлу string user_name() -- сетевое имя игрока (вроде бы имя активного пользователя в системе) cef_storage* ef_storage() -- хз что такое Работа с файлами конфигурации: ini_file* create_ini_file(string) -- создаёт из строки объект типа ini_file в памяти ini_file* game_ini() -- открытый файл "config\game.ltx" и все его вложения ini_file* system_ini() -- открытый файл "config\system.ltx" и все его вложения Побитовые операции: function bit_and(number, number) function bit_not(number) function bit_or(number, number) function bit_xor(number, number) function dik_to_bind(number) -- я подозреваю, что преобразует константу из набора DIK_keys в константу из набора key_bindings DWORD GetARGB(number, number, number, number) -- формирует 32-х разрядное целое из 4-х отдельных байт. для задания цвета. Где используется - точно не известно. Всякий мелкий утиль: void prefetch(string <имя модуля>) -- вызывает загрузку и прекомпиляцию модуля. Имя модуля указывается без расширения ".script" int time_global() -- реальное время (в миллисекундах) с начала запуска программы void buy_condition(ini_file*, string <имя секции>) -- прочитать настройки торговца, на покупку из файла конфигурации и определённой секции. Только непонятно, для кого читаются эти настройки void buy_condition(float, float) -- непонятная функция. void sell_condition(ini_file*, string <имя секции>) -- аналогично на продажу void sell_condition(float, float) -- непонятная функция void show_condition(ini_file*, string <имя секции>) -- совсем непонятно Далее описанные функции позволяют преобразовать ссылку на базовый класс в ссылку на производный для получения доступа к методам производного класса за деталями надо обращаться в описание соответствущих иерархий. надеюсь, руки до этого дойдут: action_planner* cast_action_to_planner(action_base*) action_base* cast_planner_to_action(action_planner*) cse_alife_creature_abstract* cast_alife_object_to_creature(cse_alife_object*) cse_alife_trader_abstract* cast_alife_object_to_trader_abstract(cse_alife_object*) Получение встроенных шрифтов: CGameFont* GetFontDI() CGameFont* GetFontGraffiti19Russian() CGameFont* GetFontGraffiti22Russian() CGameFont* GetFontGraffiti32Russian() CGameFont* GetFontGraffiti50Russian() CGameFont* GetFontLetterica16Russian() CGameFont* GetFontLetterica18Russian() CGameFont* GetFontLetterica25() CGameFont* GetFontMedium() CGameFont* GetFontSmall() Некая информация о текстурах. В ЗП эти функции убраны: CGameFont* GetTextureInfo(string, string) CGameFont* GetTextureName(string) CGameFont* GetTextureRect(string) Пространство имён game: Спойлер CTime* get_game_time() -- возвращает игровое время в виде объекта класса CTime void start_tutorial(string) -- запускает туториал, зарегистрированный в файле ui\game_tutorials.xml. В частности, на туториалах сделаны сны bool has_active_tutorial() -- запущен ли туториал int time() -- игровое время (в игровых миллисекундах) с начала игры (т.е. с начала прохождения игры) string translate_string(string) -- получает вменяемую строку по её строковому идентификатору из одного из xml файлов, прописанных в файле \config\localization.ltx в секции [string_table] в параметре files если там такой строки нет, то возвращает свой аргумент - исходную строку Пространство имён level: Спойлер Функции неопределённые или вызывающие непонятные вылеты: function check_object(game_object*)-- выглядит хитро. Как бы поле level.check_object есть и тип его "function" однако значение этого поля nil и вызов его невозможен. Т.е. такой функции на самом деле нет, видимо была в отладочной версии. function debug_actor() -- аналогично check_object. Нет такой функции function debug_object(string) -- аналогично check_object. Нет такой функции function physics_world() -- в ТЧ - вылет function environment() -- в ТЧ - вылет Вылета не вызывают, но назначение неясно: int game_id() -- возвращает некое число (у меня 1). Вероятно для мультиплея. client_spawn_manager* client_spawn_manager() -- возвращает некий объект, с помощью которого можно ставить некие коллбеки на спаун. В игре нигде не используется Информация об уровне в целом, управление уровнем в целом: bool present() -- наличие уровня. Так можно определять, что игра загружена. Т.е. если мы в главном меню и игра не загружена, то функция возвращает false string name() -- имя текущего уровня, точнее его идентификатор Fbox* get_bounding_volume() -- даёт некий параллелепипед, видимо охватывающий уровень Коллбеки: void add_call(const function&, const function&)-- устанавливаются два коллбека: первый. Аргументов нет, вызывается периодически непосредственно после апдейта актора должен возвращать false до тех пор, пока не решит прекратить работу. второй. Аргументов нет, вызывается один раз сразу после последнего вызова первого коллбека (после того, как тот вернёт true) поскольку частота вызовов совпадает с апдейтами актора, то можно сделать вывод, что коллбек ставится на актора void remove_call(const function&, const function&) -- по идее должно убирать коллбеки, но как-то не работает void add_call(object, const function&, const function&) -- аналогично для произвольного объекта, но теперь в качестве первого аргумента колбека при его вызове передаётся тот объект, на который его ставили void remove_call(object, const function&, const function&) void add_call(object, string, string) -- непонятно, как работает. Пытался передать имя функции, но это не сработало. void remove_call(object, string, string) void remove_calls_for_object(object) Эффекторы: float add_cam_effector(string <имя анимации>, int <идентификатор>, boolean <зациклить>, string <коллбек на окончание>) string <имя анимации> -- имя файла *.anm, адресуемого от папки anims int <идентификатор> -- произвольное целое число, которое можно использовать для удаления boolean <зациклить> -- проигрывать бесконечно string <коллбек на окончание> -- имя функции, которая выполнится по окончании действия эффекта. Функция не принимает аргументов и не возвращает значений. Не вызывается при принудительном завершении эффектора функцией remove_cam_effector. Функция возвращает некое число, для каждого файла анимации своё. Зачем нужно - не знаю. float add_cam_effector2(string, number, boolean, string) -- в целом тоже самое, что и предыдущая функция. Видимая разница в том, что предыдущая смещала позицию камеры от текущего положения актора, а эта сначала перемещает камеру актора в некую стартовую позицию. void remove_cam_effector(number <идентификатор>) -- убрать эффектор с ранее заданным номером void add_pp_effector(string <имя постэффекта>, int <произвольный идентификатор>, boolean <зациклить>) string <имя постэффекта> -- имя файла *.ppe, адресуемого от папки anims int <произвольный идентификатор> -- для дальнейшего удаления boolean <зациклить> -- проигрывать бесконечно void set_pp_effector_factor(int <идентификатор>, float <интенсивность>) int <идентификатор> -- число, ранее заданное при установке эффекта float <интенсивность> -- (0, 1) -- интенсивность эффекта void set_pp_effector_factor(int <идентификатор>, float <интенсивность>, number <скорость изменения>) int <идентификатор> float <интенсивность> number <скорость изменения> -- не до конца ясно, но вроде как скорость перехода от текущего состояния к заданному. По какому принципу считается время перехода - непонятно void remove_pp_effector(int <идентификатор>) -- убрать эффект Следующие две функции практически не используются. Задействованы незначительно только в ЗП void add_complex_effector(string <секция>, int <идентификатор>) string <секция> -- имя секции в system.ltx, с описанием эффекта int <идентификатор> void remove_complex_effector(int <идентификатор>) -- отмена эффектора Функции времени: int get_time_days() -- день месяца по игровому времени int get_time_hours() -- час текущего игрового дня int get_time_minutes() -- минута текущего игрового часа float get_time_factor() -- возвращает отношение скорости течения игрового времени к скорости реального (game_time_speed / real_time_speed) void set_time_factor(number) -- устанавливает это отношение. Фактор времени в целом не сказывается на физике мира. Т.е. скорость движения объектов остаётся естественной. Пули летят с той же скоростью, что и раньше. Люди и монстры бегают как и раньше. На чём точно сказывается фактор времени - это на смене дня и ночи. Установив его очень большим можно воочию наблюдать смену дня и ночи в течении пары минут. Погода: string get_weather() -- получить идентификатор текущей погоды void set_weather(string , boolean ) -- устанавливает погоду. Идентификатор погоды должен присутствовать в файле config\weathers\environment.ltx в сеции [weathers] иначе вылет второй параметр отвечает за немедленную смену погоды если true - меняем прямо сейчас если false - то непонятно. У меня также менялось сразу. void set_weather_fx(string) -- устанавливает погодный эффект, описанный в файле weathers\environment.ltx в секции [weather_effects]. Это всякие молнии, ветер с туманом, затемнения и пр. Так в частности сделан выброс bool is_wfx_playing() -- соответственно проигрывается ли сейчас погодный эффект float rain_factor() -- степень дождливости. Зависит от выбранной погоды. Меняется видимо автоматически HUD и интерфейс: function start_stop_menu(CUIDialogWnd*, boolean) -- в ЗП убрана. Эти функции практически не используются. Открытие окон делается через объект худа function add_dialog_to_render(CUIDialogWnd*) function remove_dialog_to_render(CUIDialogWnd*) CUIWindow* main_input_receiver() -- Возвращает открытое окно(инвентаря, торговли, ПДА, диалога) С ее помощью к стандартным окнам можно добавить новые элементы. В ЗП отсутствует! (спасибо Колмогору за дополнение) void show_indicators() -- показывает индикаторы и прицел void hide_indicators() -- прячет индикаторы и прицел void disable_input() -- блокирует мышь и клавиатуру void enable_input() -- разблокирует мышь и клавиатуру float get_snd_volume() -- уровень звука (0,1) с ползунками в опциях не связано void set_snd_volume(number) -- установить уровень звука (0,1) ESingleGameDifficulty get_game_difficulty() -- сложность игры, с ползунками в опциях не связано void set_game_difficulty(enum ESingleGameDifficulty) -- установить сложность игры Перечисление ESingleGameDifficulty экспортировано как класс game_difficulty Его описание: C++ class game_difficulty { const novice = 0; const stalker = 1; const veteran = 2; const master = 3; } т.е. вызываем функцию так: level.set_game_difficulty(game_difficulty.veteran) Работа с разными объектами на уровне: game_object* object_by_id(number) -- клиентский объект по его id (или nil, если объект не в онлайне или не существует) void spawn_phantom(const vector&) -- создаёт фантомного монстра в указанной точке (как на радаре) фантомный мостр начинает бежать к актору и добежав - исчезает function patrol_path_exists(string) function vertex_in_direction(number, vector, number) vector vertex_position(number) -- положение левел-вертекса по его номеру на каждом уровне свои вертексы. Нумерация на разных уровнях может (и вообще говоря обязательно будет) пересекаться function cover_in_direction(number, const vector&) Управление картой: void map_add_object_spot(int , string <тип метки>, string <надпись>) -- установить метку int -- идентификатор объекта string <тип метки> -- имя типа метки, зарегистрированное в файле config\ui\map_spots.xml и всех, что в него включены инклюдами string <надпись> -- надпись void map_add_object_spot_ser(int , string <тип метки>, string <надпись>) -- разница между этой и предыдущей функцией в том, что вторая ставит метку постоянно, или иными словами на серверный объект (потому и _ser в конце). При вызове вы сначала не заметите разницы, поскольку и та и другая функция поставят метку как на объект на текущем уровне, так и на любом другом. Однако после сохранения и загрузки метки, поставленные второй функцией останутся. Очевидно, каждая из функций полезна в своём случае: постоянные метки нужно ставить на тайники и квесты, а временные можно использовать к примеру для радаров и прочего в этом роде. void map_change_spot_hint(int , string <тип метки>, string <надпись>) -- сменить надпись на метке bool map_has_object_spot(int , string <тип метки>) -- проверить наличие метки void map_remove_object_spot(int , string <тип метки>) -- удалить метку Звук: function iterate_sounds(string, number, function) function iterate_sounds(string, number, object, function) function prefetch_sound(string) 2 1 Как оформить тему Правила форума Вопросы по сайту Личное пространство на Trello Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты