Нужна помощь?
Создайте тему в соответствующем разделе
Не нужно писать всё в чат!Загляните на торговую площадку
Там вы можете купить
всё что касается игровых серверовНе хотите бан?
Пожалуйста, ознакомьтесь с нашими правилами
Не нарушайте порядок!Продаёте или покупаете?
Пользуйтесь услугами гаранта
Мы сделаем вашу сделку безопасной
Таблица лидеров
Популярные публикации
Отображаются публикации с наибольшей репутацией на 05/10/22 в Сообщения
-
1 баллИ так, ребятки, вот вам небольшая 'полезняшка' от меня, и совершенно бесплатно! Описание: Скрипт, добавляющий админу сервера возможность указывать для каждого игрока индивидуальный скин спавна, его персональную точку спавна и один из имеющихся на сервере стартовых наборов с лутом, которые можно составить самим. Если указано несколько точек спавна и/или наборов лута, то будет выбран один из предложенных вариантов рандомно. Также, любой из названных параметров можно отключить в скрипте и сделать его стандартным, как он есть поумолчанию на сервере. Дополнительно - есть возможность назначить свой набор стартового лута для всех игроков на сервере не из списка скрипта! Нам понадобится: 1. Сервер DayZ 1.0, сделанный по одному из гайдов: 2. Notepad++ 3. Немножечко трезвого ума и понимания того, что мы делаем, и как прописывается лут на новом языке enfusion Установка: Перед установкой: Обратите внимание, что имя 'стандартной' миссии сервера при загрузки со Steam называется: 'dayzOffline.chernarusplus'. На хостингах имя этой папки может отличаться. Если это так, то вам в информации ниже необходимо заменить 'dayzOffline.chernarusplus' на имя вашей папки миссии сервера, иначе вы не сможете запустить сервер игры! 1. По пути: {папка с вашим сервером}\mpmissions\dayzOffline.chernarusplus\ создать папку 'CustomSpawnPlayerConfig' и поместить в созданную нами папку 3 файла из следующего архива CustomSpawnPlayerConfig.rar или создать их самим со следующим содержанием: Script.c /* Описание: Скрипт выдачи индивидуального стартового лута, скина игрока и точек спавна Автор: 123new Установка: 1. По пути: {папка с вашим сервером}\mpmissions\dayzOffline.chernarusplus\ создать папку 'CustomSpawnPlayerConfig' и поместить в нее 3 файла скрипта: Script.c Sets.c init_mod.c 2. В файле: {папка с вашим сервером}\mpmissions\dayzOffline.chernarusplus\init.c в самом верху файла добавить: #include "$CurrentDir:mpmissions\dayzOffline.chernarusplus\CustomSpawnPlayerConfig\init_mod.c" 3. В папке, обозначенной параметром запуска сервера '-profile=', поместить файл с именем CustomSpawnPlayerConfig.txt и заполнить его данными по следующему формату: UID|Skin_player|sets_numbers|points_spawns где UID - это steam64id от профиля игрока в steam Skin_player - точный id скина игрока (можно указать 0 для отключения опции) sets_numbers - номер сета со стартовым лутом (можно указать несколько через ';', указать один всего, либо указать 0 для отключения опции) points_spawns - координаты спавна игрока на карте в формате 'x y z' (можно указать несколько через ';', указать всего одну точку, либо указать 0 для отключения опции) Пример: 76561198141889254|SurvivorM_Oliver|1|12955.091797 16.115206 7993.588379 76561198141889256|SurvivorM_Oliver|1;2|14791.965820 76.481781 14041.661133;12029.079102 196.356125 7274.689941 76561198141889253|SurvivorM_Oliver|0|0 4. В файле Sets.c в папке: {папка с вашим сервером}\mpmissions\dayzOffline.chernarusplus\CustomSpawnPlayerConfig\ настроить стартовый лут для ваших игроков и написать собственные сеты ВАЖНО: количество сетов можно делать любое, номера сетов брать от 1 и выше (не должно быть -1, либо 0, только от 1 и выше) Все что укажете в блоке default будет применено для всех игроков при респавне в случае, если им не выдан никакой сет! P.S. Прикрепить к соспавненному оружию магазин не получится, рабочего кода я не смог найти!! Если у вас папка активной миссии сервера отличается от dayzOffline.chernarusplus то переименуйте ее в строке, вписываемой в: {папка с вашим сервером}\mpmissions\dayzOffline.chernarusplus\init.c {папка с вашим сервером}\mpmissions\dayzOffline.chernarusplus\CustomSpawnPlayerConfig\init_mod.c */ class CustomSpawnPlayerConfig { private string Location_Directory_config = "$profile:"; // Расположение папки с конфигом скрипта private string Location_filename_config = "CustomSpawnPlayerConfig.txt"; // имя файла с конфигом скрипта private string default_log_block_name = "[CustomSpawnPlayerConfig] "; // Стандартный блок скрипта для идентификации с script.log private string disable_read_parameter = "0"; // Стандартное значение (без кавычек) для обозначения в файле конфига скрипта неиспользование параметра private string block_split_parameters_config = "|"; // Символ, обозначающий разделение параметров при чтении файла конфига private string block_split_multi_parameters_config = ";"; // Символ, обозначающий перечисление в одной ячейке параметра нескольких параметров при чтении файла конфига private bool enabled_loading_custom_spawnpoints = true; // Параметр, включающий и отключающий возможность использования приватной точки спавна для каждого игрока. В случае отключения кастомная точка спавна будет отключена для всех поумолчанию, вне зависимости от данных в конфиге! private bool enabled_loading_custom_sets = true; // Параметр, включающий и отключающий возможность использования приватного сета для каждого игроков. В случае отключения выдача сетов будет отключена для всех поумолчанию, вне зависимости от данных в конфиге, будет выдаваться только сет для всех игроков! private bool enabled_loading_custom_skins = true; // Параметр, включающий и отключающий возможность использования индивидуального стартового скина игрока для каждого игрока. В случае отключения эта возможность будет отключена для всех поумолчанию, вне зависимости от данных в конфиге! // ------------------------------------------------------------ // ---------------- NEXT CODE DON'T EDIT ----------------- // ------------------------------------------------------------ ref map<string, ref array<vector>> players_spawnpoints = new map<string, ref array<vector> >; ref map<string, ref array<int>> players_sets = new map<string, ref array<int> >; ref map<string, string> players_skins = new map<string, string>; private bool enabled_loaded_successfull_config = false; string Log_CustomSpawnPlayerConfig_GetDateTime() { private int year, month, day, hour, minute, second; GetYearMonthDay(year, month, day); GetHourMinuteSecond(hour, minute, second); string returned_message = "[" + day.ToStringLen(2) + "." + month.ToStringLen(2) + "." + year.ToStringLen(2) + " - " + hour.ToStringLen(2) + "." + minute.ToStringLen(2) + "." + second.ToStringLen(2) + "] "; return returned_message; } bool Check_coords_disable(vector coord) { private bool ret_zn = false; private float pos_x = coord[0]; private float pos_y = coord[1]; private float pos_z = coord[2]; if ((pos_x == 0.0) & (pos_y == 0.0) & (pos_z == 0.0)) { ret_zn = true; } return ret_zn; } vector Set_Read_coords_disable() { return Vector(0.0, 0.0, 0.0); } void CustomSpawnPlayerConfig() { Print(Log_CustomSpawnPlayerConfig_GetDateTime() + default_log_block_name + "CustomSpawnPlayerConfig initialize start!"); Read_Update_Config(); } void ~CustomSpawnPlayerConfig() { Print(Log_CustomSpawnPlayerConfig_GetDateTime() + default_log_block_name + "CustomSpawnPlayerConfig work end, class closed!"); } void Read_Update_Config() { private string name_block_work = "[ReadAndUpdateSettings] "; Print(Log_CustomSpawnPlayerConfig_GetDateTime() + default_log_block_name + name_block_work + " Started Reading config!"); private array<string> readed_lines_config = ReadFileConfig(); private bool check_normal_read = AnaliseFileConfig(readed_lines_config); if (check_normal_read) { LoadFileConfig(readed_lines_config); Print(Log_CustomSpawnPlayerConfig_GetDateTime() + default_log_block_name + name_block_work + "config readed successfull!"); enabled_loaded_successfull_config = true; } else { Print(Log_CustomSpawnPlayerConfig_GetDateTime() + default_log_block_name + name_block_work + "config read failed, work script disabled for players!"); enabled_loaded_successfull_config = false; } } array<string> ReadFileConfig() { private string name_block_work = "[ReadFileConfig] "; private array<string> readed_lines_config = new array<string>; readed_lines_config.Clear(); if (FileExist ( (Location_Directory_config + Location_filename_config) ) ) { private string line_content; FileHandle file = OpenFile((Location_Directory_config + Location_filename_config), FileMode.READ); Print(Log_CustomSpawnPlayerConfig_GetDateTime() + default_log_block_name + name_block_work + "Open file config: " + (Location_Directory_config + Location_filename_config)); if (file != 0) { while ( FGets( file, line_content ) > 0 ) { readed_lines_config.Insert( line_content); } CloseFile(file); } else { Print(Log_CustomSpawnPlayerConfig_GetDateTime() + default_log_block_name + name_block_work + "ERROR!!! CAN'T OPEN FILE CONFIG : " + (Location_Directory_config + Location_filename_config)); } //readed_lines_config.Debug(); } else { Print(Log_CustomSpawnPlayerConfig_GetDateTime() + default_log_block_name + name_block_work + "ERROR!!! CAN'T FOUND FILE CONFIG OR DIRECTORY: " + (Location_Directory_config + Location_filename_config)); } return readed_lines_config; } bool AnaliseFileConfig(array<string> readed_lines_config) { private bool return_zn = true; private string name_block_work = "[AnaliseFileConfig] "; if (readed_lines_config.Count() > 0) { foreach (string line : readed_lines_config) { if (line.Contains(block_split_parameters_config)) { private array<string> splited_line = new array<string>; line.Split( block_split_parameters_config, splited_line ); if (splited_line.Count() == 4) { private string UID_player = splited_line.Get(0); private string default_skin_player = splited_line.Get(1); private string sets_numbers_player = splited_line.Get(2); private string points_spawn_player = splited_line.Get(3); if ((UID_player == "") || (default_skin_player == "") || (sets_numbers_player == "") || (points_spawn_player == "")) { Print(Log_CustomSpawnPlayerConfig_GetDateTime() + default_log_block_name + name_block_work + "ERROR!!! Lines in Readed file is not correct, please, fix your config script!"); Print(Log_CustomSpawnPlayerConfig_GetDateTime() + default_log_block_name + name_block_work + "Line checking: " + line); return_zn = false; break; } } else { Print(Log_CustomSpawnPlayerConfig_GetDateTime() + default_log_block_name + name_block_work + "ERROR!!! Readed file is have incorrect count parameters with a tag '" + block_split_parameters_config + "', please, fix your config script!"); Print(Log_CustomSpawnPlayerConfig_GetDateTime() + default_log_block_name + name_block_work + "Line checking: " + line); return_zn = false; break; } } else { Print(Log_CustomSpawnPlayerConfig_GetDateTime() + default_log_block_name + name_block_work + "ERROR!!! Readed file can't have a tag '" + block_split_parameters_config + "', please, fix your config script!"); Print(Log_CustomSpawnPlayerConfig_GetDateTime() + default_log_block_name + name_block_work + "Line checking: " + line); return_zn = false; break; } } } else { Print(Log_CustomSpawnPlayerConfig_GetDateTime() + default_log_block_name + name_block_work + "ERROR!!! Config file is empty, fix your config script!"); return_zn = false; } return return_zn; } void LoadFileConfig(array<string> readed_lines_config) { private string name_block_work = "[LoadFileConfig] "; players_spawnpoints.Clear(); players_sets.Clear(); players_skins.Clear(); foreach (string line : readed_lines_config) { private array<string> splited_line = new array<string>; splited_line.Clear(); line.Split( block_split_parameters_config, splited_line ); private string UID_player = splited_line.Get(0); private string default_skin_player = splited_line.Get(1); private string sets_numbers_player = splited_line.Get(2); private string points_spawn_player = splited_line.Get(3); private array<vector> temp_players_spawnpoints = new array<vector>; temp_players_spawnpoints.Clear(); array<int> temp_players_sets = new array<int>; temp_players_sets.Clear(); array<string> temp_players_spawnpoints_string = new array<string>; temp_players_spawnpoints_string.Clear(); array<string> temp_players_sets_string = new array<string>; temp_players_sets_string.Clear(); if (points_spawn_player.Contains(block_split_multi_parameters_config)) { points_spawn_player.Split( block_split_multi_parameters_config, temp_players_spawnpoints_string ); } else { temp_players_spawnpoints_string.Insert(points_spawn_player); } foreach (string line_spawnpoint : temp_players_spawnpoints_string) { if (line_spawnpoint == disable_read_parameter) { temp_players_spawnpoints.Insert(Set_Read_coords_disable()); } else { temp_players_spawnpoints.Insert(line_spawnpoint.ToVector()); } } Print(Log_CustomSpawnPlayerConfig_GetDateTime() + default_log_block_name + name_block_work + "Generated massive for " + UID_player + " with " + temp_players_spawnpoints.Count().ToString() + " spawnpoints."); if (sets_numbers_player.Contains(block_split_multi_parameters_config)) { sets_numbers_player.Split( block_split_multi_parameters_config, temp_players_sets_string ); } else { temp_players_sets_string.Insert(sets_numbers_player); } foreach (string line_set : temp_players_sets_string) { if (line_set == disable_read_parameter) { temp_players_sets.Insert(0); } else { temp_players_sets.Insert(line_set.ToInt()); } } if (default_skin_player == disable_read_parameter) { default_skin_player = "0"; } Print(Log_CustomSpawnPlayerConfig_GetDateTime() + default_log_block_name + name_block_work + "Generated massive for " + UID_player + " with " + temp_players_sets.Count().ToString() + " sets."); Print(Log_CustomSpawnPlayerConfig_GetDateTime() + default_log_block_name + name_block_work + "Detected for " + UID_player + " skin " + default_skin_player); players_spawnpoints.Insert(UID_player,temp_players_spawnpoints); players_sets.Insert(UID_player,temp_players_sets); players_skins.Insert(UID_player,default_skin_player); } } vector Load_And_Check_Spawnpoints(PlayerIdentity identity, vector pos_default) { private string name_block_work = "[Load_And_Check_Spawnpoints] "; private vector retun_pos = pos_default; if(identity) { private string Name_P = identity.GetName(); private string UID_P = identity.GetPlainId(); private string Game_UID_P = identity.GetId(); private string Game_ID_P = identity.GetPlayerId().ToString(); if (enabled_loading_custom_spawnpoints) { if ((players_spawnpoints.Count() > 0) && (enabled_loaded_successfull_config)) { if (players_spawnpoints.Contains(UID_P)) { private array<vector> readed_lines_config = new array<vector>; readed_lines_config = players_spawnpoints.Get(UID_P); private vector retun_pos_check = readed_lines_config.GetRandomElement(); if (Check_coords_disable(retun_pos_check)) { Print(Log_CustomSpawnPlayerConfig_GetDateTime() + default_log_block_name + name_block_work + "For player " + Name_P + "(steam64id=" + UID_P + ") disabled loading private spawn point. Will be used default spawn point!"); } else { retun_pos = retun_pos_check; Print(Log_CustomSpawnPlayerConfig_GetDateTime() + default_log_block_name + name_block_work + "For player " + Name_P + "(steam64id=" + UID_P + ") setuped private spawn point: " + retun_pos.ToString()); } } else { Print(Log_CustomSpawnPlayerConfig_GetDateTime() + default_log_block_name + name_block_work + "Can't founded private spawnpoint for player " + Name_P + "(steam64id=" + UID_P + ")"); } } else { Print(Log_CustomSpawnPlayerConfig_GetDateTime() + default_log_block_name + name_block_work + "Config script is incorrect, checking private spawnpoints is disabled! Player: " + Name_P + "(steam64id=" + UID_P + ")"); } } else { Print(Log_CustomSpawnPlayerConfig_GetDateTime() + default_log_block_name + name_block_work + "disabled loading personal spawnpoints from config file script!"); } } Print(Log_CustomSpawnPlayerConfig_GetDateTime() + default_log_block_name + name_block_work + "For player " + Name_P + "(steam64id=" + UID_P + ") will be used spawn point: " + retun_pos.ToString()); return retun_pos; } string Load_And_Check_SpawnSkin_Player(PlayerIdentity identity, string characterName) { private string name_block_work = "[SelectStartSkinPlayer] "; private string retun_skin = characterName; if(identity) { private string Name_P = identity.GetName(); private string UID_P = identity.GetPlainId(); private string Game_UID_P = identity.GetId(); private string Game_ID_P = identity.GetPlayerId().ToString(); if (enabled_loading_custom_skins) { if (players_skins.Count() > 0) { if (players_skins.Contains(UID_P)) { private string readed_skin = players_skins.Get(UID_P); if (readed_skin == "0") { Print(Log_CustomSpawnPlayerConfig_GetDateTime() + default_log_block_name + name_block_work + "For player " + Name_P + "(steam64id=" + UID_P + ") disabled loading private skin setting, will be used default setting game!"); } else { retun_skin = readed_skin; Print(Log_CustomSpawnPlayerConfig_GetDateTime() + default_log_block_name + name_block_work + "For player " + Name_P + "(steam64id=" + UID_P + ") setuped private skin setting: " + retun_skin); } } else { Print(Log_CustomSpawnPlayerConfig_GetDateTime() + default_log_block_name + name_block_work + "Can't founded private skin setting for player " + Name_P + "(steam64id=" + UID_P + ")"); } } else { Print(Log_CustomSpawnPlayerConfig_GetDateTime() + default_log_block_name + name_block_work + "Config script is incorrect, checking private skin setting is disabled! Player: " + Name_P + "(steam64id=" + UID_P + ")"); } } else { Print(Log_CustomSpawnPlayerConfig_GetDateTime() + default_log_block_name + name_block_work + "disabled loading personal skin player settings from config file script!"); } } Print(Log_CustomSpawnPlayerConfig_GetDateTime() + default_log_block_name + name_block_work + "For player " + Name_P + "(steam64id=" + UID_P + ") will be used skin: " + retun_skin); return retun_skin; } void Load_And_Check_StartLoadout(PlayerBase player) { private string name_block_work = "[SelectStartSetPlayer] "; private int use_set_id = -1; private PlayerIdentity identity = player.GetIdentity(); if(identity) { private string Name_P = identity.GetName(); private string UID_P = identity.GetPlainId(); private string Game_UID_P = identity.GetId(); private string Game_ID_P = identity.GetPlayerId().ToString(); if (enabled_loading_custom_sets) { if ((players_sets.Count() > 0) && (enabled_loaded_successfull_config)) { if (players_sets.Contains(UID_P)) { private array<int> readed_lines_config = new array<int>; readed_lines_config.Clear(); readed_lines_config = players_sets.Get(UID_P); private int chek_use_set_id = readed_lines_config.GetRandomElement(); if (chek_use_set_id == 0) { Print(Log_CustomSpawnPlayerConfig_GetDateTime() + default_log_block_name + name_block_work + "For player " + Name_P + "(steam64id=" + UID_P + ") disabled loading private set numbers. Will be used default set player! "); } else { use_set_id = chek_use_set_id; Print(Log_CustomSpawnPlayerConfig_GetDateTime() + default_log_block_name + name_block_work + "For player " + Name_P + "(steam64id=" + UID_P + ") setuped private set number is: " + use_set_id.ToString()); } } else { Print(Log_CustomSpawnPlayerConfig_GetDateTime() + default_log_block_name + name_block_work + "Can't founded private sets for player " + Name_P + "(steam64id=" + UID_P + ")"); } } else { Print(Log_CustomSpawnPlayerConfig_GetDateTime() + default_log_block_name + name_block_work + "Config script is incorrect, checking private sets is disabled! Player: " + Name_P + "(steam64id=" + UID_P + ")"); } } else { Print(Log_CustomSpawnPlayerConfig_GetDateTime() + default_log_block_name + name_block_work + "disabled loading personal loadout sets player settings from config file script! Will be used default loadout!"); } if (use_set_id >= 0) { Print(Log_CustomSpawnPlayerConfig_GetDateTime() + default_log_block_name + name_block_work + "For player " + Name_P + "(steam64id=" + UID_P + ") will be used spawn set with number is: " + use_set_id.ToString()); } else { Print(Log_CustomSpawnPlayerConfig_GetDateTime() + default_log_block_name + name_block_work + "For player " + Name_P + "(steam64id=" + UID_P + ") will be used spawn default start set without number. "); } StartSetsPlayers.StartSetsPlayer(player, use_set_id); } } private array<EntityAI> GetItemListinobject(PlayerBase player,EntityAI item, bool check_player) { array<EntityAI> EntityAI_list_items = new array<EntityAI>; EntityAI_list_items.Clear(); int attIdx = 0; int attCount = 0; EntityAI item_in_object; if ((player) && (check_player)) { attCount = player.GetInventory().AttachmentCount(); for (attIdx = 0; attIdx < attCount; attIdx++) { item_in_object = player.GetInventory().GetAttachmentFromIndex(attIdx); if ( item_in_object.IsItemBase() ) { EntityAI_list_items.Insert(item_in_object); } } } if ((item) && !check_player) { attCount = item.GetInventory().AttachmentCount(); for (attIdx = 0; attIdx < attCount; attIdx++) { item_in_object = item.GetInventory().GetAttachmentFromIndex(attIdx); if ( item_in_object.IsItemBase() ) { EntityAI_list_items.Insert(item_in_object); } } } return EntityAI_list_items; } void RemoveAllItems (PlayerBase player) { private array<EntityAI> ItemListPlayer = new array<EntityAI>; private array<EntityAI> ItemsForDelete = new array<EntityAI>; private EntityAI itemInHands_player = player.GetHumanInventory().GetEntityInHands(); if (itemInHands_player != NULL) { if (player.CanDropEntity(itemInHands_player) && player.GetHumanInventory().CanRemoveEntityInHands()) { // Print("ItemForDelete: " + itemInHands_player.ToString()); ItemsForDelete.Insert(itemInHands_player); } } ItemListPlayer = GetItemListinobject(player,NULL,true); if (ItemListPlayer.Count() > 0) { foreach(EntityAI ItemPlayer: ItemListPlayer) { private array<EntityAI> ItemInItemInInventory = GetItemListinobject(NULL,ItemPlayer,false); private CargoBase cargo = ItemPlayer.GetInventory().GetCargo(); if(cargo) { if (cargo.GetItemCount() > 0) { for (int f = 0; f < cargo.GetItemCount(); f++) { if(cargo.GetItem(f)) { ItemsForDelete.Insert(cargo.GetItem(f)); } } } } if (ItemInItemInInventory.Count() > 0) { foreach(EntityAI items_temp: ItemInItemInInventory) { if(items_temp) { ItemsForDelete.Insert(items_temp); } } } if(ItemPlayer) { ItemsForDelete.Insert(ItemPlayer); } } } if (ItemsForDelete.Count() > 0) { foreach(EntityAI item_temp: ItemsForDelete) { if(item_temp) { GetGame().ObjectDelete(item_temp); } } } } }; Sets.c class StartSetsPlayersConfig { void StartSetsPlayer(PlayerBase player,int use_set_id) { EntityAI itemCreated = NULL; EntityAI itemCreated1 = NULL; ItemBase itemCasted = NULL; switch( use_set_id ) //Раздаем лут (можно использовать значения от 1 и выше, только не 0 и не -1) { case 1: //Set with number 1 (Сет с номером 1) { My_Custom_Spawn_Parameters.RemoveAllItems(player); // Чтобы удалить с персонажа уже имеющиеся стандартные стартовые шмотки раскомментировать строку itemCreated = player.GetInventory().CreateInInventory("CoyoteBag_Green"); // Выдаем рюкзак и записываем в переменную itemCreated if (itemCreated) // Проверяем, создался ли рюкзак. Если он создался, переменная itemCreated будет не пуста и проверка пройдет { SetRandomHealthItem(itemCreated); // Выдаем рюкзаку рандомное качество itemCreated1 = itemCreated.GetInventory().CreateInInventory("Apple"); // Добавляем в инвентарь созданного рюкзака яблоко и записываем в переменную itemCreated1 if (itemCreated1) // Проверяем, создалось ли яблоко в рюкзаке, яблоко у нас с переменной itemCreated1 { SetRandomHealthItem(itemCreated1); // Выдаем яблоку рандомное качество } itemCreated1 = NULL; // Обнуляем значение переменной после работы с ней, чтобы следующая проверка прошла корректно itemCreated1 = itemCreated.GetInventory().CreateInInventory("Rag"); // Выдаем игроку бинты в рюкзак и записываем в переменную itemCreated1 if (itemCreated1) // Проверяем, создались ли бинты в рюкзаке, они у нас с переменной itemCreated1 { itemCasted = ItemBase.Cast(itemCreated1); // Выполняем преобразование в другой класс для работы с нужной нам функцией, поскольку в классе EntityAI нет нужной нам функции SetQuantity, а в подклассе ItemBase она есть. Предмет при этом так и остается один и тот же! itemCasted.SetQuantity(4); // Определяем количество для созданных бинтов как 4 штуки SetRandomHealthItem(itemCreated); // Выдаем бинтам рандомное качество, функция работает с классом EntityAI (см. в конфе файла) } } // переменную itemCreated не обнуляем далее, поскольку мы ее не используем в проверке ниже. itemCreated = player.GetInventory().CreateInInventory("TTSKOPants"); // Выдаем игроку штаны itemCreated = player.GetInventory().CreateInInventory("TTsKOJacket_Camo"); // Выдаем игроку куртку itemCreated = player.GetInventory().CreateInInventory("CombatBoots_Black"); // Выдаем игроку обувь //itemCasted = ItemBase.Cast(itemCreated); // Строка не нужна, закоментирована. используется для изменения класса EntityAI в ItemBase (чтобы нужные операции были доступны) itemCreated = player.GetInventory().CreateInInventory("CombatKnife"); // Выдаем игроку ножик в любой свободный слот в инвентаре itemCreated = player.GetInventory().CreateInInventory("FNX45"); // Выдаем игроку FNX в любой свободный слот в инвентаре itemCreated = player.GetInventory().CreateInInventory("Mag_FNX45_15Rnd"); // Выдаем игроку магазины к FNX в любой свободный слот в инвентаре itemCreated = player.GetInventory().CreateInInventory("Mag_FNX45_15Rnd"); // Выдаем игроку магазины к FNX в любой свободный слот в инвентаре itemCreated = player.GetInventory().CreateInInventory("Mag_AKM_30Rnd"); // Выдаем игроку магазины к AKM в любой свободный слот в инвентаре itemCreated = player.GetInventory().CreateInInventory("Mag_AKM_30Rnd"); // Выдаем игроку магазины к AKM в любой свободный слот в инвентаре itemCreated = NULL; // Обнуляем значение переменной после работы с ней, нужно если мы будем использовать ее далее itemCreated = player.GetHumanInventory().CreateInHands("akm"); // Выдаем игроку AKM в руки if (itemCreated) // Проверяем, создался ли АКМ { itemCreated.GetInventory().CreateAttachment( "PSO11Optic" ); // Выдаем игроку на AKM оптику ПСО 11 и крепим itemCreated.GetInventory().CreateAttachment( "AK_WoodBttstck" ); // Выдаем игроку на AKM цевье, приклад и глушитель, и крепим itemCreated.GetInventory().CreateAttachment( "AK_WoodHndgrd" ); // Выдаем игроку на AKM цевье, приклад и глушитель, и крепим itemCreated.GetInventory().CreateAttachment( "AK_Suppressor" ); // Выдаем игроку на AKM цевье, приклад и глушитель, и крепим } break; } case 2: //Set with number 2 (Сет с номером 2) { break; } case 3: //Set with number 3 (Сет с номером 3) { break; } case 4: //Set with number 4 (Сет с номером 4) { break; } case 5: //Set with number 5 (Сет с номером 5) { break; } case 6: //Set with number 6 (Сет с номером 6) { break; } default: //Default starting spawn set (Сет поумолчанию для всех игроков, если хотите назначить - добавляйте здесь!) { //My_Custom_Spawn_Parameters.RemoveAllItems(player); // Чтобы удалить с персонажа уже имеющиеся стандартные стартовые шмотки раскомментировать строку DefaultSets(player); // Для выдачи своих сетов по рандому всем игрокам, не прописанным в скрипте, раскомментировать эту строку break; } } } void SetRandomHealthItem(EntityAI itemCreated) // Функция генерирует и применяет для предмета рандомное значение здоровья! { if ( itemCreated ) { private int rndHlt = Math.RandomInt(55,6); itemCreated.SetHealth("","",rndHlt); } } void DefaultSets(PlayerBase player) // Функция выдает сеты игрокам, не прописанным в конфигурации скрипта!!! { EntityAI itemCreated = NULL; EntityAI itemCreated1 = NULL; ItemBase itemCasted = NULL; // ниже пример, если вам нужно задать свои точки спавна для всех игроков. Этот код можно также использовать и для каждого сета индивидуально! // Код закомментирован, если это надо - раскомментируйте! // начало кода точек спавна игрока /* private array <vector> spawnpoints = {"7500 0 7500", "7500 0 7500","7500 0 7500", "7500 0 7500"}; private vector selected_spawnpoint = spawnpoints.GetRandomElement(); player.SetPosition(selected_spawnpoint); */ // конец кода точек спавна игрока private int random_set_number = Math.RandomIntInclusive(1,6); // генерируем рандом номер сета от 1 до 6 включительно (по значениям блоков case ниже) switch( random_set_number ) //Раздаем лут (можно использовать значения от 1 и выше, только не 0 и не -1) { case 1: //Set with number 1 (Сет с номером 1) { break; } case 2: //Set with number 2 (Сет с номером 2) { break; } case 3: //Set with number 3 (Сет с номером 3) { break; } case 4: //Set with number 4 (Сет с номером 4) { break; } case 5: //Set with number 5 (Сет с номером 5) { break; } case 6: //Set with number 6 (Сет с номером 6) { break; } default: //Default starting spawn set (Сет поумолчанию для всех игроков, в случае если ни один из сетов выше не выпал. { //My_Custom_Spawn_Parameters.RemoveAllItems(player); // Чтобы удалить с персонажа уже имеющиеся стандартные стартовые шмотки раскомментировать строку break; } } } } init_mod.c #include "$CurrentDir:mpmissions\dayzOffline.chernarusplus\CustomSpawnPlayerConfig\Script.c" #include "$CurrentDir:mpmissions\dayzOffline.chernarusplus\CustomSpawnPlayerConfig\Sets.c" ref CustomSpawnPlayerConfig My_Custom_Spawn_Parameters = new CustomSpawnPlayerConfig(); ref StartSetsPlayersConfig StartSetsPlayers = new StartSetsPlayersConfig(); modded class CustomMission { override void OnInit () { super.OnInit(); GetGame().GetCallQueue(CALL_CATEGORY_SYSTEM).CallLater(My_Custom_Spawn_Parameters.Read_Update_Config, 120000, true); // Обновление настроек скрипта кастомных спавнов, 1 минута = 60000 } override PlayerBase CreateCharacter(PlayerIdentity identity, vector pos, ParamsReadContext ctx, string characterName) { pos = My_Custom_Spawn_Parameters.Load_And_Check_Spawnpoints(identity, pos); characterName = My_Custom_Spawn_Parameters.Load_And_Check_SpawnSkin_Player(identity, characterName); super.CreateCharacter(identity, pos, ctx, characterName); return m_player; } override void StartingEquipSetup(PlayerBase player, bool clothesChosen) { super.StartingEquipSetup(player, clothesChosen); My_Custom_Spawn_Parameters.Load_And_Check_StartLoadout(player); } } 2. В файле: {папка с вашим сервером}\mpmissions\dayzOffline.chernarusplus\init.c в самом верху файла добавить: #include "$CurrentDir:mpmissions\dayzOffline.chernarusplus\CustomSpawnPlayerConfig\init_mod.c" Чтобы получилось примерно так 3. В папке, обозначенной параметром запуска сервера '-profile=', поместить файл с именем CustomSpawnPlayerConfig.txt и заполнить его данными по следующему формату: UID|Skin_player|sets_numbers|points_spawns где UID - это steam64id от профиля игрока в steam Skin_player - точный id скина игрока (можно указать 0 для отключения опции) sets_numbers - номер сета со стартовым лутом (можно указать несколько через ';', указать один всего, либо указать 0 для отключения опции) points_spawns - координаты спавна игрока на карте в формате 'x y z' (можно указать несколько через ';', указать всего одну точку, либо указать 0 для отключения опции) Пример: CustomSpawnPlayerConfig.txt 76561198141889254|SurvivorM_Oliver|1|12955.091797 16.115206 7993.588379 76561198141889256|SurvivorM_Oliver|1;2|14791.965820 76.481781 14041.661133;12029.079102 196.356125 7274.689941 76561198141889253|SurvivorM_Oliver|0|0 4. В файле Sets.c в папке: {папка с вашим сервером}\mpmissions\dayzOffline.chernarusplus\CustomSpawnPlayerConfig\ настроить стартовый лут для ваших игроков и написать собственные сеты ВАЖНО: количество сетов можно делать любое, номера сетов брать от 1 и выше (не должно быть -1, либо 0, только от 1 и выше) Все что укажете в блоке default будет применено для всех игроков при респавне в случае, если им не выдан никакой сет! Поумолчанию в функции default вызывается функция DefaultSets, позволяющая рандомно выбирать любой из сетов для игроков, которым сет не задан в конфигурации скрипта. Принцип составления сетов такой же, как и выше. Если будете пользоваться этим, обратите вниманием на строку: private int random_set_number = Math.RandomIntInclusive(1,6); Эта функция генерирует число от 1 до 6 включительно. Соответственно если сетов будет больше 6, то число надо корректировать и тут тоже! P.S. Прикрепить к соспавненному оружию магазин не получится, рабочего кода я не смог найти!! Если у вас папка активной миссии сервера отличается от dayzOffline.chernarusplus то переименуйте ее в строке, вписываемой в: {папка с вашим сервером}\mpmissions\dayzOffline.chernarusplus\init.c {папка с вашим сервером}\mpmissions\dayzOffline.chernarusplus\CustomSpawnPlayerConfig\init_mod.c Благодарности: Товарищу Mizev за его первоначальные гайды в группе VK при появлении в сети серверной части игры
-
1 баллИ снова здравствуйте, товарищи и коллеги! Уже не один день наблюдаю среди многих из читающих такую проблему, как непонимание того, что написано в том или ином гайде, скрипте, теме форума по DayZ Standalone. А понимать бы это все это ой как бы не плохо было бы, да, товарищи? Ну хотя бы так, для себя, для осознания происходящего и упрощения своей жизни. Не все же за вас делать постоянно, как считаете? Что же, решил я вот для вас завести такую темку, полезную. В ней мы не будем рассматривать установку чего-либо или сборку мода. Мы попробуем разобраться в основах языка игры, а именно - написании своего кода, чтении кода игры, данного разработчиком, или чужим модом в мастерской. Разумеется, надеюсь я и на вашу бескорыстную помощь и поддержку, а также на помощь знатоков и экспертов скриптинга игры, ведь один я не справлюсь в написании этой безмерно полезной для многих и большой темы. А помощь ой как понадобится, чувствую затылком. Ну ладно, утомил я вас, начнем, пожалуй, согласны? Оговорюсь сразу, в данной теме мы затронем лишь скриптовую составляющую игры. Т.е. вопросы изменения модов, игры, создания собственных интерфейсов, игровых вещей и прочего освещаться не будут. Темы к ознакомлению, схожие с данным материалом: https://s-platoon.ru/topic/8622-enscript-delaem-skript-dlya-moda-i-osnovnye-principy-skriptinga-modov/ https://s-platoon.ru/topic/7838-sozdaem-svoy-servernyy-mod-dayz-14-to-discontined https://s-platoon.ru/topic/8859-enscript-rodnye-funkcii-v-kode-igry-opisanie-nahozhdenie/ Официальная документация, связанная с данным материалом (спасибо BorizzK? https://community.bistudio.com/wiki/DayZ:Enforce_Script_Syntax https://community.bistudio.com/wiki/Category:DayZ:Editing Начнем мы, пожалуй, с общего. Введение. Скрипты. Скрипты - важная часть функционирования игры, создания модов и модификации как игры, так и сервера. Они позволяют делать чудные модификации, создавать новые опции, настраивать или изменять в игре по своей задумке практически любой аспект и функционал, заданный разработчиками, дополнять его и разнообразить. Алгоритм Ваша первая задача при написании скриптов - определить, какие шаги надо предпринять, чтобы решить какую-либо проблему. Последовательность таких шагов - это и будет алгоритм. Например, намерение - передать другу ваш рюкзак. Значит необходимо выполнить следующие действия: Но тут у нас встает вопрос - игрок же вызывает какое-то меню или опцию, которая будет выполнять данные действия. Как это реализовать? Ведь игра - это лишь набор комманд, которые выполняются по одной за раз, как правильно объединить все и сделать корректно? Сделать это все можно именно посредством скриптинга в данной игре с использованием скриптов. Интерпретатор Когда вы составили алгоритм, вам нужно что-то, что может его исполнить. У нас есть компьютерная игра, которая может это сделать. В игре есть игроки, объекты которые могут выполнять те или иные действия, например, получение данных, создание объектов, открытие дверей и т.п. Все имеет свою комманду и результат выполнения. Иными словами, игра сама интерпретирует ваши скрипты и их код в рабочий вид в игре. Исходный код (Скрипт) Исходный код (скрипт) - это алгоритм, написанный на каком-либо языке программирования, который преобразуется в машинный код программы и будет выполнен в том или ином случае. В случае в нашей игрой это код, который игра преобразует в понятные для нее комманды и выполняет их. Скриптинг Скриптинг - какие-либо действия по написанию скриптов для своих работ\модов\игры. Скриптинг в DayZ в основном основывается на том, что уже имеется в игре. Т.е. на базовом функционале игры, который задан разработчиком. В DayZ вся скриптовая часть, написанная авторами игры, располагается в файлике "scripts.pbo" в папке "dta", который мы можем распаковать через "PBO Manager", например, и поглядеть. Любые скрипты могут содержать как набор из функций, так и набор из разных классов с функциями, которые могут вам понадобиться. Enforce Script Enforce Script (EnScript по простому)- это язык сценариев (интерпретации скриптинга), разработанный для движка игры DayZ "enforce Engine" компанией Bohemia Interactive Studio . Все скрипты EnScript, основные игровые логики находятся в "scripts.pbo" в папке "dta" каталога "DayZ" или "DayZ Server". Именно этот файл и будет нам полезен для выяснения того, как работают некоторые вещи (пока, наконец, не появится достойная ссылка на API от разработчиков игра, будь они прокляты). Основные принципы скриптинга на EnScript: Любая комманда, строка в функции должна завершаться на ; (точку с запятой) Тело любой функции/класса/структуры должно быть заключено в {} (фигурные скобки) Язык крайне чувствителен к регистру, т.е. MyPeremennaya и Myperemennaya будут 2 разными объектами для игры. Язык, крайне схожий с синтаксисом и коммандами C++, C# и JavaScript, для тех, кто знает эти языки хотя бы на любительском уровне, работать и писать свои скрипты будет проще в разы Структура скриптовой части игры Распаковав "scripts.pbo" (файл есть в клиенте игры и сервере, он одинаковый) мы увидим несколько папок, таких как "1_Core", "2_GameLib", "3_Game", "4_World", "5_Mission", "data", "editor" а также файлики "$PREFIX$", "$PRODUCT$","$VERSION$","config.bin","profile_fixed.cfg", "staticDefinesDoc.c". Из того, что мне известно, и что нам пригодится при написании скриптов, я отмечу лишь файлик "config.bin", который составляет основную конфигурацию pbo-файла и включенных в него файлов скриптов (по нему 'компилируются' при запуске игры в скрипты в определенные разделы кода запуска игры). А также папки "1_Core", "2_GameLib", "3_Game", "4_World", "5_Mission". Сам "config.bin" разбирать мы не будем, это сделано уже ранее в теме вот этой. Каждая из указанных ранее папок обозначает раздел инициализации кода игры. Например, в "1_Core", "2_GameLib" подгружается основной синтаксис всех функций и переменных игры (то как они будут объявляться в коде, вызываться, какие значения возвращать и принимать). В "3_Game" основной функционал самой игры, обозначающий используемые классы и базовые функции этих классов. В "4_World" все остальные классы, функции и параметры, которые будут исполняться в игре в зависимости от того, какие объекты окружения будут в ней будут и как будут функционировать. В "5_Mission" будет описываться функционал, относящийся к экранам загрузки, меню, их действиям и вызовам. На основе этих разделов и строится основной принцип скриптинга любого мода и функционирования игры в целом. Если вы откроете любой из модов, который имеет хотя бы 1 скрипт, увидите часть этой структуры. Основные разделы скриптов также взаимодействуют друг с другом, но только в порядке, в котором они выполняются и описываются. Например, из "5_Mission" вы можете вызывать классы и функции, описанные в "4_World", а из "4_World" вызвать функции в "5_Mission" не получится, поскольку игра их еще не знает на том этапе запуска и 'компиляции кода скрипта'. Функции Функции - это набор команд (действий) и параметров(переменных). Для ее вызова используется стандартный формат вида: {имя функции}({параметры функции}); Тело любой функции/класса/структуры должно быть заключено в "{}" (фигурные скобки) Функции могут быть как заданные разработчиками игры в каких-либо классах, так и написанные вами вручную собственные. Иногда для ее вызова хватает лишь одной лишь команды, например "MyFunction();". Но чаще в синтаксисе вызова функции присутствует один и более параметров, например "MyFunction("my text");" . Параметры функции могут не содержать значений, а могут иметь 1 или несколько значений, разделенных запятой, например: void MyFunction(int MyChislo, string text1, text2, bool value); У каждой команды может быть свой список данных, которые она может использовать в своем выполнении(например, как было в последнем примере), а также может быть и список данных, которые она вернет. Будут ли эти данные требоваться от функции зависит от автора, который эту функцию пишет (т.е. от разработчиков игры, если это скрипт родной игры, или от вас, если этот скрипт вы пишете сами) Функции с возвращаемыми данными (имеют тип значения, который они возвращают) могут вызываться как вот так: int chislo = MyFunction("my text"); т.е. переменная chislo пример значение, которое функция возвратила либо так: MyFunction("my text"); т.е. функция вернет значение, но оно не будет записано, и не будет использоваться далее. Функции без возврата значений (имеют тип void) могут вызываться только вот так: MyFunction("my text"); Функции могут иметь несколько типов. Например, void MyFunction() { } функция без возврата значения. А функция int MyFunction() возвратит значение типа int (число). Соответственно, функции без возврата значений будут содержать лишь код своих вычислений, а функции с возвратом обязаны иметь комменду return {значение} . Пример функции без возврата значений и принимаемых переменных: void MyFunction() { Print(" ---TEST--- "); } Функция запишет в script.log текст: " ---TEST--- " Пример вызова в коде: MyFunction(); Пример функции с возвратом значений и принимаемыми переменными: string MyFunction(string MyText) { Print(" ---TEST--- " + MyText); return "[" + MyText + "]"; } Пример вызова в коде: string MyTXT1 = MyFunction("TEXT FOR TEST"); Функция запишет в script.log текст: " ---TEST--- TEXT FOR TEST " и запишет в переменную MyTXT1 значение [MyText] Параметров, которые могут передаваться в функцию, может быть несколько, но не рекоммендую их делать более 10. Переменные и их типы Переменные - это типы данных, используемые в коде скриптов игры. Типы переменных обозначаются классами, заданными в игре. Это могут быть как заданные разработчиками поумолчанию типы данных, так и собственные классы, написанные вами. Обозначаются переменные общим видом так: {тип переменной} {название переменной} Строка с обозначением любой переменной или заданием ее значением должно быть закончено точной с запятой на конце! Например: int chislo, string text, bool value; или string text = "TEST"; Каждый тип означает, какие типы данных может принимать данная переменная, и какой объем в памяти игры она займет. Базовое количество типов схоже с c++ и c#, но есть и типы, обозначаемые заданными классами в игре. Стоит понимать, что объявленная 1 раз переменная в функции или классе не может быть объявлена в ней же еще раз, но ей может быть присвоено новое значение, например : void MyFunction() { string myperemennaya="text1"; // тут какие-то вычисления myperemennaya="text2"; } Список используемых типов переменных в игре можно прочитать тут (на немецком): https://germandayz.de/forum/thread/19551-guide-dayz-standalone-scripting-enforce-scripting/ Остальные имеют стандартный тип, используемый в том же с++ и c# Модификаторы функций и переменных. Также, переменные могут иметь модификаторы доступности данных в функциях. Например: public: делает переменную открытой к доступу в других функциях private: делает переменную закрытой к доступу в других функциях protected: ограничивает доступ к переменной только для дружественных и дочерних классов. static - переменная, которая сохраняется в памяти игры даже после удаления экземпляра функции (класса) или переменной из памяти (как в C++). native - Функция или переменная, реализованная игровым движком, не может быть перезаписана. В исходном коде движка такие функции отмечены со смещением. Невозможно изменить модами и сприптами, только использовать их сами. ref - ссылка на свой тип класса или переменной, ref - сокр. referal, т.е. ссылка в переводе Модификаторы также описаны по ссылке выше, и могут быть использованы не только в переменных, но и в функциях игры! Классы Классы - это структуры, которые могут содержать определенные функции и переменные, заданные автором скрипта. У классов может быть много функций, переменных, а каждый класс в свою очередь может быть задан и записан в отдельные переменные по нескольку раз. Т.е. это своего рода свой тип переменной, которая может содержать свои данные внутри себя. Отдельная переменная своего класса или одного из классов игры (например Playerbase) воспринимается как единичный некий экземпляр-объект данного класса, и чем больше таких переменных, тем больше экземпляров одного и того же класса существует в памяти игры. Например: PlayerBase player = NULL; Также, в классах можно обращаться к переменным и функциям, находящимся внутри классов через символ точки (это как вызов и получение результата функции или переменной). Т.е. для экземпляра класса: class MyClass { string MyText = ""; int Chislo = 0; void MyFunction() { Prnt("TEST"); } } ref MyClass Peremennaya = new ref MyClass(); создается переменная, и ее можно вызывать так: string MyResult = Peremennaya.MyText; и значение My Text будет записано в MyResult. Также можно и вызвать функцию или результат ее выполнения (если функция возвращает значение): Peremennaya.MyFunction() выполнит запись в script.log текста TEST. Переменные, объявляемые вне функций в классе одном будут доступны во всех функциях этого класса. Но переменные, заданные в классе, будут индивидуальны для каждого экземпляра этого класса. Т.е. если мы создаем свой класс, например, такого содержания: class MyClass { string MyText = ""; int Chislo = 0; } затем создаем экземпляры этого класса в памяти игры, коммандами ref MyClass Peremennaya = new ref MyClass(); ref MyClass Peremennaya2 = new ref MyClass(); то у Peremennaya и у Peremennaya2 будут свои данные в MyText и Choislo, не связанные между собой: Peremennaya.Text = "MyText1"; Peremennaya.Chislo = 2; Print("Peremennaya.Text = " + Peremennaya2.Text + " Peremennaya.Chislo = " + Peremennaya.Chislo.ToString()); Print("Peremennaya2.Text = " + Peremennaya2.Text + " Peremennaya2.Chislo = " + Peremennaya2.Chislo.ToString()); То мы получим в scriptlog: "Peremennaya.Text = Peremennaya.Text = MyText1 Peremennaya.Chislo = 2" "Peremennaya2.Text = Peremennaya2.Text = Peremennaya2.Chislo = 0" Т.е. в Peremennaya2.Text будет пусто. Обязательно для созданных собственных классов переменных указание ссылочности типов - ref (ref - сокр. referal, т.е. ссылка в переводе) - от этого зависит доступность данных в классах и функциях. Также, из классов можно вызывать и функции, и обращаться к переменным. Разумеется, если они не защищены функцией или модификатором. Например, создадим класс: Class ClassTest { string MyText1 = "123"; private string MyText2 = "456"; void MyFunction1 (string text) { string MyText3 = "789"; Print("!!!Used MyFunction:" + text); } int MyFunction2 () { return 2; } } и создадим экземпляр данного класса, и попробуем к нему обратиться: ref ClassTest Peremennaya3 = new ref ClassTest(); Print("Text1 = " + Peremennaya3.Text1); // В script.log будет Text1 = 123 Print("Text2 = " + Peremennaya3.Text2); // не запустится игра, так как модификатор private не позволит обратиться к переменной внутри класса Print("Text3 = " + Peremennaya3.MyFunction1 ("TEXT")); // В script.log будет Text3 = !!!Used MyFunction:TEXT Peremennaya3.MyFunction2(); // Выолнит функцию MyFunction2 и возвратит значение 2, но оно не будет записано А вот MyText3 из MyFunction1 не получить, так как она содержится внутри функции в классе. Моддинг Классов Классы, в свою очередь, можно менять модами, если они не являются 'нативными', либо не защищены движком игры разработчиков от изменений. Для этого применяют приписку "Modded" перед именем класса с сохранением его имени, например: Modded class PlayerBase { } Моддинг Функций в классах Функции в классах также можно перезаписывать. Для этого используется модификатор "override" перед тем, как задать эту функцию, а в теле самой этой функции можно (и крайне рекоммендуется, но не обязательно) использовать вызов "super." с дальнейшим вызовом этой функции и передачей оригинальных параметров функции. Например: Modded class PlayerBase { override void OnConnect() { Print("Test1"); // Эта строка выполнится до вызова оригинальной функции super.OnConnect(); // вызов оригинальной функции с сохранением ее параметров Print("Test2"); // Эта строка выполнится после вызова оригинальной функции } override string GetPlayerClass() { string returned_original = super.GetPlayerClass(); // вызов оригинальной функции с сохранением ее параметров и значения в переменную if(returned_original == "Bad Type") // Проверка значения { returned_original = "Good Type"; // Замена значения на нужное нам } return returned_original; // Возврат значения функцией } override void EEKilled( Object killer ) { super.EEKilled( killer ); // вызов оригинальной функции с сохранением ее параметров Print("Test3"); // Эта строка выполнится после вызова оригинальной функции } } Как видим, функции перепишутся с вызовом оригинального значения и допиской нужных или коррекцией. Можно делать и так, но крайне не рекоммендуется: Modded class PlayerBase { override void OnConnect() { Print("Test1"); // Эта строка выполнится до вызова оригинальной функции Print("Test2"); // Эта строка выполнится после вызова оригинальной функции } } Но в таком случае, если утеряно оригинальное выполнение кода игры и наследование функций, игра/сервер могут сломаться. Да и моды, которые параллельно с вашим, будут использовать эту функцию, могут перестать работать. Моддинг и скриптинг - Разница? Собственно, если вы осилили все. что описано выше, вы освоили базовую часть скриптинга в данной игре, а значит вас можно поздравить: Теперь вы готовы к написанию собственных скриптов и модов! Самой по себе разницы между скриптами и модами нету. Скрипты - это составляющая большинства современных модов в DayZ, т.е. непосредственная часть мода. Те же самые скрипты могут быть и в mpmissions и в моде, но с одной разницей - то что есть в mpmissions может быть в подключено в моде, а то что подключено в моде не всегда может быть подключено в mpmissions. А смысл как раз в том, что игра загружает скрипты последовательно, т.е. сначала оригинальный код игры с dta, потом моды, и только потом mpmission. Сама же "Mpmission" является частью, заданной в классе "5_Mission" в оригинальных скриптах игры, и делится на 2 файла в зависимости от типа запускаемой игры. Для клиента игры это "missionGameplay.c" а для сервера это "missionServer.c", откуда уже и читаем mpmission сервера. Иными словами, на момент чтения mpmission у нас по сути уже считаны и организованы все структуры разделов кода игры, и доступа к изменениям кодов и классов в "mpmissions" у нас нет. Т.е. то, что вносится в Mpmissions можно вносить в свой мод, но никак не наоборот. Сами же скрипты по своей стркутуре и особенностям такие же. Примечание: Что же касается модификаторов, типов переменных, функций, классов, используемых в игре в скриптах и модах, можно пока почитать вот тут на немецком: https://germandayz.de/forum/thread/19551-guide-dayz-standalone-scripting-enforce-scripting/ Позже будем пытаться создавать свою тему с данным описанием Что касается информации о родных функциях и классах, используемых в игре и на сервере - этой информации найти не смог. Но ее вы можете найти сами так: распаковываем весь scripts.pbo в папку, запускаем Notepad и используем поиск в папке по тексту (Ctrl+F вкладка №3), ищем по кусочкам нужных фраз на английском и смотрим как называется функция, ее расположение в классе. Также, предлагаю всем, кто заинтересован в облегчении поиска информации о таких функциях, помочь друг другу и составить этот список самим в вот этой теме на форуме: Поиск по форуму поможет остальным найти интересующую нас информацию ?
-
Рассылка
