Jump to content

Leaderboard

  1. V3ct0r

    V3ct0r

    Administrators


    • Points

      561

    • Content Count

      2,253


  2. champ

    champ

    Administrators


    • Points

      62

    • Content Count

      100


  3. dragontechi

    dragontechi

    Advanced members


    • Points

      36

    • Content Count

      176


  4. Graf

    Graf

    Community


    • Points

      34

    • Content Count

      461



Popular Content

Showing content with the highest reputation since 05/25/2021 in all areas

  1. 9 points
    PKOdev.NET website for Tales of Pirates Server Hello friends! I want to share with you a website for your own Tales of Pirates server. Features 1) News management; 2) Server rules page; 3) Downloads; 4) Player rankings (by experience, by gold, by number of guild members); 5) Game account registartion with activation by email; 6) Game account restore by email; 7) Game database of monsters and items; 8 ) Donations page; 9) Server status and statistics, GM online; 10) Account management (account information, characters, password/email/pin change); 11) Offline Stall Server extension to view stalls and search items. Requirements 1) Web server; 2) PHP version 7.0 and above; 3) Enabled PDO extension with sqlsrv and sqlite drivers. Installation 1) Put website files to the working directory of your webserver; 2) Configuire file config\inc.config.php. The file is very well commented, so you shouldn't have any problems configuring it; 3) The site uses the Smarty template engine to easily change the appearance. All HTML templates are stored in templates folder; 4) You can find email templates are in templates\email folder. Some pictures Download 1) Google Drive Credits All credits and copyrights belong to @Billie and Kingdom Pirates Online team. If you have any questions or problems related to the website, then feel free to contact them!
  2. 9 points
    New administrator on the forum Hello friends! Today I want to introduce you to the new administrator of the PKOdev.NET forum - @patrick13! @patrick13 has been an active participant in the forum since its inception and since then he has made a great contribution to the development of our community. So, he helped and continues to help translate materials from Russian language into English for publication in the English-language section of the forum, provides technical support on the server- and client-sides of the game to the rest of the community, takes initiative and proposes new ideas, keeps order on the forum, until now acting as a moderator. In addition, @patrick13 has programming skills in the field of applied and web development, fluent in English and Russian languages. In view of the foregoing, I made the decision to invite @patrick13 to become the second administrator, to which he responded positively. I consider his candidacy worthy and beneficial to the further development of the project and the community as a whole. Congratulations to @patrick13 and I would like to thank him for his contributions to the community!
  3. 6 points
    [Mod] Social buttons (Discord, Youtube, Twitch and etc) The mod allows you to add social buttons to the game, by clicking on which the player will be redirected to the corresponding resource on the Internet using the URL specified in the mod settings, for example, to the Discord server, to the Youtube channel, to the Facebook group. Buttons are bound to the minimap form ("frmMinimap"). Requirements Installed mod loading system for server and client (PKOdev.NET mod loader). Modification information Name: pkodev.mod.social; Version: 1.0; Author: V3ct0r; Type: for client (Game.exe); Supported executable .exe files: GAME_13X_0, GAME_13X_1, GAME_13X_2, GAME_13X_3, GAME_13X_4, GAME_13X_5. Installation 1) In the "mods" directory of your client, create a "pkodev.mod.social" folder; 2) Place into it the mod DLL file "pkodev.mod.social.client.13x_<ID>.dll" for your version of Game.exe; 3) Place into it the mod settings file "pkodev.mod.social.cfg"; 4) In the GUI scripts of the game client, add the required social buttons to the minimap form (form "frmMinimap" from the file "minimap.clu"), for example: btnFacebook = UI_CreateCompent(frmMinimap, BUTTON_TYPE, "btnFacebook", 24, 24, 0, 180) UI_LoadButtonImage(btnFacebook, "texture/mods/pkodev.mod.social/social.png", 24, 24, 0, 0, FALSE ) btnDiscord = UI_CreateCompent(frmMinimap, BUTTON_TYPE, "btnDiscord", 24, 24, 28, 180) UI_LoadButtonImage(btnDiscord, "texture/mods/pkodev.mod.social/social.png", 24, 24, 24, 0, FALSE ) btnYoutube = UI_CreateCompent(frmMinimap, BUTTON_TYPE, "btnYoutube", 24, 24, 56, 180) UI_LoadButtonImage(btnYoutube, "texture/mods/pkodev.mod.social/social.png", 24, 24, 48, 0, FALSE ) btnTwitch = UI_CreateCompent(frmMinimap, BUTTON_TYPE, "btnTwitch", 24, 24, 84, 180) UI_LoadButtonImage(btnTwitch, "texture/mods/pkodev.mod.social/social.png", 24, 24, 72, 0, FALSE ) btnTwitter = UI_CreateCompent(frmMinimap, BUTTON_TYPE, "btnTwitter", 24, 24, 112, 180) UI_LoadButtonImage(btnTwitter, "texture/mods/pkodev.mod.social/social.png", 24, 24, 96, 0, FALSE ) 5) Add social buttons to the mod settings file "pkodev.mod.social.cfg" in the following format: <button_name> = <URL> For the buttons from the example above: btnFacebook = https://facebook.com/ btnDiscord = https://discord.com/ btnYoutube = https://www.youtube.com/ btnTwitch = https://www.twitch.tv/ btnTwitter = https://twitter.com/ Download 1) Binary release (.dll); 2) The source code of the mod for Visual Studio 2019 Community (C++). If you encounter any problem, bug or have any questions, then feel free to write in this thread.
  4. 6 points
    A couple of years ago I had the idea of using an object as an npc for daily quests, I paid for it and never used it but I share it in case someone is interested Add in characterinfo after line 5 on server and client (compile) 7 CHA7 CHA7 4 2 7 0 1 1 1 0 0 0 0 0 0 0 0 0 1 7 100 182 -1 -1 0 0 0 7,8,9,10 0.797 1.392 4.709 40 1,5 0 399 398 0 0 0 1 1 0 0 25,28,29,34,35,36,37 100 0 0 0 0 0 0 0 1 1 1000 0 0 1 0 1 40 0 18 0 4 5 0 3 2 1 1 0 1 1 1442 0 1500 480 0 5 5 5 5 5 5 20 0 0 0 0 20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1,1,1 Add in characteraction.tx 7 1 0 99 before 10 in line 1944 (I think), do not alter the order of how the numbers are displayed or the client will mark an error. add in garnernpc from server XX Quest Board 1 7 15 223200,279300 223200,279300 180 Argent City 3 0 Script_Npc01 0 and place the files in their respective client folders, Inside the file are the instructions in case there is an error Download Here is useful for, or any other use
  5. 6 points
    [Mod] Displaying the level of items on their icons ("smart icons") Some information appears on the icons of specific items: 1) For items with inserted gems, the level of fusion is displayed; 2) For gems, their level is displayed; 3) For fairies, their level is displayed; 4) For apparels, the inscription "App" is displayed. Requirements Installed mod loading system for server and client (PKOdev.NET mod loader). Modification information Name: pkodev.mod.itemlv Version: 1.0; Author: V3ct0r; Type: for client (Game.exe); Supported executable .exe files: GAME_13X_0, GAME_13X_1, GAME_13X_2, GAME_13X_3, GAME_13X_4 and GAME_13X_5. Installation Place the mod DLL file "pkodev.mod.itemlv.client.13x_<ID>.dll" for your version of Game.exe into the "mods" folder of the game client. Download 1) Binary release (.dll); 2) The source code of the mod for Visual Studio 2019 Community (C++). If you encounter any problem, bug or have any questions, then feel free to write in this thread.
  6. 6 points
    [Source Code Mod] Interface Restrict Hello ! I have done this mod because it is annoying(atleast for me) when an interface element sinks beyond the client window. As for now, the code is implemented to work only for the skills user interface, you would have to make it work by yourself for the rest of the elements, which is pretty easy to figure out by just looking at the code and a bit of experience with the source code. Download: 1) Mod 2) Preview If you're having any issue to implement it, be sure to leave a comment with your issue with no worries.
  7. 6 points
    Насколько я помню в редакторе проверки на выделенный объект делаются по названию ноды. В чтобы установить "кисть" для редактирования поверхности земли, нужно чтобы название выбранной ноды совпадало с названием указанным в StringSet. * Вырезка из собственных исходников, код может отличаться от публичного CTreeNode* parent = dynamic_cast<CTreeNode*>(select->GetParent()); if (!parent) return; item = dynamic_cast<CItem*>(parent->GetItem()); if (!item) return; if (std::strcmp(item->GetString(), CLanguageRecord::inst()->GetString(539)) == 0) // [539] "поверхность" { CGraph* p = dynamic_cast<CGraph*>(tree->GetSelect()->GetItem()); if (p) g_Editor.SetTerr(press, p->nTag); return; } if (std::strcmp(item->GetString(), CLanguageRecord::inst()->GetString(540)) == 0) // [540] "Строительство" { CGraph* p = dynamic_cast<CGraph*>(tree->GetSelect()->GetItem()); if (p) g_Editor.SetObj(press, p->nTag); } Судя по первому скриншоту название ноды установлено как "поверхность земли". Попробуй в StringSet изменить [539] "поверхность" на [540] "поверхность земли", должно помочь. Либо найти в scripts\lua\forms файл editor.clu там поищи там: поверхность земли \239\238\226\229\240\245\237\238\241\242\252 \231\229\236\235\232 замени на поверхность \239\238\226\229\240\245\237\238\241\242\252
  8. 6 points
    Инструмент для обрезания и склеивания карт Данный инструмент позволяет вырезать квадратные фрагменты из файлов карт клиента .map и .obj, а так же добавлять фрагменты уже к существующим картам, таким образом, объединять несколько карт в одну. С её помощью, например, можно вырезать отдельный остров или создать объединенную карту мира. В .map файлах содержится вся основная информация о картах игрового мира: 1) Области суши и воды; 2) ID текстур поверхности суши; 3) ID регионов из areaset.bin; 4) Рельеф местности, высоты; 5) Проходимые и непроходимые участки; 6) Боевые и безопасные зоны. В .obj файлах находится список всех неживых объектов, которые присутствуют на карте (здания, постройки, деревья, растения, камни и тому подобное). Сам по себе инструмент не является законченной программой – пользователь должен самостоятельно написать программу, которая создаст требуемую карту. В качестве языка программирования используется C++, а средой программирования выступает Visual Studio 2019 Community. Таким образом, для использования данного инструмента потребуются базовые знания языка C++. API Инструментарий представлен двумя классами, которые находятся в файле Map.h: 1) pkodev::MapFile – класс для работы с картами в формате .map; 2) pkodev::ObjFile – класс для работы с картами в формате .obj. Данные классы обладают одинаковым интерфейсом. Кроме того, в файле Map.h определена структура pkodev::point, которая описывает точку с координатами (x, y). Поскольку, в основном, требуется одновременное редактирование .map и .obj файлов, был определен класс pkodev::MapWrapper, который инкапсулирует внутри себя объекты pkodev::MapFile и pkodev::ObjFile, и обеспечивает их одновременное изменение. Обладает таким же интерфейсом, как и указанные классы. В процессе работы могут возникнуть ошибки. Для их обработки определены классы исключений pkodev::map_file_exception и pkodev::obj_file_exception, которые являются наследниками класса std::runtime_error. MapFile::MapFile(), ObjFile::ObjFile() Создать пустую карту с нулевым размером. MapFile(unsigned int width, unsigned int height), ObjFile:: ObjFile(unsigned int width, unsigned int height) Создать пустую карту с размерами width x height. void MapFile::load(const std::string& path), void ObjFile::load(const std::string& path) Загрузить карту из файла. Выбрасывают исключения pkodev::map_file_exception и pkodev::obj_file_exception соответственно. void MapFile::save(const std::string& path), void ObjFile:: save (const std::string& path) Сохранить карту в файл. Выбрасывают исключения pkodev::map_file_exception и pkodev::obj_file_exception соответственно. MapFile MapFile::cut(const point& start, const point& end), ObjFile ObjFile::cut(const point& start, const point& end) Вырезать квадратный фрагмент карты. start – начальные координаты (x0, y0), end – конечные (x1, y1). Выбрасывают исключения pkodev::map_file_exception и pkodev::obj_file_exception соответственно. void MapFile::glue(const point& pos, MapFile& map), void ObjFile::glue(const point& pos, ObjFile& map) Добавить на карту квадратный фрагмент. pos – координаты, по которым разместить фрагмент, map – добавляемый фрагмент карты. Выбрасывают исключения pkodev::map_file_exception и pkodev::obj_file_exception соответственно. void MapFile::del(const point& start, const point& end), void ObjFile::del(const point& start, const point& end) Удалить с карты квадратный фрагмент. start – начальные координаты (x0, y0), end – конечные (x1, y1). Фрагмент заменяется морем. Выбрасывают исключения pkodev::map_file_exception и pkodev::obj_file_exception соответственно. void MapFile::clear(), void ObjFile::clear() Удалить карту и освободить память. Класс pkodev::MapWrapper обладает аналогичным интерфейсом, но есть разница в методах load() и save(): путь до файла указывается без расширения. Примеры использования Вырезание фрагмента Напишем программу, которая вырежет "остров Удачи" из локации "Великий Синий океан". Соответственно, нам необходимо работать с файлами darkblue.map и darkblue.obj. Открываем Visual Studio 2019 Community, создаем консольное приложение C++ и подключаем файлы Map.h и Map.cpp, либо загружаем уже готовый проект из архива во вложении. Алгоритм программы будет следующий: 1) Открыть файлы darkblue.map и darkblue.obj; 2) Вырезать из них фрагмент с координатами x0 = 1430, y0 = 1675, x1 = 1780, y1 = 2025; 3) Сохранить фрагмент в файлы fortune.map и fortune.obj. Пишем код: #include <iostream> #include "Map.h" // Точка входа int main(int argc, char* argv[]) { try { // Создаем объект для одновременной работы с .map и .obj файлами pkodev::MapWrapper darkblue; // Загружаем карту из файла darkblue darkblue.load("C:\\pkodev\\Client\\map\\darkblue"); // Вырезаем остров удачи pkodev::MapWrapper fortune = darkblue.cut({ 1430, 1675 }, { 1780, 2025 }); // Сохраняем остров удачи fortune.save("C:\\pkodev\\Client\\map\\fortune"); } catch (const pkodev::map_file_exception& e) { std::cout << ".map file error: " << e.what() << std::endl; return 1; } catch (const pkodev::obj_file_exception& e) { std::cout << ".obj file error: " << e.what() << std::endl; return 2; } catch (...) { std::cout << "Unknown error!" << std::endl; return 3; } return 0 } В результате получим карту (скриншот из YAMMI): Склеивание карт Теперь попробуем склеить несколько карт в одну. Для примера создадим массив "островов Удачи", из острова, который мы получили в прошлом примере. Алгоритм программы будет следующий: 1) Создать пустую карту размером 1024 x 1024; 2) Загрузить "остров Удачи" из файлов fortune.map и fortune.obj; 3) Поместить "остров Удачи" по координатам (128, 32) на карту; 4) Поместить "остров Удачи" по координатам (512, 320) на карту; 5) Поместить "остров Удачи" по координатам (128, 576) на карту; 6) Сохранить карту в файл array.map и array.obj. Пишем код: #include <iostream> #include "Map.h" // Точка входа int main(int argc, char* argv[]) { try { // Создаем пустую карту 1024 x 1024 pkodev::MapWrapper map(1024, 1024); // Остров Удачи pkodev::MapWrapper fortune; // Загружаем остров Удачи из файла fortune.load("C:\\pkodev\\Client\\map\\fortune"); // Добавляем несколько островов Удачи на пустую карту map.glue({ 128, 32 }, fortune); map.glue({ 512, 320 }, fortune); map.glue({ 128, 576 }, fortune); // Сохраняем карту map.save("C:\\pkodev\\Client\\map\\array"); } catch (const pkodev::map_file_exception& e) { std::cout << ".map file error: " << e.what() << std::endl; return 1; } catch (const pkodev::obj_file_exception& e) { std::cout << ".obj file error: " << e.what() << std::endl; return 2; } catch (...) { std::cout << "Unknown error!" << std::endl; return 3; } return 0; } В результате получим карту (скриншот из YAMMI): Скачать инструмент (9 Кб)
  9. 6 points
    hello there! this small optimizing for _evtGameOptionFormMouseDown normal code will run every functions in the list even if its same previous value example: so what we do small optimize to call changed values in system options only " this helpful if you are using hide effects/apps etc" the modification: open UISystemForm.cpp and search for : void CSystemMgr::_evtGameOptionFormMouseDown(CCompent* pSender, int nMsgType, int x, int y, DWORD dwKey) for example we change it to now repeat same steps for the rest options pGroup = g_stUISystem.cbxHelpMode; if (pGroup) { bool bHelpMode = pGroup->GetActiveIndex() == 1 ? true : false; if (g_stUISystem.m_sysProp.m_gameOption.bHelpMode != bHelpMode) { g_stUISystem.m_sysProp.m_gameOption.bHelpMode = bHelpMode; if (!bHelpMode) g_stUIStart.ShowLevelUpHelpButton(bHelpMode); g_stUIStart.ShowInfoCenterButton(bHelpMode); ::WritePrivateProfileString("gameOption", "helpMode", bHelpMode ? "1" : "0", "./user/system.ini"); } }
  10. 5 points
    Друзья вот дизайн инвентаря с временным мешком. Хочу вам сказать что данный дизайн хочу полностью внести в игру пиратия очень понравилось данное оформление. Хочу скачать
  11. 5 points
    [Мод] Система ежедневных наград за вход в игру Данный мод реализует систему ежедневных наград за вход в игру. Игрокам необходимо каждый день заходить в игру, чтобы получить очередную награду - с каждым новым днем награда становится ценнее. Если игрок пропускает день, то цепочка сбрасывается и начинается заново с первого дня. Каждую неделю цепочка так же сбрасывается. Цепочка наград настраивается администратором в специальной lua функции и рассчитывается на неделю вперед, после чего сохраняется в базе данных сервера. Требования Установленный Загрузчик модов для сервера и клиента (PKOdev.NET mod loader). Информация о моде Название: pkodev.mod.reward; Версия: 1.0; Автор: V3ct0r; Тип: для клиента и сервера (Game.exe и GameServer.exe); Поддерживаемые исполняемые .exe файлы: GAME_13X_0, GAME_13X_1, GAME_13X_2, GAME_13X_3, GAME_13X_4, GAME_13X_5, GAMESERVER_136 и GAMESERVER_138. Установка Сервер: 1) В директории "GameServer\mods" Вашего сервера создайте папку "pkodev.mod.reward"; 2) Поместите в неё файл DLL-библиотеки мода "pkodev.mod.reward.server.13<x>.dll" для Вашей версии GameServer.exe; 3) В файл functions.lua ("GameServer\resource\script\calculate\") запишите следующий скрипт: -- Daily reward system (pkodev.mod.reward) -- Transfer the list of items to the system function GetRewardArrayAdapter(role) -- Get a list of items for daily reward local arr = GetRewardArray(role) -- Transfer the list to the system return arr[1].id, arr[1].number, arr[2].id, arr[2].number, arr[3].id, arr[3].number, arr[4].id, arr[4].number, arr[5].id, arr[5].number, arr[6].id, arr[6].number, arr[7].id, arr[7].number end -- Daily reward system (pkodev.mod.reward) -- Get a list of items for daily reward function GetRewardArray(role) -- Select an item depending on character race local hairstyle_book = function(role) -- List of items -- ID: 931 Lance Trendy Hairstyle Book -- ID: 932 Carsise Trendy Hairstyle Book -- ID: 933 Phyllis Trendy Hairstyle Book -- ID: 934 Ami Trendy Hairstyle Book local items = {931, 932, 933, 934} -- Get character type ID local id = GetChaTypeID(role) -- Return item id depending on the type ID return items[id] or 0 end -- Make a list of items for daily reward local items = { -- Day 1 (Short Sword x 1 or Long Sword x 1 or Fencing Sword x 1) {id = math.random(1, 3), number = 1}, -- Day 2 (Apple x 99 or Bread x 99 or Cake x 99) {id = math.random(1847, 1849), number = 99}, -- Day 3 (Fairy Coin x 50) {id = 855, number = 50}, -- Day 4 (Random fairy ID 183 ... 193 x 1) {id = math.random(183, 193), number = 1}, -- Day 5 (Hairstyle Book x 1) {id = hairstyle_book(role), number = 1}, -- Day 6 (Fairy Ration x 10) {id = 227, number = 10}, -- Day 7 (Refining Gem x 1) {id = 885, number = 1} } -- We have to return an array of items to caller function return items end 4) В MSSQL Management Studio выполните SQL-запрос: USE GameDB ALTER TABLE character ADD reward VARCHAR(128) NOT NULL DEFAULT '0' WITH VALUES Клиент: 1) В директории "mods" Вашего клиента создайте папку "pkodev.mod.reward"; 2) Поместите в неё файл DLL-библиотеки мода "pkodev.mod.reward.client.13x_<x>.dll" для Вашей версии Game.exe; 3) Поместите файлы текстур формы "main.png" и "buttons.tga" в директорию "texture\mods\pkodev.mod.reward" Вашего клиента; 4) В файл скриптов "main.clu" ("scripts\lua\forms") добавьте код формы ежедневной награды: ---------------------------------------------------------------------------------------------------- -- Daily login reward form ---------------------------------------------------------------------------------------------------- -- The form frmReward = UI_CreateForm( "frmReward", FALSE, 366, 158, 150, 200, TRUE, FALSE ) UI_SetFormStyle( frmReward , 0 ) UI_AddFormToTemplete( frmReward, FORM_MAIN ) UI_FormSetIsEscClose( frmReward, FALSE ) UI_SetIsDrag( frmReward, TRUE ) -- Form background frmRewardImg = UI_CreateCompent( frmReward, IMAGE_TYPE, "frmRewardImg", 366, 158, 0, 0 ) UI_LoadImage( frmRewardImg, "texture/mod/pkodev.mod.reward/main.png", NORMAL, 366, 158, 0, 0 ) -- Form title labTitle = UI_CreateCompent( frmReward, LABELEX_TYPE, "labTitle", 400, 150, 10, 7 ) UI_SetCaption( labTitle, "\197\230\229\228\237\229\226\237\224\255 \237\224\227\240\224\228\224!") UI_SetTextColor( labTitle, COLOR_WHITE ) -- Reward button btnGetReward = UI_CreateCompent( frmReward, BUTTON_TYPE, "btnGetReward", 67, 24, 150, 120 ) UI_LoadButtonImage( btnGetReward, "texture/mod/pkodev.mod.reward/main.png", 67, 24, 0, 158, TRUE ) -- Close button btnClose = UI_CreateCompent( frmReward, BUTTON_TYPE, "btnClose", 21, 21, 343, 2 ) UI_LoadButtonImage( btnClose, "texture/mod/pkodev.mod.reward/buttons.tga", 21, 21, 270, 0, TRUE ) UI_SetButtonModalResult( btnClose, BUTTON_CLOSE ) -- Item slots cmdItemSlot0 = UI_CreateCompent( frmReward, COMMAND_ONE_TYPE, "cmdItemSlot0", 32, 32, 20, 73 ) UI_SetIsDrag( cmdItemSlot0, FALSE ) cmdItemSlot1 = UI_CreateCompent( frmReward, COMMAND_ONE_TYPE, "cmdItemSlot1", 32, 32, 69, 73 ) UI_SetIsDrag( cmdItemSlot1, FALSE ) cmdItemSlot2 = UI_CreateCompent( frmReward, COMMAND_ONE_TYPE, "cmdItemSlot2", 32, 32, 118, 73 ) UI_SetIsDrag( cmdItemSlot2, FALSE ) cmdItemSlot3 = UI_CreateCompent( frmReward, COMMAND_ONE_TYPE, "cmdItemSlot3", 32, 32, 167, 73 ) UI_SetIsDrag( cmdItemSlot3, FALSE ) cmdItemSlot4 = UI_CreateCompent( frmReward, COMMAND_ONE_TYPE, "cmdItemSlot4", 32, 32, 216, 73 ) UI_SetIsDrag( cmdItemSlot4, FALSE ) cmdItemSlot5 = UI_CreateCompent( frmReward, COMMAND_ONE_TYPE, "cmdItemSlot5", 32, 32, 265, 73 ) UI_SetIsDrag( cmdItemSlot5, FALSE ) cmdItemSlot6 = UI_CreateCompent( frmReward, COMMAND_ONE_TYPE, "cmdItemSlot6", 32, 32, 314, 73 ) UI_SetIsDrag( cmdItemSlot6, FALSE ) ---------------------------------------------------------------------------------------------------- Настройка мода 1) В функции GetRewardArray(role) запишите код, который будет генерировать цепочку наград для персонажа role на следующие семь дней. Функция должна вернуть таблицу из 7 элементов с полями id и number, где id - это ID предмета, который выдается в качестве награды, а number - количество предметов. Каждый элемент соответствует своему дню (1-й элемент - первый день, 2-ой элемент - второй день и так далее). Пример: function GetRewardArray(role) local items = { -- День 1: Яблоко x 20 {id = 1847, number = 20}, -- День 2: Хлеб x 40 {id = 1848, number = 40}, -- День 3: Кекс x 60 {id = 1849, number = 60}, -- День 4: Монета феи x 55 {id = 855, number = 55}, -- День 5: Питание для феи x 15 {id = 227, number = 15}, -- День 6: Хлеб x 99 {id = 1848, number = 99}, -- День 7: Кекс x 99 {id = 1849, number = 99} } return items end ID предметов и их количество можно генерировать случайным образом или в зависимости от расы персонажа, его профессии и тому подобного. 2) По умолчанию период награды составляет 24 часа. Вы можете изменить это значение в исходном коде серверной части мода (проект pkodev.mod.reward.server, файл structure.h), после чего скомпилируйте проект: // Reward interval in seconds static const unsigned int interval{ 24 * 60 * 60 }; // 24 hours 3) Настройка на стороне клиента не требуется. Старая версия GUI (большое спасибо пользователю @Masuka00!) Скачать текстуру В main.clu нужно записать новый код для кнопки "Apply": -- Close button btnClose = UI_CreateCompent( frmReward, BUTTON_TYPE, "btnClose", 14, 14, 342, 4 ) UI_LoadButtonImage( btnClose, "texture/mods/pkodev.mod.reward/main.png", 14, 14, 271, 174, TRUE ) UI_SetButtonModalResult( btnClose, BUTTON_CLOSE ) Скачать 1) Бинарные файлы мода (.dll); 2) Исходный код мода для Visual Studio 2019 Community (C++). Если Вы столкнулись с какой-либо проблемой, багом или у Вас возникли вопросы, то пишите в данной теме.
  12. 5 points
    [Mod] Medals (necklaces) with titles The modification allows you to create medals (necklaces) with different titles that appear in brackets before the name of the character (see screenshot). Also, these necklaces allow you to change the color of the names of the characters. The text, color of the title and color of the character's name are specified in the file ItemInfo.txt for items with type 25 (necklace). 1) The text of the title is specified in the description of the item The maximum title length is 15 symbols; 2) The color of the title is specified in the 5th field instead of model for Lance. Color has format FFRRGGBB; 3) The color of the name is specified in the 6th field instead of model for Carsise. Color has format FFRRGGBB; Some examples of medals with titles: XXXX Medal 1 (Red Admin) l0005 10130005 FFFF0000 0 0 0 0 0 25 0 0 0 0 0 1 1 1 1 1 1 32 -1 1 -1 0 0 5 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0 0,1000 10000,10000 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 Admin XXXX Medal 2 (Green maindev) l0005 10130005 FF00FF00 0 0 0 0 0 25 0 0 0 0 0 1 1 1 1 1 1 32 -1 1 -1 0 0 5 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0 0,1000 10000,10000 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 maindev XXXX Medal 3 (Blue PkoDEV) l0005 10130005 FF0000FF 0 0 0 0 0 25 0 0 0 0 0 1 1 1 1 1 1 32 -1 1 -1 0 0 5 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0 0,1000 10000,10000 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 PkoDEV Example of medal with title and colored character name: XXXX Medal 2 l0005 10130005 FF00FF00 FFFF8000 0 0 0 0 25 0 0 0 0 0 1 1 1 1 1 1 32 -1 1 -1 0 0 5 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0 0,1000 10000,10000 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 PKOdev.NET Requirements Installed mod loading system for server and client (PKOdev.NET mod loader). Modification information Name: pkodev.mod.title; Version: 1.0; Author: V3ct0r; Type: for client (Game.exe); Supported executable .exe files: GAME_13X_0, GAME_13X_1, GAME_13X_2, GAME_13X_3, GAME_13X_4, GAME_13X_5. Installation 1) In the "mods" directory of your client, create a "pkodev.mod.title" folder; 2) Place into it the mod DLL file "pkodev.mod.title.client.13x_<ID>.dll" for your version of Game.exe; 3) Add new medals (necklaces) with titles to the file ItemInfo.txt of the server and client according to the example from the topic header. Compile ItemInfo.txt for the client. Download 1) Binary release (.dll); 2) The source code of the mod for Visual Studio 2019 Community (C++). If you encounter any problem, bug or have any questions, then feel free to write in this thread.
  13. 5 points
  14. 5 points
    Hi folks, I have promised a tutorial the other day on how to create a game updater but unfortunately I have been quite busy and to be completely honest it's easier and quicker for me to write something rather than create a high quality guide. The advantage of using this patcher is that you do not need to keep track of your patches or create any sort of zips, simply commit your changes to your repository containing your client and the updater will automatically sort everything out for you This patcher requires only one configuration file which is called appsettings.json. In there you need to set up a few things for the patcher to work correctly, those are: RepositoryName - set this to the name of your public repository containing your game client. ApiKey - you need to generate an api key and store it inside appsettings.json file, to create your api key, go to this link. This api key requires only repo:status priveleges (access to read commits from public repositories), you can set other privileges at your own risk. Please ensure you set no this token expiration date to "No expiration". Owner - GitHub username of account that is the owner of the repository. In other words, if I created a repository called kopClient, then I would change my appsettings RepositoryName to kopClient and change Owner to champ. This solution is written in C#, which consists of two projects: PkodevUpdater project - WPF application with the GUI of the updater. UpdaterLibrary - .NET core library which contains the main functionality of the updater. This updater is free to use and was released for PkoDev.net specifically, therefore I kindly ask to not post this updater outside of PkoDev.net community. To compile this project you need Visual Studio 2019 and above, as well as .NET 5.0 framework. Please bear in mind there are a few things that could be improved and those were marked with TODO comments. For instance: The method that updates client hash accepts a hash string param but the code does not check if that string is a valid hash. When a file is deleted and the directory where this file was deleted from is empty, the launcher does not delete that directory or the corresponding parent directory. Please let me know if you come across any issues or bugs. If you would like to contribute, then please fork the repository and create a PR. The image used in the updater is a placeholder only and I strongly suggest that you do not use anything that belongs to King of Pirates without my consent. Link to the repository: click me
  15. 5 points
    [Source Code Mod] Fade Logo with hint Hello ! I have done this mod since a few weeks ago, and I decided to share it because some of you might think it looks cool and nice. The code can definitely be improved. Download 1) Mod 2) Preview I will make this mod work with V3ct0r's mod loader aswell, I will post it soon.
  16. 5 points
    Новый администратор на форуме Всем привет! Сегодня я хочу вам представить нового администратора форума PKOdev.NET - @patrick13! @patrick13 является активным участником форума с момента его открытия и с тех пор он внес большой вклад в развитие нашего сообщества. Так, он помогал и продолжает помогать переводить материалы с русского языка на английский для публикации в англоязычном разделе форума, оказывает техническую поддержку по серверной и клиентской частям игры остальным участникам сообщества, проявляет инициативу и предлагает новые идеи, следит за порядком на форуме, до настоящего момента выполняя обязанности модератора. Кроме того, @patrick13 обладает навыками программирования в сфере прикладной и веб-разработки, хорошо знает английский и русский языки. В связи с вышесказанным, я принял решение предложить @patrick13 стать вторым администратором, на что он дал положительный ответ. Считаю его кандидатуру достойной и благотворно влияющей на дальнейшее развитие проекта и сообщества в целом. Поздравляю @patrick13 и выражаю ему большую благодарность за вклад в комьюнити!
  17. 5 points
    Благодарю за идею, но я вообще не переживаю по поводу копирования материалов с нашего форума. В первую очередь, меня как автора радует сам процесс создания новых материалов и интересует максимальное распространение их внутри сообщества, с целью принесения пользы - "особенная личность" это обеспечивает. Как показывает практика, тенденция такова, что сайты и форумы, которые бездумно копируют, долго не живут. В Интернете можно найти мёртвые форумы, на которые скопированы гайды еще со времен maindev.ru (русскоязычный раздел форума до 2016 года находился там), да и сабж данной темы уже выглядит скорее дохлым, нежели живым. Соответственно, все эти копирования производятся до поры до времени. Далее, пользователь в любом случае выйдет на оригинал на PKOdev.NET: например, если кто-то столкнется с проблемой с каким-либо модом, то на in-pko.com ему не смогут помочь с вероятностью 99%, поэтому пользователь придет за решением сюда. Исходя из вышесказанного, я не вижу смысла использовать водяные знаки, кроме того, что они мне не нравятся как механизм защиты от копирования, доставляют неудобства авторам и читателям. Да и изображения составляют лишь небольшую часть наших материалов. Мне не жалко делиться материалами с другими ресурсами: я ориентирован на сотрудничество. Мне интересно посещать другие форумы внутри нашего сообщества и находить там уникальные материалы, а здоровая конкуренция приводит лишь к всеобщему развитию. Но, учитывая методы развития форума in-pko.com, основанные на паразитировании на PKOdev.NET (а это массовый спам в ЛС пользователей, флуд в разделах нашего форума, копирование материалов без согласования с авторами), кроме как "воровством" такое поведение назвать нельзя, поэтому мы не смогли пройти мимо и не обстебать эту тему.
  18. 4 points
    Offline stalls system One of the gaming aspects of the game is trading between characters through special stalls, which players can open by learning a special skill. The player sell his items for a certain price, and other players can buy them. However, for such trading, the player have to be in the game, that is, be connected to the server, which makes him to leave his computer constantly turned on and keep the game client minimized. This is very inconvenient, so the system of "offline" stalls was invented, which allows players to disconnect from the server and still remain trading in the stalls. There are several ways to implement such a system, but the most common system is "offline" stalls through a proxy server: 1) The game client (Game.exe) connects to the proxy server; 2) The proxy server, in turn, opens a connection to the GateServer.exe; 3) Further, the proxy server transfers all packets between Game.exe and GateServer.exe, while analyzing them; 4) When a player opens a trade stall, the proxy server captures this (GateServer.exe sent Game.exe a successful stall opening packet); 5) If a player disconnects from the server while in a trading stall, then the proxy server closes the connection to Game.exe, but at the same time keeps the connection to GateServer.exe and starts imitating Game.exe. Thus, GateServer.exe is unaware of the fact that Game.exe is disconnected and the player's character remains to trade in the stall on the server. Game.exe | Game.exe | <---------> pkodev.stallserver.exe <---------> GateServer.exe Game.exe | This topic discusses the development of such a proxy server - PKOdev.NET Stall Server. Warning! The application is currently under development. The application has not been fully tested and is not stable. This means that errors, bugs and critical vulnerabilities may be present. Use it for testing purposes only! Features 1) Offline stalls system; 2) Limiting the number of offline stalls from one IP address; 3) Limiting the trading time in an offline stall; 4) Automatic disconnection of the account from the server when a player tries to enter his account while trading in an offline stall; 5) Notification of players in the chat that a player trades in an offline stall (in PM); 6) Prevention of SQL-injections in login and PIN create (change) packets from game client; 7) Setting for the maximum number of connections from the same IP address and the interval between connections. to-do 1) Translate comments in files Server.h and Server.cpp to English language; 2) Fix application crash when processing packets; 3) Fix application crash on startup when local port is closed; 4) Fix bridge hanging when blocking packets on enabled encryption in GateServer.cfg (thanks to @small666 for finding the bug); 5) Make thread synchronization when processing packets; 6) Close the offline stall if it is empty; 7) Modification of GateServer.exe to determine the IP addresses of clients that are behind the server of offline stalls. At this point in the logs and database, the IP addresses of all clients will be written as 127.0.0.1 (if both GateServer.exe and pkodev.stallserver.exe are running on the same machine). 8 ) Compatibility with Corsairs Online (CO) source code. Building and running 1) Clone the repository with the project to your disk (the link will be below); 2) Open the solution file pkodev.stallserver.sln in Visual Studio 2022 Community (or higher version); 3) Build the solution. The server executables will appear in the bin folder; 4) Place the configuration file pkodev.stallserver.cfg from the cfg folder in the same directory as the server executable file pkodev.stallserver.exe; 5) Customize the configuration file pkodev.stallserver.cfg (the file is well commented); 6) To connect the game client (Game.exe) to the offline stall server, you need to install the pkodev.mod.stallserver mod; 7) To connect the offline stall server to GateServer.exe, the GateServer should be without any modifications, for example, from the PKO 1.38 server files. 8 ) Run offline stall server executable pkodev.stallserver.exe. Git repository https://github.com/V3ct0r1024/pkodev.stallserver
  19. 4 points
    Mod loading system for server and client (PKOdev.NET mod loader) The Problem Many developers and administrators of Tales of Pirates servers in our community know that the functionality of the client and server can be changed by mods (addons, plugins, patches). Some examples of mods: 1) The fix of SQL Injections in AccountServer.exe and GroupServer.exe; 2) Increasing the limits for .txt / .bin files (ItemInfo, CharacterInfo, SkillInfo, etc.); 3) Local chat message handling using the lua function HandleChat(); 4) Character transformation using the lua function TransformCha(); 5) Character effects panel; 6) Displaying the levels of HP and SP under characters and monsters. Thus, with the help of mods, you can fix critical bugs and vulnerabilities, change settings, add new functionality and features. Initially, the appearance of mods was caused by the lack of open access to the source codes of the client and the server: the developers had no choice but to edit executable .exe files, developing and applying reverse engineering skills. After the publication of the source codes, the popularity of mods still remains at a high level. This is due to a few reasons: 1) Low quality of the received source codes, lack of experience in their use. To use them, the administrator needs to have an extensive knowledge of the C++ programming language, understand the client-server architecture, and understand how the server and the client work. In addition, the source codes require a long study and research for bugs and vulnerabilities, including the testing process; 2) The existing official builds of the server and client fully satisfy the requirements of most administrators and players, in addition, their performance and reliability have been confirmed by years of use. Many programs, scripts and mods were written for them, which may be incompatible with the server and client executable files compiled from the source codes; 3) The source code researching allows you to better understand the structure of the server and client executables (GameServer.exe, Game.exe). The knowledge gained makes it possible to create mods of increased complexity. When implementing their projects, administrators and developers can go in two ways: use the old, official builds of the server and client, and change their functionality using mods, or go towards the development of source codes. As it should already be clear, this topic supports the first way. At the moment, mod development is associated with some problems: 1) Our community lacks a clear standard and culture for writing mods. Someone injects the code directly into the executable file ("patching"), others prefer to write DLL. Some mods can conflict with each other, which leads to errors and subtle bugs; 2) Installing mods involves certain difficulties: for example, how to transfer a mod from one GameServer.exe to another one? Each time you need to do editing (patching) .exe file, and for this you need to have special knowledge and skills. If the mods are made in the form of DLL libraries, then each mod must be manually added into the import table of the executable file. All this is inconvenient, time-consuming and creates the possibility of errors and bugs during the installation process; 3) There are many versions of GameServer.exe and Game.exe (the rest of the server .exe's are not taken into account), which have a different binary structure. In other words, the developed mod for GameServer.exe version 1.36 will not work with GameServer.exe version 1.38 - you need to develop the mod for a specific .exe file. As a result, there is confusion about the versions of the executable files. A shining example is the addresses of the limits for .txt/.bin tables, I think many have noticed that they are different for different .exe. Based on the above, it was decided to create a system that would solve the current state of affairs in regards to mods and simplify their usage. The Mod Loader The mod loader performs several tasks: 1) Determining the type and version of the executable file (.exe) to be modified; 2) Searching for mods, determining their version, attaching to the process of the executable file; 3) Unification of the process of creating, installing and uninstalling mods. It is a DLL library that attaches one-time to the executable file of the server or client. Mods are also DLL libraries that are placed in a specific directory and are automatically launched by the loader when the server or client executable file starts. Before running the executable file, control is transferred to the loader. The loader determines the type and version of the .exe file to which it is attached and starts the process of searching for DLL libraries in the "mods" directory from the server or client root folder. The DLLs found are dynamically attached to the server or client process after which the loader requests the library information regarding the mod name, type, version of the executable target file, name and the author of the mod. If the type and version of the .exe file with attached loader matches the type and version of the .exe file obtained from the mod's library, then the loader gives the mod a command to start. Furthermore, changes to the code of the process of the executable file, thereby carrying out the modification. Before terminating the server or client process, control is again gained to the loader, which in turn detaches all mods from the process. The current version of the mod loader can work with the official 1.3x versions of GameServer.exe (server) and Game.exe (client). The type of executable file (GameServer.exe or Game.exe) and its version is determined by the build timestamp (linker timestamp), which is written in the COFF header of each executable. Supported GameServer.exe and Game.exe ---------------------+----+----------------+-------------- Name | ID | Designation | Time stamp ---------------------+----+----------------+-------------- GameServer.exe 1.36 | 1 | GAMESERVER_136 | 1204708785 ---------------------+----+----------------+-------------- GameServer.exe 1.38 | 2 | GAMESERVER_138 | 1204708785 ---------------------+----+----------------+-------------- Game.exe | 3 | GAME_13X_0 | 1222073761 ---------------------+----+----------------+-------------- Game.exe | 4 | GAME_13X_1 | 1243412597 ---------------------+----+----------------+-------------- Game.exe | 5 | GAME_13X_2 | 1252912474 ---------------------+----+----------------+-------------- Game.exe | 6 | GAME_13X_3 | 1244511158 ---------------------+----+----------------+-------------- Game.exe | 7 | GAME_13X_4 | 1585009030 ---------------------+----+----------------+-------------- Game.exe | 8 | GAME_13X_5 | 1207214236 ---------------------+----+----------------+-------------- GateServer.exe 1.38 | 101| GATESERVER_138 | 1224838480 ---------------------+----+----------------+-------------- Installing the Mod Loader 1) In the root directory of the executable file, create a folder called "mods" *. This folder will store DLL libraries of mods; 2) Open the executable file in CFF Explorer. Go to the "Import adder" tab (1); 3) Click the "Add" button (2) and select the pkodev.mod.loader.dll file (see the attachments at the end of this post); 4) In the "Exported functions" list, select "ExportedFunction" (3); 5) Click the "Import By Name" button (4); 6) Uncheck the "Rebuild OFTs" checkbox (5); 7) Click the "Rebuild Import Table" button (6); 8 ) Save the file (7). 9) Run the executable file. You should see the following message in the console window: [pkodev.mod.loader] ----------------------------------------------- [pkodev.mod.loader] PKOdev.NET mod loader ver. 1.0 by V3ct0r [pkodev.mod.loader] ----------------------------------------------- If the executable file does not have a console window, for example, Game.exe, then run it as follows: system\Game.exe startgame > output.txt The console output will now be redirected to the text file output.txt. * Note: for Game.exe, the mods folder must be in the client's root directory, not in the "system" folder. Installing mods To install a mod, just place its DLL library in the "mods" folder. For convenience, each mod can be placed in a separate folder. An example of a folder structure for GameServer.exe: GameServer | -> Mods | -> .disabled | -> .priority | -> pkodev.mod.example1.server.138.dll | -> pkodev.mod.example2 | -> pkodev.mod.example2.server.138.dll | -> pkodev.mod.example3 | -> pkodev.mod.example3.server.138.dll After launching the executable file, you should see the new mod in the list of loaded mods: Uninstalling mods To uninstall a mod, you need to delete its DLL library from the "mods" folder. Temporary disabling of mods To disable the loading of certain mods, create a ".disabled" file in the root directory with mods ("mods" folder) and write the names of the mods that you want to temporarily disable into it from a new line. For example: // File: mods\.disabled // Write here the names of mods that do not need to be loaded pkodev.mod.fullmap pkodev.mod.tablelimit Thus, mods "pkodev.mod.fullmap" and "pkodev.mod.tablelimit" will be ignored by the loader. Mod loading priority The mod loader allows you to load certain mods in the specified order. To do this, create a ".priority" file in the root directory with mods ("mods" folder) and write down the names of mods in it in descending order of priority. Mods not listed in this file will be loaded after mods with priority, in random order. For example: // File mods\.priority // Write down mods loading priority in descending order here pkodev.mod.power pkodev.mod.tablelimit pkodev.mod.fullmap Mods will be loaded in the following order: 1. pkodev.mod.power; 2. pkodev.mod.tablelimit; 3. pkodev.mod.fullmap; 4. Next - all other mods found in the "mods" folder in random order. Creating a mod In order for a mod to be loaded by the mod loader, it must meet the following requirements: 1) The name of the DLL library of the mod should be like: pkodev.mod.<mod name>.<client or server>.<.exe designation >.dll Examples: pkodev.mod.tablelimit.client.13x_0.dll pkodev.mod.mobspawn.server.138.dll 2) DLL library of the mod should export 3 functions: __declspec(dllexport) void __cdecl GetModInformation(mod_info& info) Fill in the structure of type mod_info. This structure contains basic information about the mod: its name, version, author name, executable file ID for which the mod is intended. // Mod information structure struct mod_info { // Mod name char name[128]; // Mod version char version[64]; // Author’s name char author[64]; // Type and version of the target .exe file (see the table) unsigned int exe_version; }; __declspec(dllexport) void __cdecl Start(const char* path) Enable the mod and modify the process of the executable file. The path variable contains the path to the root directory of the mod. In this function, the mod must perform its initialization, load the necessary settings and modify the process of the executable file. __declspec(dllexport) void __cdecl Stop() Disable the mod. In this function, the mod must save its settings, roll back the process modification (optional) and free resources. 3) The type and version of the executable file specified in the DLL library of the mod (structure modinfo, field exe_version) must match the type and version of the executable file for which it is intended. If the loader has defined the type and version of the executable file as GameServer.exe 1.38 (GAMESERVER_138) with ID 2, then the mod's DLL library should write the value 2 in the exe_version field, otherwise the mod will be determined as unsuitable. Mod development example Any programming language can be used to develop the mod which supports creating DLLs. I will use the C++ as programming language and the Visual Studio 2019 Community as development environment. As an example, let's create a mod for GameServer.exe version 1.38 that will display the "Hello world!" message in its window. 1) Let's define the name of the mod, let it be: pkodev.mod.helloworld Then the name of the DLL library of the mod will be: pkodev.mod.helloworld.server.138.dll 2) Create a Dynamic-Link Library (DLL) project; 3) Add the loader.h file to the project (see the attachments at the end of this post); 4) Implement the function GetModInformation(): void GetModInformation(mod_info& info) { strcpy_s(info.name, "pkodev.mod.helloworld"); strcpy_s(info.version, "1.0"); strcpy_s(info.author, "V3ct0r"); info.exe_version = GAMESERVER_138; } 5) Implement the function Start() void Start(const char* path) { std::cout << "Hello world!" << std::endl; std::cout << "path = " << path << std::endl << std::endl; } 6) Implement the function Stop() void Stop() { } 7) Compile the project. As a result, we’ll get the file pkodev.mod.helloworld.server.138.dll; 8 ) Install and test the mod. In the GameServer.exe window, we should see the message "Hello world!" and the path to the root directory of the mod. The sample mod project can be found in the attachments. Download 1) The mod loader; 2) Source code of the mod loader (C++); 3) Interface for creating mods (file loader.h); 4) The project of the sample mod "Hello world!" for Visual Studio 2019 Community (C++); 5) Samples of client and server executables from the table (7.3 MB); 6) PKOdev .NET mod loader project template for Visual Studio 2019 Community (C++). Available mods 1) Connecting Game.exe to Stall Server ("offline" stalls server connector); 2) Fixing instant respawn of killed monsters after GameServer restart; 3) Editing the limits of .txt tables; 4) Player rating system; 5) System of daily rewards for entering the game; 6) Automatically connect to the server / enter the game (Client modification that allows you to automatically connect to the server); 7) Displaying coordinates under the NPC; 8 ) Displaying additional parameters on the form with character characteristics (frmState); 9) Displaying the cooldown of skills; 10) Displaying the player's character level next to its name; 11) Antibot; 12) Displaying the name of the item in the apparel; 13) Displaying the level of items on their icons ("smart icons"); 14) Change the size of the monsters; 15) Server time; 16) Social buttons (Discord, Youtube, Twitch and etc); 17) Medals (necklaces) with titles; 18) Displaying servers response time ("ping") on the server selection form; 19) Contract system; 20) Disabling error messages when compiling .txt tables (table_bin); 21) Colored GM messages (GM notice); 22) Fixing the resetting character professions when reconnecting to the server; 23) Cleaning up chats; 24) Disabling password verification when entering into the in-game shop (IGS); 25) 60 frames per second (60 FPS); 26) Flying effect for wings; 27) Full area map for the region; 28) Highlight friends and enemies with color. (updated on 02/18/2022) If you have any questions or have problems, then feel free to write in this thread.
  20. 4 points
    04/21/2022 + The project has been upgraded to Visual Studio Community 2022; + Added the feature to automatically close the offline stall if it becomes empty (all items are sold). This behavior is enabled or disabled using the 'close_stall_on_empty' option in the 'pkodev.stallserver.cfg' configuration file; + Sending the client's IP address in the login packet to the GateServer to determine the IP addresses of the players behind the StallServer. GateServer should have the appropriate extension installed. This behavior is enabled or disabled using the 'ip_mod' option in the 'pkodev.stallserver.cfg' configuration file; + Insignificant code fixes and other minor changes. All changes have been commited to the project repository on GitHub. Don't forget to update the configuration file 'pkodev.stallserver.cfg'.
  21. 4 points
    Загрузчик модов для сервера и клиента (PKOdev.NET mod loader) Проблема Многим разработчикам и администраторам серверов Пиратии в нашем сообществе известно, что функциональность клиента и сервера можно изменять так называемыми модами (аддонами, плагинами, дополнениями, патчами). Например: 1) Исправление SQL-инъекций в AccountServer.exe и GroupServer.exe; 2) Увеличение лимитов для .txt/.bin файлов (ItemInfo, CharacterInfo, SkillInfo и других); 3) Обработка сообщений в канал местного чата с помощью lua функции HandleChat(); 4) Трансформация персонажей с помощью lua функции TransformCha(); 5) Панель наложенных на персонажа эффектов; 6) Отображение уровня ЖЗ и МН под персонажами и монстрами. Таким образом, с помощью модов можно исправлять критические баги и уязвимости, изменять настройки, добавлять новый функционал и возможности. Изначально появление модов было вызвано отсутствием в открытом доступе исходных кодов клиента и сервера: разработчикам ничего не оставалось, кроме того, как редактировать исполняемые .exe файлы, развивая и применяя навыки реверс-инжиниринга. После публикации "исходников" популярность модов по-прежнему остается на высоком уровне. Этому способствует ряд причин: 1) Низкое качество полученных исходных кодов, отсутствие опыта их использования. Чтобы ими пользоваться, администратору нужно обладать широкими знаниями языка программирования C++, разбираться в клиент-серверной архитектуре, понимать как устроен сервер и клиент. Кроме того, исходные коды требуют длительного изучения и исследования на предмет багов и уязвимостей, включая процесс тестирования; 2) Существующие официальные сборки сервера и клиента в полной мере удовлетворяют требованиям большинства администраторов и игроков, кроме того, их работоспособность и надежность подтверждена годами практического применения. Для них было создано множество программ, скриптов и модов, которые могут быть несовместимы с исполняемыми файлами сервера и клиента, собранными из исходных кодов; 3) Изучение исходных кодов позволяет лучше понять устройство исполняемых файлов сервера и клиента Пиратии. Такие полученные знания делают возможным создавать моды повышенной сложности. Администраторы и разработчики при реализации своих игровых проектов могут пойти по двум путям: использовать старые, официальные сборки сервера и клиента, и изменять их функционал с помощью модов, либо развиваться в направлении разработки исходных кодов. Как уже должно быть понятно, данная тема поддерживает первый путь. В настоящий момент разработка модов связана с некоторыми проблемами: 1) В нашем сообществе отсутствует четкий стандарт и культура написания модов. Кто-то внедряет код непосредственно в исполняемый .exe файл методом "патчинга", другие предпочитают писать DLL-библиотеки. Некоторые моды могут конфликтовать друг с другом, что приводит к ошибкам и трудноуловимым багам; 2) Как следствие, установка модов сопряжена с определенными трудностями: например, как перенести мод из одного GameServer.exe в другой? Каждый раз необходимо заниматься редактированием ("патчингом") исполняемых .exe файлов, а для этого нужно обладать специальными знаниями и навыками. Если моды выполнены в виде DLL-библиотек, то каждый мод необходимо вручную вносить в таблицу импорта исполняемого .exe файла. Все это неудобно, отнимает много времени и создает вероятность совершения ошибок в процессе установки и появления багов; 3) Существует некоторое множество версий GameServer.exe и Game.exe (остальные серверные исполняемые .exe файлы не принимаем во внимание), которые имеют различную двоичную структуру. Иными словами, разработанный мод для GameServer.exe версии 1.36 не будет работать с GameServer.exe версии 1.38 – Вам необходимо разрабатывать мод под конкретный .exe файл. Вследствие этого возникает путаница с версиями исполняемых файлов. Яркий пример – адреса лимитов для .txt/.bin: думаю, многие заметили что они разные для разных .exe. Исходя из вышесказанного, было принято решение создать систему, которая исправит текущее положение вещей в отношении модов и упростит их использование – Загрузчик модов для клиента и сервера. Загрузчик модов Загрузчик модов выполняет несколько задач: 1) Унификация процесса создания, установки и запуска модов; 2) Определение типа и версии исполняемого .exe файла, который подлежит модификации; 3) Поиск установленных модов, определение их версии и совместимости с целевым исполняемым .exe файлом, подключение модов к исполняемому .exe файлу клиента или сервера. Представляет собой DLL-библиотеку, которая единоразово подключается к исполняемому .exe файлу клиента или сервера . Моды так же являются DLL-библиотеками, которые помещаются в определенную директорию и автоматически запускаются загрузчиком при запуске клиента или сервера. Перед запуском исполняемого .exe файла клиента или сервера управление передается загрузчику. Загрузчик определяет тип и версию .exe файла, к которому он привязан, и начинает процесс поиска DLL-библиотек в директории "mods" из корневой папки клиента/сервера. Текущая найденная DLL-библиотека динамически подключается к процессу клиента/сервера, после чего загрузчик запрашивает у библиотеки информацию о моде: название мода, тип и версия целевого .exe файла, версия мода, имя автора модификации. Если тип и версия .exe файла с загрузчиком совпадает с типом и версией .exe файла, полученными из DLL-библиотеки мода, то загрузчик дает моду команду на запуск. Далее мод вносит изменения в код процесса исполняемого файла, тем самым осуществляя модификацию. Перед завершением процесса клиента/сервера управление снова передается загрузчику, который по очереди отключает от процесса все моды. Текущая версия загрузчика может работать с официальными 1.3x версиями Game.exe (клиент) и GameServer.exe (сервер). Определение типа исполняемого файла (GameServer.exe или Game.exe) и его версии производится по метке времени компиляции (linker timestamp), которая записана в COFF-заголовке каждого исполняемого файла. Поддерживаемые Game.exe и GameServer.exe ---------------------+----+----------------+-------------- Название | ID | Обозначение | Метка времени ---------------------+----+----------------+-------------- GameServer.exe 1.36 | 1 | GAMESERVER_136 | 1204708785 ---------------------+----+----------------+-------------- GameServer.exe 1.38 | 2 | GAMESERVER_138 | 1204708785 ---------------------+---+----------------+-------------- Game.exe | 3 | GAME_13X_0 | 1222073761 ---------------------+----+----------------+-------------- Game.exe | 4 | GAME_13X_1 | 1243412597 ---------------------+----+----------------+-------------- Game.exe | 5 | GAME_13X_2 | 1252912474 ---------------------+----+----------------+-------------- Game.exe | 6 | GAME_13X_3 | 1244511158 ---------------------+----+----------------+-------------- Game.exe | 7 | GAME_13X_4 | 1585009030 ---------------------+----+----------------+-------------- Game.exe | 8 | GAME_13X_5 | 1207214236 ---------------------+----+----------------+-------------- GateServer.exe 1.38 | 101| GATESERVER_138 | 1224838480 ---------------------+----+----------------+-------------- Установка загрузчика модов 1) В корневой директории исполняемого .exe файла, к которому подключается загрузчик модов, создайте папку с названием "mods"*. В этой папке будут храниться DLL-библиотеки модов; 2) Откройте исполняемый .exe файл в программе CFF Explorer. Перейдите на вкладку "Import adder" (1); 3) Нажмите кнопку "Add" (2) и выберите файл pkodev.mod.loader.dll; 4) В списке "Exported functions" выберите "ExportedFunction" (3); 5) Нажмите кнопку "Import By Name" (4); 6) Снимите флажок "Rebuild OFTs" (5); 7) Нажмите кнопку "Rebuild Import Table" (6); 8 ) Сохраните файл (7). 9) Запустите исполняемый .exe файл. В окне консоли вы должны увидеть следующее сообщение: [pkodev.mod.loader] ----------------------------------------------- [pkodev.mod.loader] PKOdev.NET mod loader ver. 1.0 by V3ct0r [pkodev.mod.loader] ----------------------------------------------- Если у исполняемого файла нет окна консоли, например, у Game.exe, то запустите его следующим образом: system\Game.exe startgame > output.txt Теперь вывод в консоль будет перенаправлен в текстовый файл output.txt. * Примечание: для Game.exe папка "mods" должна находиться в корневой директории игрового клиента, а не в папке system. Установка модов Чтобы установить мод достаточно поместить его DLL-библиотеку в папку "mods". Для удобства каждый мод можно помещать в отдельную папку. Пример структуры папок для GameServer.exe: GameServer | -> Mods | -> .disabled | -> .priority | -> pkodev.mod.example1.server.138.dll | -> pkodev.mod.example2 | -> pkodev.mod.example2.server.138.dll | -> pkodev.mod.example3 | -> pkodev.mod.example3.server.138.dll После запуска исполняемого .exe файла Вы должны увидеть новый мод в списке загруженных модов: Удаление модов Чтобы удалить мод, необходимо удалить его DLL-библиотеку из папки "mods". Временное отключение модов Чтобы отменить загрузку тех или иных модов, создайте в корневой директории с модами (папка "mods") файл ".disabled" и запишите в него названия модов, которые необходимо временно отключить, с новой строки. Например: // Файл: mods\.disabled // Запишите ниже названия модов, которые необходимо отключить pkodev.mod.fullmap pkodev.mod.tablelimit Таким образом, моды "pkodev.mod.fullmap" и "pkodev.mod.tablelimit" будут проигнорированы загрузчиком. Приоритет загрузки модов Загрузчик модов позволяет загружать те или иные моды в указанном порядке. Для этого создайте в корневой директории с модами (папка "mods") файл ".priority" и запишите в него названия модов в порядке убывания приоритета. Моды, не записанные в данном файле, будут загружены после модов с приоритетом, в случайном порядке. Например: // Файл mods\.priority // Запишите ниже названия модов в порядке убывания приоритета загрузки pkodev.mod.power pkodev.mod.tablelimit pkodev.mod.fullmap Моды будут загружены в следующем порядке: 1. pkodev.mod.power; 2. pkodev.mod.tablelimit; 3. pkodev.mod.fullmap; 4. Далее - все остальные обнаруженные в папке "mods" моды в случайном порядке. Создание мода Для того, чтобы мод мог быть загружен загрузчиком, он должен соответствовать следующим требованиям: 1) Название DLL-библиотеки мода должно быть вида: pkodev.mod.<название мода>.<client или server>.<обозначение версии.exe >.dll Например: pkodev.mod.tablelimit.client.13x_0.dll pkodev.mod.mobspawn.server.138.dll 2) DLL-библиотека мода должна экспортировать 3 функции: __declspec(dllexport) void __cdecl GetModInformation(mod_info& info) Заполнить структуру типа mod_info. Данная структура содержит основную информацию о моде: название, версию, имя автора, ID типа и версии исполняемого .exe файла, для которого предназначен мод. // Mod information structure struct mod_info { // Название мода char name[128]; // Версия мода char version[64]; // Имя автора char author[64]; // Тип и версия целевого .exe файла (см. таблицу) unsigned int exe_version; }; __declspec(dllexport) void __cdecl Start(const char* path) Запустить мод и произвести модификацию процесса исполняемого файла. В переменной path содержится путь до корневой директории мода. В данной функции мод должен выполнить свою инициализацию, загрузить необходимые настройки и произвести модификацию процесса исполняемого файла. __declspec(dllexport) void __cdecl Stop() Остановить мод. В данной функции мод должен сохранить свои настройки, откатить модификацию процесса (необязательно) и освободить ресурсы. 3) Тип и версия исполняемого файла, указанная в DLL-библиотеке мода (структура modinfo, поле exe_version), должны совпадать с типом и версией исполняемого файла, для которого он предназначен. Если загрузчик определил тип и версию исполняемого файла как GameServer.exe 1.38 (GAMESERVER_138) с ID 2 (см. таблицу выше), то DLL-библиотека мода должна записывать в поле exe_version значение 2. Пример разработки мода Для разработки мода можно использовать любой язык программирования, который поддерживает создание DLL-библиотек. Я буду использовать язык C++ и среду разработки Visual Studio 2019 Community. В качестве примера создадим мод для GameServer.exe версии 1.38 (ID 2), который будет выводить в его окно сообщение "Hello world!". 1) Определим название мода, пусть оно будет: pkodev.mod.helloworld Тогда название DLL-библиотеки мода будет: pkodev.mod.helloworld.server.138.dll 2) Создадим проект динамически подключаемой библиотеки .DLL; 3) Подключаем к проекту файл loader.h (см. вложения в конце данного сообщения); 4) Реализуем функцию GetModInformation(): void GetModInformation(mod_info& info) { strcpy_s(info.name, "pkodev.mod.helloworld"); strcpy_s(info.version, "1.0"); strcpy_s(info.author, "V3ct0r"); info.exe_version = GAMESERVER_138; } 5) Реализуем функцию Start(): void Start(const char* path) { std::cout << "Hello world!" << std::endl; std::cout << "path = " << path << std::endl << std::endl; } 6) Реализуем функцию Stop(): void Stop() { } 7) Скомпилируем проект. В результате мы получим файл pkodev.mod.helloworld.server.138.dll; 8 ) Устанавливаем и тестируем мод. В окне GameServer.exe мы должны увидеть сообщение "Hello world!" и путь до корневой директории мода: Проект примера мода можно найти во вложении. Скачать 1) Загрузчик модов; 2) Исходный код загрузчика модов для Visual Studio 2019 Community (C++); 3) Интерфейс для создания модов (файл loader.h); 4) Проект примера мода "Hello world!" для Visual Studio 2019 Community (C++); 5) Образцы исполняемых файлов клиента и сервера из таблицы (7.3 Мб); 6) Шаблон проекта мода PKOdev.NET loader для Visual Studio 2019 Community (C++). Доступные моды 1) Подключение Game.exe к Stall Server (сервер "оффлайн" ларьков); 2) Исправление мгновенного возрождения убитых монстров после перезапуска сервера; 3) Редактирование лимитов .txt таблиц; 4) Система рейтинга игроков; 5) Система ежедневных наград за вход в игру; 6) Отображение времени отката ("кулдауна") умений; 7) Отображение координат под NPC; 8 ) Автоматическое подключение к серверу / вход в игру; 9) Социальные кнопки (Discord, Youtube, Twitch и др.); 10) Медали (ожерелья) со званиями; 11) Отображение уровня персонажа игрока рядом с его именем; 12) Отображение дополнительных параметров на форме с характеристиками персонажа (frmState); 13) Время сервера; 14) Антибот; 15) Отображение уровня предметов на иконках ("умные иконки"); 16) Отображение названия предмета в аппарели; 17) Изменение размера персонажей; 18) Отображение времени отклика ("пинг") на форме выбора сервера; 19) Система контрактов; 20) Отключение проверки пароля при входе во внутриигровой Интернет-магазин; 21) Отключение сообщений об ошибках при компиляции .txt-таблиц (table_bin); 22) Очистка чатов; 23) Исправление сброса профессии персонажей при переподключении к серверу ("слёт профессии"); 24) Цветные GM-сообщения (GM notice); 25) 60 кадров в секунду (60 FPS); 26) Эффект полета для крыльев; 27) Полная карта местности для региона; 28) Выделение друзей и врагов цветом. (Обновлено 18.02.2022) Если у Вас есть какие-либо вопросы или возникли проблемы, то смело спрашивайте в данной теме!
  22. 4 points
    [Mod] System of daily rewards for entering the game This mod implements a system of daily rewards for entering the game. Players need to enter the game every day in order to receive the next reward - with each new day the reward becomes more valuable. The chain resets and starts over from the first day if a player misses a day. The chain is also reset every week. The chain of rewards is configured by the administrator in a special lua function and is generated for a week forward, after which it is saved in the server database. Requirements Installed mod loading system for server and client (PKOdev.NET mod loader). Modification information Name: pkodev.mod.reward; Version: 1.0; Author: V3ct0r; Type: for client and server (Game.exe and GameServer.exe); Supported executable .exe files: GAME_13X_0, GAME_13X_1, GAME_13X_2, GAME_13X_3, GAME_13X_4, GAME_13X_5, GAMESERVER_136 and GAMESERVER_138. Installation Server: 1) In the "GameServer\mods" directory of your server, create a "pkodev.mod.reward" folder; 2) Place into the folder the mod DLL file "pkodev.mod.reward.server.13<x>.dll" for your version of GameServer.exe; 3) In the functions.lua file ("GameServer\resource\script\calculate\") write the following script: -- Daily reward system (pkodev.mod.reward) -- Transfer the list of items to the system function GetRewardArrayAdapter(role) -- Get a list of items for daily reward local arr = GetRewardArray(role) -- Transfer the list to the system return arr[1].id, arr[1].number, arr[2].id, arr[2].number, arr[3].id, arr[3].number, arr[4].id, arr[4].number, arr[5].id, arr[5].number, arr[6].id, arr[6].number, arr[7].id, arr[7].number end -- Daily reward system (pkodev.mod.reward) -- Get a list of items for daily reward function GetRewardArray(role) -- Select an item depending on character race local hairstyle_book = function(role) -- List of items -- ID: 931 Lance Trendy Hairstyle Book -- ID: 932 Carsise Trendy Hairstyle Book -- ID: 933 Phyllis Trendy Hairstyle Book -- ID: 934 Ami Trendy Hairstyle Book local items = {931, 932, 933, 934} -- Get character type ID local id = GetChaTypeID(role) -- Return item id depending on the type ID return items[id] or 0 end -- Make a list of items for daily reward local items = { -- Day 1 (Short Sword x 1 or Long Sword x 1 or Fencing Sword x 1) {id = math.random(1, 3), number = 1}, -- Day 2 (Apple x 99 or Bread x 99 or Cake x 99) {id = math.random(1847, 1849), number = 99}, -- Day 3 (Fairy Coin x 50) {id = 855, number = 50}, -- Day 4 (Random fairy ID 183 ... 193 x 1) {id = math.random(183, 193), number = 1}, -- Day 5 (Hairstyle Book x 1) {id = hairstyle_book(role), number = 1}, -- Day 6 (Fairy Ration x 10) {id = 227, number = 10}, -- Day 7 (Refining Gem x 1) {id = 885, number = 1} } -- We have to return an array of items to caller function return items end 4) In MSSQL Management Studio, execute the SQL query: USE GameDB ALTER TABLE character ADD reward VARCHAR(128) NOT NULL DEFAULT '0' WITH VALUES Client: 1) In the "mods" directory of your client create a "pkodev.mod.reward" folder; 2) Place into the folder the mod DLL file "pkodev.mod.reward.client.13x_<x>.dll" for your version of Game.exe; 3) Place the daily reward form texture files "main.png" and "buttons.tga" into the "texture\mods\pkodev.mod.reward\" directory of your client; 4) Add the code for the daily reward form into the "main.clu" script file ("scripts\lua\forms\"): ---------------------------------------------------------------------------------------------------- -- Daily login reward form ---------------------------------------------------------------------------------------------------- -- The form frmReward = UI_CreateForm( "frmReward", FALSE, 366, 158, 150, 200, TRUE, FALSE ) UI_SetFormStyle( frmReward , 0 ) UI_AddFormToTemplete( frmReward, FORM_MAIN ) UI_FormSetIsEscClose( frmReward, FALSE ) UI_SetIsDrag( frmReward, TRUE ) -- Form background frmRewardImg = UI_CreateCompent( frmReward, IMAGE_TYPE, "frmRewardImg", 366, 158, 0, 0 ) UI_LoadImage( frmRewardImg, "texture/mods/pkodev.mod.reward/main.png", NORMAL, 366, 158, 0, 0 ) -- Form title labTitle = UI_CreateCompent( frmReward, LABELEX_TYPE, "labTitle", 400, 150, 10, 7 ) UI_SetCaption( labTitle, "Daily reward!") UI_SetTextColor( labTitle, COLOR_WHITE ) -- Reward button btnGetReward = UI_CreateCompent( frmReward, BUTTON_TYPE, "btnGetReward", 67, 24, 150, 120 ) UI_LoadButtonImage( btnGetReward, "texture/mods/pkodev.mod.reward/main.png", 67, 24, 0, 158, TRUE ) -- Close button btnClose = UI_CreateCompent( frmReward, BUTTON_TYPE, "btnClose", 21, 21, 343, 2 ) UI_LoadButtonImage( btnClose, "texture/mods/pkodev.mod.reward/buttons.tga", 21, 21, 270, 0, TRUE ) UI_SetButtonModalResult( btnClose, BUTTON_CLOSE ) -- Item slots cmdItemSlot0 = UI_CreateCompent( frmReward, COMMAND_ONE_TYPE, "cmdItemSlot0", 32, 32, 20, 73 ) UI_SetIsDrag( cmdItemSlot0, FALSE ) cmdItemSlot1 = UI_CreateCompent( frmReward, COMMAND_ONE_TYPE, "cmdItemSlot1", 32, 32, 69, 73 ) UI_SetIsDrag( cmdItemSlot1, FALSE ) cmdItemSlot2 = UI_CreateCompent( frmReward, COMMAND_ONE_TYPE, "cmdItemSlot2", 32, 32, 118, 73 ) UI_SetIsDrag( cmdItemSlot2, FALSE ) cmdItemSlot3 = UI_CreateCompent( frmReward, COMMAND_ONE_TYPE, "cmdItemSlot3", 32, 32, 167, 73 ) UI_SetIsDrag( cmdItemSlot3, FALSE ) cmdItemSlot4 = UI_CreateCompent( frmReward, COMMAND_ONE_TYPE, "cmdItemSlot4", 32, 32, 216, 73 ) UI_SetIsDrag( cmdItemSlot4, FALSE ) cmdItemSlot5 = UI_CreateCompent( frmReward, COMMAND_ONE_TYPE, "cmdItemSlot5", 32, 32, 265, 73 ) UI_SetIsDrag( cmdItemSlot5, FALSE ) cmdItemSlot6 = UI_CreateCompent( frmReward, COMMAND_ONE_TYPE, "cmdItemSlot6", 32, 32, 314, 73 ) UI_SetIsDrag( cmdItemSlot6, FALSE ) ---------------------------------------------------------------------------------------------------- Mod customization 1) In the GetRewardArray(role) function, write the code that will generate the chain of rewards for the character role for the next seven days. The function must return a table of 7 elements with fields id and number, where id is the ID of the item that is issued as a reward, and number is the number of items in the reward. Each element corresponds to its own day (1st element is the first day, 2nd element is the second day, and so on). Example: function GetRewardArray(role) local items = { -- Day 1: Apple x 20 {id = 1847, number = 20}, -- Day 2: Bread x 40 {id = 1848, number = 40}, -- Day 3: Cake x 60 {id = 1849, number = 60}, -- Day 4: Fairy coin x 55 {id = 855, number = 55}, -- Day 5: Fairy ration x 15 {id = 227, number = 15}, -- Day 6: Bread x 99 {id = 1848, number = 99}, -- Day 7: Cake x 99 {id = 1849, number = 99} } return items end Item IDs and their number can be generated randomly or depending on the character's race, profession, etc 2) By default, the reward period is 24 hours. You can change this value in the mod server-side source code (pkodev.mod.reward.server project, structure.h file), then compile the project: // Reward interval in seconds static const unsigned int interval{ 24 * 60 * 60 }; // 24 hours 3) No client side configuration required. Old style GUI (Thanks to @Masuka00!) main.clu: -- Close button btnClose = UI_CreateCompent( frmReward, BUTTON_TYPE, "btnClose", 14, 14, 342, 4 ) UI_LoadButtonImage( btnClose, "texture/mods/pkodev.mod.reward/main.png", 14, 14, 271, 174, TRUE ) UI_SetButtonModalResult( btnClose, BUTTON_CLOSE ) Download Download 1) Binary release (.dll); 2) The source code of the mod for Visual Studio 2019 Community (C++). If you encounter any problem, bug or have any questions, then feel free to write in this thread.
  23. 4 points
  24. 4 points
    Привет, @Ropedann! Хочу внести свой вклад в твой проект. Написал редактор списков NPC (файлов GameServer\resource\<map>\<map>npc.txt ). Pull Request отправлен на GitHub. Я не силен в C#, поэтому мой код может быть не очень качественным. Также хочу поблагодарить @champ за оказанную помощь в решении проблем, с которыми я столкнулся в ходе разработки. Надеюсь, ты не забросишь этот проект.
  25. 4 points
    [Мод] Редактирование лимитов .txt таблиц С помощью данного мода для системы "PKODev.NET mod loader" можно легко редактировать лимиты для .txt/.bin файлов клиента и сервера без необходимости редактирования Game.exe и GameServer.exe соответственно в HEX-редакторе. Лимиты редактируются в текстовом файле pkodev.mod.tablelimit.cfg: areaset = 300 character_lvup = 120 characterinfo = 2500 forgeitem = 12 hairs = 500 int_cha_item = 32 iteminfo = 6000 lifelvup = 1000 saillvup = 1000 shipinfo = 120 shipiteminfo = 500 skilleff = 240 skillinfo = 500 characterposeinfo = 100 chaticons = 100 elfskillinfo = 100 eventsound = 30 itempre = 100 itemrefineeffectinfo = 5000 itemrefineinfo = 20000 itemtype = 100 magicgroupinfo = 10 magicsingleinfo = 100 mapinfo = 100 musicinfo = 500 notifyset = 100 objevent = 10 resourceinfo = 3000 sceneffectinfo = 14000 sceneobjinfo = 800 selectcha = 60 serverset = 100 shadeinfo = 14000 stoneinfo = 100 terraininfo = 100 Необязательно перечислять все таблицы, если требуется отредактировать лимиты только некоторых: iteminfo = 12000 characterinfo = 6000 mapinfo = 500 Таблицы GameServer.exe (13) Таблицы Game.exe (31) Требования Установленный Загрузчик модов для сервера и клиента (PKOdev.NET mod loader). Информация о моде Название: pkodev.mod.tablelimit; Версия: 1.0; Автор: V3ct0r; Тип: для клиента и сервера (Game.exe и GameServer.exe); Поддерживаемые исполняемые .exe файлы: GAME_13X_0, GAME_13X_1, GAME_13X_2, GAME_13X_3, GAME_13X_4, GAME_13X_5, GAMESERVER_136 и GAMESERVER_138. Установка 1) В директории "mods" Вашего сервера или клиента создайте папку "pkodev.mod.tablelimit"; 2) Поместите в неё файл DLL-библиотеки мода "pkodev.mod.tablelimit.<client/server>.<x>.dll" для Вашей версии Game.exe или GameServer.exe; 3) Поместите в неё файл настроек мода "pkodev.mod.tablelimit.cfg"; 4) Отредактируйте файл "pkodev.mod.tablelimit.cfg" по своему усмотрению - укажите требуемые значения лимитов для каждого файла .txt/.bin таблиц: <Название таблицы> = <Значение лимита> Скачать 1) Бинарные файлы мода (.dll); 2) Исходный код мода для Visual Studio 2019 Community (C++). Если Вы столкнулись с какой-либо проблемой, багом или у Вас возникли вопросы, то пишите в данной теме.
  26. 4 points
    Hi folks, I have seen a few members selling this type of auto updater and decided to write one myself and hopefully help some of you create your very first auto updater from scratch To follow this tutorial, you should have basic understanding of C# (or any similar programming language), be familiar with object-oriented programming as well as know how GitHub or any sort of source control works. Problem: the majority of updaters require manual configuration and patches specification, which is error-prone and time-consuming. Solution: create a GitHub repository with the latest version of game client. Create an updater that will scan through the commits and automatically either update or delete necessary files. To simplify this tutorial, I have already written a library in C# that integrates with GitHub and does necessary API calls, which we will use later in the tutorial. Prerequisites: Microsoft Visual Studio 2019+, .NET 5.0 framework and some spare time. Part 1: Project set-up and basic UI. To begin with, open Microsoft Visual Studio and select a .NET WPF application. WPF is a slightly more complicated that Windows Forms, so if you're more familiar with the latter one, then feel free to go for it. I will be using WPF for the sake of performance. Client "Next", specify the project name and location then choose the latest .NET framework available, in my case that is 4.8. Once that is done, Microsoft Visual Studio will generate the project and load it for you. Our basic structure is ready at this point. Now, it is up to you how you want this updater to work and you do not have to stick to the UI that I will be creating. For this project, I want to create some sort of a splash screen that will be shown while we are updating the client or searching for updates and when that's done, I want to show the main updater application with all the links and images, so I am going to create a loading screen first. To do so, right click on your project name in the right hand side of the screen under "Solution Explorer" tab and select Add -> New Item. After that find an option called "WPF Window", specify a name for it and click "Add": Now that we have created our splash screen window, I would like to modify some of its properties. For instance, on window load I would like it to be rendered in the center of the user's screen. Additionally, I would like to change the title, width and height of the window. To do so, you could either modify the properties directly via XML file or by right clicking on the window file and selecting "Properties" item: Now that our basic window is done, we need to check the application start up path or in other words the window that will be ran when we execute the application. To do that, go to your App.xaml file and modify StartupUri property to whatever you have called your splash screen, in my case it is LoadingWindow.xaml: Now we can test our loading screen by debugging the application. To debug the application you can either press F5 or click on "Start" button that has a green arrow next to it: Once the project has finished compiling, you should see our loading window: Now we have the loading window it is great and all. However, I would like to make it more informative by adding a status label and a progress bar to it, which will indicate that something is happening. To do that, open your Toolbox tab, which can normally be found on the left hand side of the screen. If you are missing this tab, then you can also find the Toolbox window by finding it in VS View -> Toolbox (or by pressing CTRL + ALT + X): Cool, so I am going to drag a label, which will be our status text and a progress bar which will indicate that some sort of a process is happening whilst the window is open. To do that, I am going to use a marquee progress bar, which can be done by setting IsIndeterminate property of the progress bar to true: Now if we debug our application window again, we will see our loading window with the progress bar and status label:
  27. 4 points
    [Mod] Server time The mod adds a text label with a clock to the game - the current server time. The server time is taken from the packet ID: 940 that the server sends to the client upon connection, for example: [01-17 10:44:47:879] The clock label is bound to the minimap form "frmMinimap" from the GUI script file "\scripts\lua\forms\minimap.clu". Requirements Installed mod loading system for server and client (PKOdev.NET mod loader). Modification information Name: pkodev.mod.clock; Version: 1.0; Author: V3ct0r; Type: for client (Game.exe); Supported executable .exe files: GAME_13X_0, GAME_13X_1, GAME_13X_2, GAME_13X_3, GAME_13X_4 and GAME_13X_5. Installation 1) In the "mods" directory of your client, create a "pkodev.mod.clock" folder; 2) Place into it the mod DLL file "pkodev.mod.clock.client.13x_<ID>.dll" for your version of Game.exe; 3) Place into it the mod settings file "pkodev.mod.clock.cfg" and write to the file the desired server time output format in accordance with the documentation for the strftime() function. For example, the format: Server time: %H:%M:%S %d.%m.%y May give the following output: Server time: 10:51:20 17.01.2022 4) In the GUI script file "\scripts\lua\forms\minimap.clu" add the code for the "labClock" text label, which will be responsible for displaying the server time: ------------------------------------------------------------------------------------------ -- Clock label ------------------------------------------------------------------------------------------ labClock = UI_CreateCompent(frmMinimap, LABELEX_TYPE, "labClock", 20, 15, 20, 220) UI_SetCaption(labClock, "Clock") UI_SetTextColor(labClock, COLOR_WHITE) UI_SetLabelExFont(labClock, DEFAULT_FONT, TRUE, COLOR_BLACK) ------------------------------------------------------------------------------------------ Download 1) Binary release (.dll); 2) The source code of the mod for Visual Studio 2019 Community (C++). If you encounter any problem, bug or have any questions, then feel free to write in this thread.
  28. 4 points
    [Мод] Система контрактов Данная система представляет собой импровизированный квест типа "Охота на монстров", целью которого является убийство некоторого числа определенных монстров. Игроку выдается специальный предмет - "Контракт", в котором написано на какого монстра необходимо охотиться. Так же в нем записывается число монстров и текущий прогресс. После убийства необходимого числа монстров контракт считается выполненным, а игрок получает награду. Некоторые особенности системы: 1) Тип предмета для контракта должен быть 99. Для предмета также выбирается уникальный ID; 2) Контракт можно подобрать, выбросить, передать другому игроку, положить в банк или продать; 3) Для получения награды после завершения контракта, игрок должен использовать предмет контракта двойным кликом. Если контракт не был завершен, то игрок увидит соответствующее сообщение в систему; 4) Состав и количество награды определяется администратором в специальной функции в скрипте системы; 5) Если у игрока в инвентаре несколько контрактов на убийство одного и того же монстра, то при убийстве данного монстра тот или иной контракт выбирается случайным образом. Установка Все необходимые файлы и скрипты можно скачать в конце темы. Сервер 1) Добавьте в файл ItemInfo.txt предмет для контракта: XXXX Contract n0184 10130005 0 0 0 0 0 00 99 0 0 0 0 0 1 1 1 1 1 1 0 -1 0 -1 0 0 -1 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0 10,10 0,0 0 0 0 0 0 0 0 0 0 ItemUse_PKOdevContract 0 0 0 0 0 0 After completion you will receive a reward! где XXXX - любой незанятый ID. 2) Создайте файл с названием "pkodev.contract.lua" в директории "GameServer\resource\script\calculate\mods"; 3) Поместите в данный файл следующий код: -------------------------------------------------------------- -- The contract system script -- -- Author: V3ct0r from PKOdev.NET -- Version: 1.0 (01/12/2022) -- -- How to install the system: -- 1) Put this file to '\GameServer\resource\script\calculate\mods' folder -- 2) Put the following line at the beginning of 'SkillEffect.lua' file: -- dofile(GetResPath("script\\calculate\\mods\\pkodev.contract.lua")) -- 3) Add the contract item in the ItemInfo.txt file -- XXXX Contract n0184 10130005 0 0 0 0 0 00 99 0 0 0 0 0 1 1 1 1 1 1 0 -1 0 -1 0 0 -1 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0 10,10 0,0 0 0 0 0 0 0 0 0 0 ItemUse_PKOdevContract 0 0 0 0 0 0 Upon completion, you are entitled to a reward -- 4) Specify the item ID in 'contract.conf.item_id' table below: -- item_id = XXXX -- 5) Write the code for issuing a reward for completing a contract in the 'contract.conf.reward_cb' function -- 6) To create a new contract use the function 'contract.create': -- local <result (0 or 1)>, <item_descriptor>, <slot (from 0 to bag_size - 1)> -- = contract.create(<character_descriptor>, <monster_id>, <monster_number>) -- For example: -- local ret, item, slot = contract.create(role, 103, 7) -- 7) Done! -------------------------------------------------------------- -- Print a log print("Loading pkodev.contract.lua") -- The contract system contract = contract or {} --------------------------------------- -- Settings --------------------------------------- contract.conf = { -- Contract item ID item_id = XXXX, -- User-defined function for reward reward_cb = function(role, item) -- Give 1,000 gold AddMoney (role, 0, 1000) -- Give an random item local arr = { -- Refining Gem x 1 {id = 885, count = 1}, -- or Gem of Rage x 2 {id = 863, count = 2}, -- or Cake x 60 {id = 1849, count = 60}, -- or Fairy of Luck x 1 {id = 231, count = 1} } local r = math.random(1, table.getn(arr)) GiveItem(role, 0, arr[r].id , arr[r].count, 4) -- Launch fireworks PlayEffect(role, 361) end } --------------------------------------- -- Constants --------------------------------------- contract.const = { item_type = 99, -- Contract item type target_id = ITEMATTR_VAL_STR, -- Item attribute ID with the ID of target monster target_max = ITEMATTR_VAL_AGI, -- Item attribute ID with the total amount of monsters to hunt target_cur = ITEMATTR_VAL_DEX -- Item attribute ID with the total amount of monsters already hunted } --------------------------------------- -- Hooks --------------------------------------- -- Adding an item to inventory event contract.Creat_Item__original = Creat_Item Creat_Item = function(item, item_type, item_lv, item_event) -- Check the item type if ( item_type == contract.const['item_type'] ) then -- Reset the previous attrbiutes Reset_item_add() -- Add new attributes to the item Add_Item_Attr(contract.const['target_id'], 0) Add_Item_Attr(contract.const['target_max'], 0) Add_Item_Attr(contract.const['target_cur'], 0) return item_add.cnt, item_add.attr[1][1], item_add.attr[1][2], item_add.attr[2][1], item_add.attr[2][2], item_add.attr[3][1], item_add.attr[3][2], item_add.attr[4][1], item_add.attr[4][2], item_add.attr[5][1], item_add.attr[5][2], item_add.attr[6][1], item_add.attr[6][2], item_add.attr[7][1], item_add.attr[7][2] end -- Call the original function Creat_Item(item, item_type, item_lv, item_event) return contract.Creat_Item__original(item, item_type, item_lv, item_event) end -- Player killed monster event contract.GetExp_PKM__original = GetExp_PKM GetExp_PKM = function(monster, role) -- Call the original function GetExp_PKM(dead, atk) contract.GetExp_PKM__original(monster, role) -- Get the main character's descriptor role = TurnToCha(role) -- Number of contracts in the player's bag local ret = CheckBagItem(role, contract.conf['item_id']) -- Check that player has contracts if ( ret > 0 ) then -- Monster ID local id = GetChaTypeID(monster) -- List of contracts in the bag local arr = {} local k = 0 -- Build the list of contracts for i = 0, ( GetKbCap(role) - 1 ), 1 do -- Get the item descriptor local item = GetChaItem(role, 2, i) -- Check the item ID if ( GetItemID(item) == contract.conf['item_id'] ) then -- Get the monster ID from contract local target_id = GetItemAttr(item, contract.const['target_id']) -- Check the monster ID if ( id == target_id ) then -- Get amount of monsters to hunt local target_cur = GetItemAttr(item, contract.const['target_cur']) local target_max = GetItemAttr(item, contract.const['target_max']) -- Check that the contract is not completed if ( target_cur < target_max ) then -- Add the item to the list k = k + 1 arr[k] = { item_ = item, cur_ = target_cur, max_ = target_max } end end end end -- Check that matching contracts have been found if ( k > 0 ) then -- Randomly select a contract local r = math.random(1, k) -- Increase the number of hunted monsters arr[r].cur_ = arr[r].cur_ + 1 -- Update amount of hunted monsters SetItemAttr(arr[r].item_, contract.const['target_cur'], arr[r].cur_) -- Synchronize the bag SynChaKitbag(role, 13) -- Check that the contract is not completed if ( arr[r].cur_ < arr[r].max_ ) then -- Write a message BickerNotice( role, string.format( "Contract: Remaining '%s' to hunt: %d / %d!", GetMonsterName(id), arr[r].cur_, arr[r].max_ ) ) else -- Write a message BickerNotice( role, string.format( "Contract: All '%s' are killed! The contract is completed.", GetMonsterName(id) ) ) end end end end --------------------------------------- -- Useful functions --------------------------------------- -- Create a contract contract.create = function(role, target_id, number) -- Get the main character's descriptor role = TurnToCha(role) -- Check that the bag is not locked if ( KitbagLock(role, 0) == LUA_FALSE ) then -- Error LG("pkodev.contract", "Can't create the contract item (id:", contract.conf['item_id'], ") because the bag is locked!") return LUA_FALSE, nil, 0 end -- Check that the bag has one free slot if ( GetChaFreeBagGridNum(role) == 0 ) then -- Error LG("pkodev.contract", "Can't create the contract item (id:", contract.conf['item_id'], ") because there are no free slots in the bag!") return LUA_FALSE, nil, 0 end -- Create an item local r1, r2 = MakeItem(role, contract.conf['item_id'], 1, 4) -- Check the result if ( r1 == 0 ) then -- Error LG("pkodev.contract", "Can't create the contract item (id:", contract.conf['item_id'], ")!") return LUA_FALSE, nil, 0 end -- Get the item descriptor local item = GetChaItem(role, 2, r2) -- Set contract data local a1 = SetItemAttr(item, contract.const['target_id'], target_id) local a2 = SetItemAttr(item, contract.const['target_max'], number) local a3 = SetItemAttr(item, contract.const['target_cur'], 0) -- Check that the data is set if ( (a1 == 0) or (a2 == 0) or (a3 == 0) ) then -- Error LG("pkodev.contract", "Can't set the contract data! a1 = ", a1, ", a2 = ", a2, ", a3 = ", a3) return LUA_FALSE, item, r2 end -- Synchronize the kitbag SynChaKitbag(role, 13) -- Write a message to the player SystemNotice(role, string.format("You received a monster hunt contract [%s] x %d!", GetMonsterName(target_id), number)) -- The contract is successfully created! return LUA_TRUE, item, r2 end -- Contract item use event ItemUse_PKOdevContract = function(role, item) -- Get the main character's descriptor role = TurnToCha(role) -- Get contract data local target_id = GetItemAttr(item, contract.const['target_id']) local target_max = GetItemAttr(item, contract.const['target_max']) local target_cur = GetItemAttr(item, contract.const['target_cur']) -- Check that the contract is not completed if ( target_cur < target_max ) then -- Print a message SystemNotice( role, string.format("You have to kill [%s] x %d more to complete this contract!", GetMonsterName(target_id), (target_max - target_cur) ) ) -- Cancel the item usage UseItemFailed(role) else -- Print a message SystemNotice(role, "You have successfully completed the contract, congratulations!") -- Call user-defined reward function if ( contract.conf['reward_cb'] ~= nil ) then contract.conf['reward_cb'](role, item) end end end 5) Запишите в скрипт системы ID предмета контракта из ItemInfo.txt: contract.conf = { -- Contract item ID item_id = XXXX, . . . 6) Запишите в функцию reward_cb() код для выдачи награды за выполнение контракта: -- User-defined function for reward reward_cb = function(role, item) -- Give 1,000 gold AddMoney (role, 0, 1000) -- Give an random item local arr = { -- Refining Gem x 1 {id = 885, count = 1}, -- or Gem of Rage x 2 {id = 863, count = 2}, -- or Cake x 60 {id = 1849, count = 60}, -- or Fairy of Luck x 1 {id = 231, count = 1} } local r = math.random(1, table.getn(arr)) GiveItem(role, 0, arr[r].id , arr[r].count, 4) -- Launch fireworks PlayEffect(role, 361) end 7) Откройте файл "GameServer\resource\script\calculate\SkillEffect.lua" и в самом начале запишите строку: dofile(GetResPath("script\\calculate\\mods\\pkodev.contract.lua")) Клиент 1) Установите загрузчик модов PKOdev.NET mod loader; 2) Поместите файл DLL-библиотеки мода "pkodev.mod.contract.client.13x_<ID>.dll" для Вашей версии Game.exe в папку "mods" игрового клиента; 3) Добавьте в файл ItemInfo.txt предмет для контракта (см. пункт 1 инструкции по установке системы на сервер). Создание и выдача контрактов Каждый контракт должен быть создан только с использованием функции contract.create(). Использовать функции GiveItem(), MakeItem(), либо GM-команду &make и другие способы создания предметов не допускается. Синтаксис: local <Результат LUA_TRUE|LUA_FALSE>, <Дескриптор предмета>, <Ячейка предмета> = contract.create(<Дескриптор персонажа>, <ID монстра>, <Число монстров>) Пример: local ret, item, pos = contract.create(role, 103, 7) В результате будет создан контракт на убийство семи "Лесных духов" как на изображении из шапки темы. Выдавать контракты можно, например, через специального NPC или с помощью другого предмета. Скачать 1) Бинарные файлы мода (.dll); 2) Исходный код мода для Visual Studio 2019 Community (C++). Если Вы столкнулись с какой-либо проблемой, багом или у Вас возникли вопросы, то пишите в данной теме.
  29. 4 points
    [Mod] Displaying servers response time ("ping") on the server selection form Next to each server on the server selection form, their response time ("ping") is displayed. Requirements Installed mod loading system for server and client (PKOdev.NET mod loader). Modification information Name: pkodev.mod.ping Version: 1.0; Author: V3ct0r; Type: for client (Game.exe); Supported executable .exe files: GAME_13X_0, GAME_13X_1, GAME_13X_2, GAME_13X_3, GAME_13X_4 and GAME_13X_5. Installation Place the mod DLL file "pkodev.mod.ping.client.13x_<ID>.dll" for your version of Game.exe into the "mods" folder of the game client. If necessary, configure the GUI scripts of the server selection form "frmServer" (file "\scripts\lua\forms\login.clu"). Download 1) Binary release (.dll); 2) The source code of the mod for Visual Studio 2019 Community (C++). If you encounter any problem, bug or have any questions, then feel free to write in this thread.
  30. 4 points
    [Mod] Displaying the player's character level next to its name This mod allows you to display the level of the player's character next to its name (see screenshot above). Requirements Installed mod loading system for server and client (PKOdev.NET mod loader). Modification information Name: pkodev.mod.namelevel; Version: 1.0; Author: V3ct0r; Type: for client (Game.exe); Supported executable .exe files: GAME_13X_0, GAME_13X_1, GAME_13X_2, GAME_13X_3, GAME_13X_4, GAME_13X_5. Installation 1) In the "mods" directory of your client, create a "pkodev.mod.namelevel" folder; 2) Place into it the mod DLL file "pkodev.mod.namelevel.client.13x_<ID>.dll" for your version of Game.exe; 3) Place into it the mod settings file "pkodev.mod.namelevel.cfg"; 4) In the file "pkodev.mod.namelevel.cfg" write the desired displaying format for the level and character name, for example, format: Lv{:level:} {:name:} where {:level:} will be replaced by the mod for the character's level, and {:name:} - for the character's name. in the game will give the result: Lv80 V3ct0r Download 1) Binary release (.dll); 2) The source code of the mod for Visual Studio 2019 Community (C++). If you encounter any problem, bug or have any questions, then feel free to write in this thread.
  31. 4 points
    Цветные GM-сообщения (GM notice) Данный мод позволяет отправлять игрокам цветные GM-сообщения (см. скриншот выше) с помощью поля ввода в игровом клиента (ALT + P), либо с использованием функции GMNotice(). Чтобы сделать текст сообщения цветным, в самом начале сообщения необходимо прописать следующий код: {color:Цвет}Сообщение Цвет сообщения указывается в формате RGB в виде шестнадцатеричного числа (FFRRGGBB). Следующий пример выведет игрокам GM-сообщение "Hello PKOdev.NET" оранжевого цвета: {color:FFFF8000}Hello PKOdev.NET! Так же можно использовать функцию GMNotice(): GMNotice("{color:FFFF8000}Hello PKOdev.NET!") Требования Установленный Загрузчик модов для сервера и клиента (PKOdev.NET mod loader). Информация о моде Название: pkodev.mod.colorgmnotice; Версия: 1.0; Автор: V3ct0r; Тип: для клиента (Game.exe); Поддерживаемые исполняемые .exe файлы: GAME_13X_0, GAME_13X_1, GAME_13X_2, GAME_13X_3, GAME_13X_4, GAME_13X_5. Установка Поместите файл DLL-библиотеки мода "pkodev.mod.colorgmnotice.client.13x_<ID>.dll" для Вашей версии Game.exe в папку "mods" игрового клиента. Скачать 1) Бинарные файлы мода (.dll); 2) Исходный код мода для Visual Studio 2019 Community (C++). Если Вы столкнулись с какой-либо проблемой, багом или у Вас возникли вопросы, то пишите в данной теме.
  32. 4 points
    [Mod] Contract system This system is a "Monster Hunt" type quest, the purpose of which is to kill a certain number of specific monsters. The player is given a special item - "Contract", which says which monster to hunt. It also records the number of monsters and current progress. After killing the required number of monsters, the contract is considered completed, and the player receives a reward. Some specifics of the system: 1) The item type for the contract should be 99. A unique ID is also selected for the item; 2) The contract can be picked up, thrown away, transferred to another player, put in the bank or sold; 3) To receive a reward after the completion of the contract, a player should use the item of the contract by double-clicking. If the contract has not been completed, the player will see a corresponding message in the system chat; 4) The composition and amount of the reward is determined by the administrator in a special function in the script of the contract system; 5) If a player has several contracts for killing the same monster in his inventory, then when killing this monster, one or another contract is selected randomly. Installation All necessary files and scripts can be downloaded at the end of the topic. Server 1) Add an item for the contract to the ItemInfo.txt file: XXXX Contract n0184 10130005 0 0 0 0 0 00 99 0 0 0 0 0 1 1 1 1 1 1 0 -1 0 -1 0 0 -1 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0 10,10 0,0 0 0 0 0 0 0 0 0 0 ItemUse_PKOdevContract 0 0 0 0 0 0 After completion you will receive a reward! where XXXX is any unused ID. 2) Create a file with name "pkodev.contract.lua" in the directory "GameServer\resource\script\calculate\mods"; 3) Write the following code in this file: -------------------------------------------------------------- -- The contract system script -- -- Author: V3ct0r from PKOdev.NET -- Version: 1.0 (01/12/2022) -- -- How to install the system: -- 1) Put this file to '\GameServer\resource\script\calculate\mods' folder -- 2) Put the following line at the beginning of 'SkillEffect.lua' file: -- dofile(GetResPath("script\\calculate\\mods\\pkodev.contract.lua")) -- 3) Add the contract item in the ItemInfo.txt file -- XXXX Contract n0184 10130005 0 0 0 0 0 00 99 0 0 0 0 0 1 1 1 1 1 1 0 -1 0 -1 0 0 -1 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0,0 0 10,10 0,0 0 0 0 0 0 0 0 0 0 ItemUse_PKOdevContract 0 0 0 0 0 0 Upon completion, you are entitled to a reward -- 4) Specify the item ID in 'contract.conf.item_id' table below: -- item_id = XXXX -- 5) Write the code for issuing a reward for completing a contract in the 'contract.conf.reward_cb' function -- 6) To create a new contract use the function 'contract.create': -- local <result (0 or 1)>, <item_descriptor>, <slot (from 0 to bag_size - 1)> -- = contract.create(<character_descriptor>, <monster_id>, <monster_number>) -- For example: -- local ret, item, slot = contract.create(role, 103, 7) -- 7) Done! -------------------------------------------------------------- -- Print a log print("Loading pkodev.contract.lua") -- The contract system contract = contract or {} --------------------------------------- -- Settings --------------------------------------- contract.conf = { -- Contract item ID item_id = XXXX, -- User-defined function for reward reward_cb = function(role, item) -- Give 1,000 gold AddMoney (role, 0, 1000) -- Give an random item local arr = { -- Refining Gem x 1 {id = 885, count = 1}, -- or Gem of Rage x 2 {id = 863, count = 2}, -- or Cake x 60 {id = 1849, count = 60}, -- or Fairy of Luck x 1 {id = 231, count = 1} } local r = math.random(1, table.getn(arr)) GiveItem(role, 0, arr[r].id , arr[r].count, 4) -- Launch fireworks PlayEffect(role, 361) end } --------------------------------------- -- Constants --------------------------------------- contract.const = { item_type = 99, -- Contract item type target_id = ITEMATTR_VAL_STR, -- Item attribute ID with the ID of target monster target_max = ITEMATTR_VAL_AGI, -- Item attribute ID with the total amount of monsters to hunt target_cur = ITEMATTR_VAL_DEX -- Item attribute ID with the total amount of monsters already hunted } --------------------------------------- -- Hooks --------------------------------------- -- Adding an item to inventory event contract.Creat_Item__original = Creat_Item Creat_Item = function(item, item_type, item_lv, item_event) -- Check the item type if ( item_type == contract.const['item_type'] ) then -- Reset the previous attrbiutes Reset_item_add() -- Add new attributes to the item Add_Item_Attr(contract.const['target_id'], 0) Add_Item_Attr(contract.const['target_max'], 0) Add_Item_Attr(contract.const['target_cur'], 0) return item_add.cnt, item_add.attr[1][1], item_add.attr[1][2], item_add.attr[2][1], item_add.attr[2][2], item_add.attr[3][1], item_add.attr[3][2], item_add.attr[4][1], item_add.attr[4][2], item_add.attr[5][1], item_add.attr[5][2], item_add.attr[6][1], item_add.attr[6][2], item_add.attr[7][1], item_add.attr[7][2] end -- Call the original function Creat_Item(item, item_type, item_lv, item_event) return contract.Creat_Item__original(item, item_type, item_lv, item_event) end -- Player killed monster event contract.GetExp_PKM__original = GetExp_PKM GetExp_PKM = function(monster, role) -- Call the original function GetExp_PKM(dead, atk) contract.GetExp_PKM__original(monster, role) -- Get the main character's descriptor role = TurnToCha(role) -- Number of contracts in the player's bag local ret = CheckBagItem(role, contract.conf['item_id']) -- Check that player has contracts if ( ret > 0 ) then -- Monster ID local id = GetChaTypeID(monster) -- List of contracts in the bag local arr = {} local k = 0 -- Build the list of contracts for i = 0, ( GetKbCap(role) - 1 ), 1 do -- Get the item descriptor local item = GetChaItem(role, 2, i) -- Check the item ID if ( GetItemID(item) == contract.conf['item_id'] ) then -- Get the monster ID from contract local target_id = GetItemAttr(item, contract.const['target_id']) -- Check the monster ID if ( id == target_id ) then -- Get amount of monsters to hunt local target_cur = GetItemAttr(item, contract.const['target_cur']) local target_max = GetItemAttr(item, contract.const['target_max']) -- Check that the contract is not completed if ( target_cur < target_max ) then -- Add the item to the list k = k + 1 arr[k] = { item_ = item, cur_ = target_cur, max_ = target_max } end end end end -- Check that matching contracts have been found if ( k > 0 ) then -- Randomly select a contract local r = math.random(1, k) -- Increase the number of hunted monsters arr[r].cur_ = arr[r].cur_ + 1 -- Update amount of hunted monsters SetItemAttr(arr[r].item_, contract.const['target_cur'], arr[r].cur_) -- Synchronize the bag SynChaKitbag(role, 13) -- Check that the contract is not completed if ( arr[r].cur_ < arr[r].max_ ) then -- Write a message BickerNotice( role, string.format( "Contract: Remaining '%s' to hunt: %d / %d!", GetMonsterName(id), arr[r].cur_, arr[r].max_ ) ) else -- Write a message BickerNotice( role, string.format( "Contract: All '%s' are killed! The contract is completed.", GetMonsterName(id) ) ) end end end end --------------------------------------- -- Useful functions --------------------------------------- -- Create a contract contract.create = function(role, target_id, number) -- Get the main character's descriptor role = TurnToCha(role) -- Check that the bag is not locked if ( KitbagLock(role, 0) == LUA_FALSE ) then -- Error LG("pkodev.contract", "Can't create the contract item (id:", contract.conf['item_id'], ") because the bag is locked!") return LUA_FALSE, nil, 0 end -- Check that the bag has one free slot if ( GetChaFreeBagGridNum(role) == 0 ) then -- Error LG("pkodev.contract", "Can't create the contract item (id:", contract.conf['item_id'], ") because there are no free slots in the bag!") return LUA_FALSE, nil, 0 end -- Create an item local r1, r2 = MakeItem(role, contract.conf['item_id'], 1, 4) -- Check the result if ( r1 == 0 ) then -- Error LG("pkodev.contract", "Can't create the contract item (id:", contract.conf['item_id'], ")!") return LUA_FALSE, nil, 0 end -- Get the item descriptor local item = GetChaItem(role, 2, r2) -- Set contract data local a1 = SetItemAttr(item, contract.const['target_id'], target_id) local a2 = SetItemAttr(item, contract.const['target_max'], number) local a3 = SetItemAttr(item, contract.const['target_cur'], 0) -- Check that the data is set if ( (a1 == 0) or (a2 == 0) or (a3 == 0) ) then -- Error LG("pkodev.contract", "Can't set the contract data! a1 = ", a1, ", a2 = ", a2, ", a3 = ", a3) return LUA_FALSE, item, r2 end -- Synchronize the kitbag SynChaKitbag(role, 13) -- Write a message to the player SystemNotice(role, string.format("You received a monster hunt contract [%s] x %d!", GetMonsterName(target_id), number)) -- The contract is successfully created! return LUA_TRUE, item, r2 end -- Contract item use event ItemUse_PKOdevContract = function(role, item) -- Get the main character's descriptor role = TurnToCha(role) -- Get contract data local target_id = GetItemAttr(item, contract.const['target_id']) local target_max = GetItemAttr(item, contract.const['target_max']) local target_cur = GetItemAttr(item, contract.const['target_cur']) -- Check that the contract is not completed if ( target_cur < target_max ) then -- Print a message SystemNotice( role, string.format("You have to kill [%s] x %d more to complete this contract!", GetMonsterName(target_id), (target_max - target_cur) ) ) -- Cancel the item usage UseItemFailed(role) else -- Print a message SystemNotice(role, "You have successfully completed the contract, congratulations!") -- Call user-defined reward function if ( contract.conf['reward_cb'] ~= nil ) then contract.conf['reward_cb'](role, item) end end end 5) Write the contract item ID from ItemInfo.txt into the script of the system : contract.conf = { -- Contract item ID item_id = XXXX, . . . 6) Write your code for giving a reward for completing the contract in the function reward_cb(): -- User-defined function for reward reward_cb = function(role, item) -- Give 1,000 gold AddMoney (role, 0, 1000) -- Give an random item local arr = { -- Refining Gem x 1 {id = 885, count = 1}, -- or Gem of Rage x 2 {id = 863, count = 2}, -- or Cake x 60 {id = 1849, count = 60}, -- or Fairy of Luck x 1 {id = 231, count = 1} } local r = math.random(1, table.getn(arr)) GiveItem(role, 0, arr[r].id , arr[r].count, 4) -- Launch fireworks PlayEffect(role, 361) end 7) Open the file "GameServer\resource\script\calculate\SkillEffect.lua" and at the beginning of the file write the line: dofile(GetResPath("script\\calculate\\mods\\pkodev.contract.lua")) Client 1) Install the mod loading system PKOdev.NET mod loader; 2) Place the mod DLL file "pkodev.mod.contract.client.13x_<ID>.dll" for your version of Game.exe into the "mods" folder of the game client; 3) Add the item for the contract to the ItemInfo.txt file (see point 1 of the instructions for installing the system on the server). Creation and issuance of contracts Each contract must only be created using the contract.create() function. Using the GiveItem(), MakeItem() functions, or the &make GM command and other ways to create items is not allowed. The syntax: local <Result LUA_TRUE|LUA_FALSE>, <Item descriptor>, <Item slot> = contract.create(<Character descriptor>, <Monster ID>, <Number of monsters>) Example: local ret, item, pos = contract.create(role, 103, 7) As a result, a contract will be created for killing seven "Forest Spirits" as in the image from the topic header. You can give contracts to players, for example, through a special NPC or with the another item. Download 1) Binary release (.dll); 2) The source code of the mod for Visual Studio 2019 Community (C++). If you encounter any problem, bug or have any questions, then feel free to write in this thread.
  33. 4 points
    Привет! Всё супер, спасибо что спросил. Давно мы не описывали свою работу в этой теме, так как в большинстве всё описание ведём на своём закрытом форуме для коммуникации внутри команды и некоторую часть выкладываем нашим преданным игрокам (матросам). Объём работы велик, много что переписали и нужно переписать/дописать, работаем целой командой и день и ночь, практически каждый день Команда занимающая клиентской частью сейчас очень активно занимается адаптацией игры под всевозможные платформы, на данный момент имеем поддержку win x32, win x64, linux, android, macOS и сейчас в работе над IOS(отчеты техников в спойлере), должны к концу месяца закончить. Очень трудно адаптировать китайщину под кроссплатформу, там очень много мелочей которые тратят кучу времени, к примеру для адаптация под компилятор MinGW и поддержку x64 пришлось запилить свой клей между игрой и LUA, (https://github.com/Alex2772/cpp_lua_glue) так как там есть asm вставки, которые как ты знаешь на x64 совсем другие). Ещё интереснее стало когда пришлось избавиться от WinAPI, MinGW нам вообще жопу порвал, он ругается на все мелочи, если знаком с этим компилятором знаешь о чем я. В итоге первый запуск на Linux завели спустя 2 месяца ежедневной работы, так как архитектура исходников не позволяет расширяться и нанимать новый разрабов не опасаясь сливов, пришлось разбить проект на много репозиториев, переделать модули в библиотеки (libdbc.dll/so, util.dll/so, odbc.dll/so и т.д), чтобы можно было позволить работать над отдельными модулями не имея доступы к основным исходникам. К этому всему прикрутили автоматическую компиляцию всех компонентов на билд машинах (CI CD), для билда всё перевели на CMake под это всё барахло закупили оборудование (linux тачка с 32 CPU и 256 RAM) со своей простроенной NAT архитектурой и всё это под оберткой Conan (python). В общем очень всё тяжело, сложно, но очень интересно и планы на продукт грандиозные. Очень сильно упоролись в поддержку множества устройств, пришлось большой объём работы провести над переписью шейдеров игры под разные видеокарты intel, nvidia, амуде)). Сюда же прикрепили крутую оптимизацию GPU и CPU, нашли кучу проблем с сетевой частью, которая очень сильно тормозит и бросается с потока на поток (class Sema), игровым движком (не графическим), кучу копирования классов пришлось на ссылки перекинуть (очень крутой буст кстати дало), свои кастомные решения ThreadPool'a, обработчика событий, backtrace и крч много-много-много всего, которое требуется любому современному продукту. К этому прикрутили популярные методы улучшения графики (HBAO, динамические тени, динамическое освещение, новая технология источников света в 1 calldraw, skybox с собственной технологией динамического размыливания). Ко всему прочему большой акцент сделали на GUI, так как адаптация под мобилку потребует полностью перерисовывать интерфейс, решили полностью перейти на самописный фреймворк(https://github.com/aui-framework/aui), который даст возможность крутить интерфейс как захотим под любым углом, сейчас активно переводим все существующие элементы под него, так к примеру в августе разработали новый чат с динамическим расширением, в ноябре между адаптацией под платформы завезли новые bb коды на основе xml парсинга для сервера (цвета, выравнивания (даже по ширине текста)) Что касается серверной части, мы в основном занимались доработками lua. Пришлось пробежаться по всем файлам и провести микро оптимизацию всех функций, наследие от китайцев и старых разработчиков оставило кучу сюрпризов. Перешли на lua 5.4 со всеми вытекающими последствиями, после чего завезли несколько профилировщиков, обнаружили уязвимые места и фиксим их. Так же закончили дробление lua на файлы, теперь сборка логически разбита на 200+ файлов по механикам или смыслам, а все функции покрыты комментариями для новых разработчиков, для расширения штата создали свою базу знаний для обучения скриптеров/геймдизов/нарративщиков. В ней мы пишем документацию по всем системам, которые у нас реализованы или находящихся в планах на реализацию. Развернули большую компанию по введению 2 и более языков на уровне скриптов. Переработали множество квестов и наград за них для прозрачного развития игрока относительно игрового процесса. Теперь прокачка игрока построена не только на тотальном убийстве игроков, а на прохождении заданий в городах/деревнях или исторической цепочке. Проработали и продолжаем прорабатывать начало игры для игрока любого уровня - мы постепенно знакомим игрока со всеми механиками игры начиная с локации для новичков. Процесс взятия профессии мы так же перенесли на новую локацию. Игрок находится под нашим контролем первые 30-40 минут своей игры. Мы проделали большую работу по написанию новой-старой локации Остров Зимы(Северные королевства), в этой локации мы продолжили работать над ЛОРом игры и добавили множество заданий, новых существ, новые поселения и активности для игрока высокого уровня. По смете выложили уже 4.255 млн на всю разработку, планируем хорошую рекламную компанию и ожидаем очень большую нагрузку из-за этого сейчас приходится продумывать и прорабатывать каждый модуль по отдельности, обвязывать его тестами. Из первой необходимости осталось доделать IOS, автоматизировать процесс деплоя, доделать патчер и лаунчер, доделать поддержку английского и передать на перевод под другие языки. В следующем году планируем открываться, в первом квартале надеемся провести локальные тесты. Тут примерно 30% проделанной работы, кучу остальной мелочи описывать смысла не вижу. Как-то так у нас дела))
  34. 4 points
  35. 4 points
    Система награды игроков по расписанию С помощью данной системы можно выдавать всем игрокам на сервере в определенное время награду, указанную в расписании: все игроки, которые в данное время будут онлайн, получат предмет. Как установить 1) Создайте файл с названием "pkodev.gift.lua" в директории "GameServer\resource\script\calculate\mods"; 2) Поместите в файл следующий код: -------------------------------------------------------------- -- Gift system script -- -- Author: V3ct0r from PKODev.NET -- Version: 1.0 (11/08/2021) -- -- How to install the system: -- 1) Put this file to '\GameServer\resource\script\calculate\mods' folder -- 2) Put the following line at the beginning of 'mlist.lua' file: -- dofile(GetResPath("script\\calculate\\mods\\pkodev.gift.lua")) -- 3) Done! -- -- Interface: -- 1) Add a gift to queue: -- local gift_id = giftmod:addGift(item_id, number, hour, minute, second, month, day, year) -- 2) Remove a gift from queue -- local success = giftmod:removeGift(gift_id) -- Where 'success' can be 'true' or 'false' -- 3) Get gift number in queue -- local number = giftmod:getGiftNumber() -- 4) Print a list of queued gifts in GameServer window: -- giftmod:printGifts() -- -- These commands also can be used with &lua_all GM-command, for example: -- &lua_all giftmod:addGift(item_id, number, hour, minute, second, month, day, year) -- Note: After GameServer.exe restart gifts. which were added using GM-command, will be removed -------------------------------------------------------------- -- Update guard if (PKODEV_GIFT_GUARD ~= nil) then -- Exit the script return end -- Define update guard PKODEV_GIFT_GUARD = true -- Print a log print("Loading pkodev.gift.lua") -- Class Gift Gift = {} -- Make a Gift function Gift:new(id, item_id, count, gift_time) -- Private fields local private = { id = id or -1, item_id = item_id or -1, count = count or 0, gift_time = gift_time or 0, is_given = false } -- Public fields local public = { } -- Get an gift ID function public:getId() return private.id end -- Get an item id function public:getItemId() return private.item_id end -- Get an item count function public:getItemCount() return private.count end -- Get a time at which to give the gift function public:getTime() return private.gift_time end setmetatable(public, self) self.__index = self; return public end -- Class GiftSystem GiftSystem = {} -- Make a Gift system function GiftSystem:new() -- Private fields local private = { -- List of gifts to give gifts = { }, -- List of active players players = { }, -- Timer function timer_func = nil, -- List of hooks hooks = { } } -- Public fields local public = { } -- Player entered a map event function private:on_player_entered_map(role, mapdesc, map) -- Check that map exists in the list if ( private.hooks[map] ~= nil ) then -- Check that enter function is hooked if ( private.hooks[map].enter ~= nil ) then -- Call original function private.hooks[map].enter(role, mapdesc) end end -- Add player to the list private.players[ GetRoleID(role) ] = role end -- Player leaved a map event function private:on_player_leaved_map(role, map) -- Check that map exists in the list if ( private.hooks[map] ~= nil ) then -- Check that leave function is hooked if ( private.hooks[map].leave ~= nil ) then -- Call original function private.hooks[map].leave(role) end end -- Remove player from the list private.players[ GetRoleID(role) ] = nil end -- Timer event function private:on_timer_event(map) -- Check that timer function is hooked if ( private.timer_func ~= nil ) then -- Call original function private.timer_func(map) end -- Get current system time local t = os.time() -- Update gifts for i = table.getn(private.gifts), 1, -1 do -- Get a gift local gift = private.gifts[i] -- Check that it's time to give out the gift if ( t >= gift:getTime() ) then -- Give the gift to players for cha_id, role in pairs(private.players) do GiveItem(role, 0, gift:getItemId(), gift:getItemCount(), 4) end -- Remove the gift from the list table.remove(private.gifts, i) end end end -- Set hooks function private:setHook() -- Search for 'after_enter_', 'before_leave_' and timer functions for key, value in pairs(_G) do -- Get a global item name in lower case local name = string.lower(key) -- Player entered a map if ( string.find(name, "after_enter_") == 1 ) then -- Get map name local map = string.sub(name, string.len("after_enter_") + 1) -- Add map to the list private.hooks[map] = private.hooks[map] or {} -- Associate original enter function address with map name private.hooks[map].enter = value -- Set the hook _G[key] = function(role, mapdesc) private:on_player_entered_map(role, mapdesc, map) end end -- Player leaved a map if ( string.find(name, "before_leave_") == 1 ) then -- Get map name local map = string.sub(name, string.len("before_leave_") + 1) -- Add map to the list private.hooks[map] = private.hooks[map] or {} -- Associate original leave function address with map name private.hooks[map].leave = value -- Set the hook _G[key] = function(role) private:on_player_leaved_map(role, map) end end -- Timer if ( private.timer_func == nil ) then -- Search for timer function if ( string.find(name, "map_copy_run_") == 1 ) then -- Number of underscore characters local n = 0 -- Count the number of underscore characters string.gsub(name, ".", function(c) if ( c == '_' ) then n = n + 1 end end) -- Number of underscore characters should be equal to 3 if (n == 3) then -- Set timer function private.timer_func = value -- Set the hook _G[key] = function(map) private:on_timer_event(map) end end end end end -- Check that timer hook is enabled if ( private.timer_func == nil ) then print("pkodev.gift: Warning, suitable timer function is not found!") end end -- Add a gift to the list function public:addGift(item_id, count, h, m, s, mon, day, year) -- Check item ID if ( string.lower(GetItemName(item_id)) == "unknown" ) then -- Do not add a gift return -1 end -- Check item count if (count <= 0) then -- Do not add a gift return -1 end -- Get item timestamp local gift_timestamp = os.time{ month = mon, day = day, year = year, hour = h, min = m, sec = s } -- Check that item time is not expired if ( gift_timestamp <= os.time() ) then -- Do not add a gift return -1 end -- Get an ID for new gift local gift_id = public:getGiftNumber() -- Create a gift local gift = Gift:new(gift_id, item_id, count, gift_timestamp) -- Add a gift to the list table.insert(private.gifts, gift) -- Return gift ID return gift_id end -- Remove a gift by ID function public:removeGift(gift_id) -- Find a gift in the list for index, gift in pairs(private.gifts) do -- Check gift ID if ( gift_id == gift:getId() ) then -- Remove the gift from the list table.remove(private.gifts, index) -- Gift removed return true end end -- Gift not found return false end -- Get gift number function public:getGiftNumber() return table.getn(private.gifts) end -- Print a list of gifts function public:printGifts() -- Get gift number local n = public:getGiftNumber() -- Check that there are gifts in the list if (n > 0) then -- Print all gifts for index, gift in pairs(private.gifts) do -- Get time data local temp = os.date("*t", gift:getTime()) -- Print a gift print( string.format( "pkodev.gift: %d) [Gift ID: %d] - %s x %d at %02d:%02d:%02d %02d/%02d/%02d", index, gift:getId(), GetItemName(gift:getItemId()), gift:getItemCount(), temp.hour, temp.min, temp.sec, temp.month, temp.day, temp.year ) ) end else -- No gifts print("There are no active gifts!") end end -- Enable the necessary hooks for the gift system to work private:setHook() setmetatable(public, self) self.__index = self; return public end -- Create an instance of the gift system giftmod = GiftSystem:new() -- Add gifts to the queue giftmod:addGift(863, 1, 16, 6, 30, 11, 9, 2022) -- 'Gem of Rage' x 1 at 16:06:30 11/09/2022 giftmod:addGift(684, 1, 16, 7, 25, 11, 15, 2022) -- 'New Sheepskin Scroll' x 1 at 16:07:25 15/09/2022 giftmod:addGift(1849, 99, 12, 7, 0, 11, 18, 2022) -- 'Cake' x 99 at 12:07:00 18/09/2022 -- Print queued gifts giftmod:printGifts() 3) Откройте файл "GameServer\resource\script\monster\mlist.lua" и в самом начале запишите строку: dofile(GetResPath("script\\calculate\\mods\\pkodev.gift.lua")) 4) Запустите GameServer.exe. В окне консоли Вы должны увидеть следующий вывод: pkodev.gift: 1) [Gift ID: 0] - Gem of Rage x 1 at 16:06:30 11/09/2022 pkodev.gift: 2) [Gift ID: 1] - New Sheepskin Scroll x 1 at 16:07:25 11/15/2022 pkodev.gift: 3) [Gift ID: 2] - Cake x 99 at 12:07:00 11/18/2022 5) Настройте систему по Вашему усмотрению (см. раздел "Как использовать" далее); 6) Процесс установки системы завершен. Как использовать 1) Вы можете определить расписание выдачи наград в конце файла "pkodev.gift.lua" используя команду giftmod:addGift(): local gift_id = giftmod:addGift(ID_предмета, количество, час, минута, секунда, месяц, день, год) Также Вы можете добавить награду в очередь используя GM-команду*: &lua_all giftmod:addGift(ID_предмета, количество, час, минута, секунда, месяц, день, год) *Примечание: После перезапуска GameServer.exe, все награды, которые были добавлены с помощью GM-команды, удалятся. 2) Вы можете удалить награду из расписания с помощью команды "giftmod:removeGift()": local success = giftmod:removeGift(gift_id) -- Где 'success' может быть 'true' или 'false' Где переменная gift_id - это ID награды, которая ранее была добавлена в очередь командой giftmod:addGift(). 3) Вы можете получить число наград в очереди с помощью команды giftmod:getGiftNumber(): local number = giftmod:getGiftNumber() 4) Наконец, Вы можете отобразить очередь наград в окне консоли GameServer.exe: giftmod:printGifts() Это все! Скачать скрипт системы (3 Кб)
  36. 4 points
    Карта мира (Аскарон, Магический океан и Великий синий океан на одной карте) Объединенная игровая карта мира с основными континентами и островами на одной карте. Установка карты Клиент: 1) Поместить файлы world.map, world.obj, world.rbo в папке "Client\map" из приложенного архива в соответствующую папку игрового клиента; 2) Поместить файл миникарты "Client\texture\minimap\world\world.pk" из приложенного архива в соответствующую папку игрового клиента; 3) Добавить в файл mapinfo.txt ("Клиент\scripts\table") строку: XX world World 1 2202,2782 255,255,255 Где XX – последний незанятый ID. 4) Скомпилировать mapinfo.bin. Сервер: 1) Поместить папку "GameServer\resource\world" из приложенного архива в папку "GameServer\resource" Ваших серверных файлов; 2) Добавить следующую строку в файл "GameServer\resource\script\MisScript\ScriptDefine.lua" AddMap("world", "World") 3) Добавить карту в GameServer.cfg для запуска: map = world Некоторые полезные координаты Основные города: Аргент 2145, 3410 (&move 2145, 3410, world) Шайтан 3085, 3250 (&move 3085, 3250, world) Ледынь 1015, 500 (&move 1015, 500, world) Громоград 650, 2080 (&move 650, 2080, world) Острова: Остров Лета 3455, 1755 (&move 3455, 1755, world) Остров Весны 3506, 797 (&move 3506, 797, world) Остров Осени 2915, 1460 (&move 2915, 1460, world) Остров Удачи 1600, 1320 (&move 1600, 1320, world) Остров Зефира 1405, 2405 (&move 1405, 2405, world) Остров Купидона 2055, 2490 (&move 2055, 2490, world) Остров Канареек 3900, 3450 (&move 3900, 3450, world) Остров Стужи 3050, 2280 (&move 3050, 2280, world) Ледниковый Остров 2240, 1940 (&move 2240, 1940, world) Остров Руин 2720, 3670 (&move 2720, 3670, world) Остров Арены 1225, 2765 (&move 1225, 2765, world) Особенности практического применения 1) Карта не продумывалась в плане дизайна и проектировалась "на глаз" чтобы уместить основные континенты и острова на площади 4096 x 4096. Так, например, не учитывались географические и климатические особенности: "летние" острова находятся рядом с заснеженным континентом, а "зимние" – рядом с пустынным. Целью создания данной карты являлась демонстрация возможности подобных разработок; 2) Карта совершенно пустая. Это означает что на неё нужно добавить: точки возрождения персонажей игроков, NPC, точки возрождения монстров, ресурсы, порталы, причалы, регионы погоды и тому подобное; 3) Поскольку на одной карте будет множество объектов, включая персонажей игроков, неизвестно как будет работать GameServer.exe в плане производительности и хватит ли ему памяти. Вероятно, три основных континента были разделены разработчиками игры на разные карты именно из соображений производительности и распределения ресурсов. Тем не менее, можно попробовать настраивать следующие параметры из GameServer.cfg: [Entity] max_ply = 3000 max_cha = 15000 max_item = 30000 max_tnpc = 300 4) Серверные файлы world.atr и world.blk были получены с помощью программы YAMMI. При конвертации .map файла в .atr и .blk было получено предупреждение, что данная функция экспериментальная и, при использовании этих файлов на стороне сервера, могут возникнуть непредвиденные проблемы. Если такие проблемы действительно возникнут, и при должной необходимости, рассматривается разработка собственного конвертера .map -> .atr и .map -> .blk; 5) Генерация миникарты занимает около 4 часов, а итоговый файл .pk весит 849 Мегабайт (размер целого клиента!). Это связано с тем, что каждый фрагмент миникарты имеет разрешение 256 x 256 и сохраняется в формате .bmp, а также из-за большего числа фрагментов, чем на любой другой карте ("пустые" фрагменты с морем не сохраняются в .pk файл). При этом, фрагменты, например, из миникарты garner имеют размеры всего 64 x 64. Поэтому в теории можно существенно сократить размер файла world.pk, если пропатчить Game.exe и заставить его генерировать фрагменты размером 64 x 64. Также стоит отметить, что PK Viewer не работает с такими большими .pk файлами; 6) Файлы карты имеют большие размеры: world.map (86,4 МБ), world.obj (22,3 МБ), world.atr (48,0 МБ), world.blk (8,00 МБ). Получение карты Данная карта была получена с помощью Инструмента для обрезания и склеивания карт со следующей программой: #include <iostream> #include "Map.h" // Entry point int main(int argc, char* argv[]) { // Path to directory with maps const std::string base{ "C:\\pkodev\\map" }; // Print a welcome message std::cout << "Map cut & glue tool by V3ct0r from PKODev.NET" << std::endl; std::cout << std::endl; try { // Write a message std::cout << "Building world map, it can take a time . . ." << std::endl; // Main maps pkodev::MapWrapper garner, magicsea, darkblue; // Load main maps garner.load(base + "\\garner"); magicsea.load(base + "\\magicsea"); darkblue.load(base + "\\darkblue"); // Main continents pkodev::MapWrapper argent, shaitan, icicle; // Cut main continents from main maps argent = garner.cut( { 168, 980 }, { 2364, 3272 } ); shaitan = magicsea.cut( { 522, 2816 }, { 1880, 3900 } ); icicle = darkblue.cut( { 386, 178 }, { 3248, 1076 } ); // Some islands pkodev::MapWrapper autsumspr, fortune, cupid, arena, bridge, chill, glacier, zephyr; // Cut islands from main maps autsumspr = darkblue.cut( { 2088, 2371 }, { 4000, 3660 } ); // Autumn island + Summer island + Spring island fortune = darkblue.cut( { 1414, 1681 }, { 1771, 2024 } ); // Isle of Fortune cupid = magicsea.cut( { 2368, 2330 }, { 2675, 2608 } ); // Cupid isle arena = darkblue.cut( { 372, 3376 }, { 518, 3498 } ); // Arena isle bridge = darkblue.cut( { 762, 3344 }, { 964, 3524 } ); // Unknown isle nearly arena isle chill = magicsea.cut( { 2274, 370 }, { 2554, 782 } ); // Isle of Chill glacier = garner.cut( { 2134, 1069 }, { 2325, 1222 } ); // Glacier isle zephyr = garner.cut ({ 3200, 3045 }, { 3610, 3390 } ); // Zephyr isle // Use Ascaron map as base map garner.del( { 0, 112 }, { 4095, 4000 } ); // Free main maps magicsea.clear(); darkblue.clear(); // Add main continents + Autumn/Summer/Spring islands to the base map garner.glue( { 80, 1600 }, argent); argent.clear(); garner.glue( { 2700, 2500 }, shaitan); shaitan.clear(); garner.glue( { 2200, 600 }, autsumspr); autsumspr.clear(); garner.glue( { 80, 160 }, icicle); icicle.clear(); // Remove some garbage from the map garner.del( { 1119,1872 }, { 2372,2987 }); garner.del( { 1265, 1660 }, { 1770, 1980 }); garner.del( { 2621, 1765 }, { 2945, 1935 }); garner.del( { 2016, 1810 }, { 2115, 1875 }); garner.del( { 3912, 2623 }, { 4095, 3050 }); garner.del( { 1082, 1980 }, { 1124, 2024 }); garner.del( { 1125, 1819 }, { 1246, 1864 }); garner.del( { 2239, 3000 }, { 2289, 3036 }); garner.del( { 2948, 600 }, { 2970, 648 }); garner.del( { 245, 588 }, { 282, 620 }); garner.del( { 324, 680 }, { 390, 906 }); garner.del( { 2768, 3442 }, { 2882, 3480 }); garner.del( { 2935, 3428 }, { 2965, 3460 }); garner.del( { 3096, 3404 }, { 3226, 3447 }); garner.del( { 2240, 3572 }, { 2279, 3605 }); garner.del( { 3383, 3327 }, { 3603, 3459 }); garner.del( { 3743, 3204 }, { 3864, 3257 }); garner.del( { 3880, 3076 }, { 3915, 3105 }); garner.del( { 4010, 3168 }, { 4036, 3205 }); garner.del( { 3359, 908 }, { 3607, 1090 }); garner.del( { 1032, 1944 }, { 1055, 1968 }); garner.del( { 3254, 1192 }, { 3367, 1299 }); garner.del( { 3093, 1471 }, { 3153, 1610 }); garner.del( { 3075, 1679 }, { 3117, 1714 }); garner.del( { 3783, 671 }, { 3881, 793 }); garner.del( { 3695, 805 }, { 3727, 836 }); garner.del( { 2963, 615 }, { 2977, 631 }); garner.del( { 2040, 1685 }, { 2224, 1850 }); // Add islands to the map garner.glue( { 1388, 1036 }, fortune); fortune.clear(); garner.glue( { 1900, 2420 }, cupid); cupid.clear(); garner.glue( { 1125, 2740 }, arena); arena.clear(); garner.glue( { 2944, 1932 }, chill); chill.clear(); garner.glue( { 2656, 3632 }, bridge); bridge.clear(); garner.glue( { 2096, 1885 }, glacier); glacier.clear(); garner.glue( { 1348, 2160 }, zephyr); zephyr.clear(); // Save new map to file garner.save(base + "\\garner"); // Write a message std::cout << "Done!" << std::endl; } catch (const pkodev::map_file_exception& e) { std::cout << ".map file error: " << e.what() << std::endl; return 1; } catch (const pkodev::obj_file_exception& e) { std::cout << ".obj file error: " << e.what() << std::endl; return 2; } catch (...) { std::cout << "Unknown error!" << std::endl; return 3; } return 0; } Скачать карту (596,3 МБ)
  37. 4 points
    #define SHOWRSIZE 40 g_pGameApp->GetCurScene()->GetTerrain()->SetShowSize(SHOWRSIZE + 5, SHOWRSIZE + 5);
  38. 4 points
    Hello friends! I promised to release an updated version of StallServer, but I'm having some difficulties with multithreading, which I'm currently dealing with. I also recently suffered an illness, so there was no opportunity to work on the project. The project is not abandoned and almost finished. I apologize for the long wait
  39. 4 points
    Hello, I built this for for a server but I think it would be useful for the rest of the community too. This feature basically allows players to hide certain dropped items on the ground. They can use this to specifically filter out garbage/low tier drops, and only see rare drops and pick them up. While 'hidden', the items will also not get picked up by Ctrl + A, so they can freely pick up all items that they are interested in without filling their inventory with garbage. I made this feature available through the drop list of a monster on the CO client. You can choose to expose it however you wish. I'll add the CO-client specific changes at the end so you can use it for that if you wish. I've attached a gif of what the feature looks like. Code - GlobalVar.cpp At the top, add - #include "LootFilter.h" a bit further down - CGameApp* g_pGameApp = NULL; LootFilter* g_lootFilter = NULL; Create the following two files in the src directory LootFilter.h #include "stdafx.h" #include <map> class LootFilter { public: LootFilter(); ~LootFilter(); map<int, bool> GetFilteredItems() { return lootFilter; } void AddFilteredItem(unsigned long itemId); void RemoveFilteredItem(unsigned long itemId); bool HasFilteredItem(unsigned long itemId); void PrintAllItems(); private: map<int, bool> lootFilter; }; extern LootFilter* g_lootFilter; LootFilter.cpp #include "stdafx.h" #include <map> #include "LootFilter.h" #include "GameApp.h" #include <string> #include "log.h" LootFilter::LootFilter() { if (!CreateDirectory("user", NULL)) { DWORD dw = GetLastError(); if ( dw != 183 ) { return; } } ifstream lootFilterFile; lootFilterFile.open("user\\lootfilter.txt"); string itemIdReader; if (lootFilterFile.is_open()) { while (getline(lootFilterFile, itemIdReader)) { if ( itemIdReader.length() == 0) { continue; } int itemId = atoi(itemIdReader.c_str()); lootFilter.insert(pair<int, bool>(itemId, TRUE)); } } } void LootFilter::AddFilteredItem(unsigned long itemId) { lootFilter.insert(pair<int, bool>(itemId, TRUE)); ofstream lootFilterFile; char itemIdBuffer[10]; itoa(itemId, itemIdBuffer, 10); lootFilterFile.open("user\\lootfilter.txt", ios_base::app); lootFilterFile << string(itemIdBuffer) << std::endl; lootFilterFile.close(); } void LootFilter::RemoveFilteredItem(unsigned long itemId) { lootFilter.erase(itemId); string line; ifstream in; in.open("user\\lootfilter.txt"); ofstream temp; temp.open("user\\lootfilter_new.txt"); while (getline(in, line)) { char itemIdBuffer[10]; itoa(itemId, itemIdBuffer, 10); if (line.compare(string(itemIdBuffer)) != 0) { temp << line << std::endl; } } in.close(); temp.close(); remove("user\\lootfilter.txt"); rename("user\\lootfilter_new.txt", "user\\lootfilter.txt"); } bool LootFilter::HasFilteredItem(unsigned long itemId) { if ( lootFilter.find(itemId) == lootFilter.end() ) { return false; } return true; } void LootFilter::PrintAllItems() { map<int,bool>::iterator it = lootFilter.begin(); for(it = lootFilter.begin(); it != lootFilter.end(); it++) { g_pGameApp->SysInfo("Filtered item %d %d", it->first, it->second); } } In Main.cpp At the top - #include "LootFilter.h" A bit further down, look for g_pGameApp - g_pGameApp = new CGameApp(); g_lootFilter = new LootFilter(); Scene.h Add this function declaration below the other ones for CSceneItem (after line 217 in CO) CSceneItem* FilterItemsByItemID(unsigned long id, bool shouldHide); Scene.cpp Add this function somewhere in the file - CSceneItem* CGameScene::FilterItemsByItemID(unsigned long id, bool shouldHide) { CSceneItem* pItem; for(int i = 0; i < _nSceneItemCnt; i++) { pItem = &_pSceneItemArray[i]; if (pItem->IsValid()) { CItemRecord* itemData = pItem->GetItemInfo(); if ( itemData ) { if (itemData->lID == id ) { pItem->SetHide(shouldHide); } } } } if ( !shouldHide ) { g_lootFilter->RemoveFilteredItem(id); } else { g_lootFilter->AddFilteredItem(id); } return NULL; } SceneItem.cpp Replace the CSceneItem::Render function with this - void CSceneItem::Render() { if( GetScene()->GetTerrain() ) { if(!GetScene()->GetTerrain()->IsPointVisible((float)_nCurX / 100.0f, (float)_nCurY / 100.0f)) return; } if ( _pItemInfo && g_lootFilter->HasFilteredItem(_pItemInfo->lID) ) { SetHide(TRUE); setIsShowName(false); return; } CSceneNode::Render(); // g_Render.EnableMipmap(FALSE); MPSceneItem::Render(); } In the CSceneItem::setIsShowName function, add this line at the top _IsShowName = v; Make sure to include the LootFilter.h and LootFilter.cpp files in your kop.vcxproj or kop.vcproj files I had .vcxproj, so - kop.vcxproj Look for <ClInclude Include="..\src\GameWG.h" /> and add <ClInclude Include="..\src\LootFilter.h" /> after it. kop.vcxproj.filters Look for <ClCompile Include="..\src\SoundCommon.cpp" /> and add <ClCompile Include="..\src\LootFilter.cpp" /> after it. Look for <ClInclude Include="..\src\SoundManager.h" /> and add <ClInclude Include="..\src\LootFilter.h" /> after it. This should let you compile the given code. For people who are NOT using CO files, if you want to trigger the filter for a particular item, you need to have the item ID, and then do something like this - CGameApp::GetCurScene()->FilterItemsByItemID(itemId, true); If you are using the CO client and have the monster drop UI available, I'll post how to make changes to that UI in a follow-up post below I offer NO support for any issues you may have past basic compilation. It's up to you to figure out how to integrate this if you want it.
  40. 4 points
    Hello, @K1D0! I totally agree with your opinion regarding his reputation. I am sure that In-PKO, White, Lua and other fake accounts to make visibility of activity and mislead people are the same person. This fact is confirmed by his message (which he hastened to remove) in your topic on in-pko forum: It is not a news that he sells other people's work for money and says it his development. Compare these files from 'his' ProxyServer source code with my ones from StallServer. There are even my comments in Russian. Settings.h: Settings.cpp You can notice that he made some ridiculous edits which indicate his little knowledge of the C++ language. I am not an expert too, but the need to pass 'large' objects by reference and not by value is the basics.
  41. 3 points
    Друзья всем добрый день давно уже занимаюсь фотошопом и тут решил создать другой инвентарь да и вообще новый стиль для пиратии. Но вот у меня появился такой вопрос подскажите что не хватает или что изменить в инвентаре!!!!!!!! Может кому то нужен будет в дальнейшем данный стиль пишите в вк https://vk.com/paulovserega52 и время от времени буду выкладывать новые виды!!!!!
  42. 3 points
    [Release] Clean Tales of Pirates 1.36 Client and Patch Hey all. This is the official Tales of Pirates installer for a clean 1.36 client, as well as a clean 1.36 patch; note that the only client and patch currently available are mismatched. I have also added the archives of the installed files for each in case you don't want to run the installer. Installers Archives
  43. 3 points
    Looks like 1k+ players are bots: All accounts are always online even if a player close the game client.
  44. 3 points
    [Скрипт] Система промокодов Данный скрипт реализует простую систему промокодов. Игроки могут использовать промокоды для получения предметов. Промокоды вводятся в канал местного чата через косую черту, например: /agjtjSfsaAS34 Промокод можно использовать только один раз. Для хранения промокодов используется текстовый файл. Требования Для работы скрипта требуется GameServer.exe с поддержкой функции HandleChat() - обработчик сообщений в местный чат. Установка скрипта 1) Создайте файл с названием "pkodev.promo.lua" в следующей директории GameServer: GameServer\resource\script\calculate\mods 2) Запишите в файл следующий код: -- Print a log print("Loading pkodev.promo.lua") -- Check that HandleChat function exists if (HandleChat == nil) then -- Write a log print("pkodev.promo.lua: Warning, the HandleChat() function is not exist!") -- Do not load the script return end -- Promocodes system promo = promo or { } -- Name of the file with promocodes promo.file = "promocodes.dat" -- List with promocodes promo.list = {} -- Save data to file promo.save = function(path) -- Open the file local file, msg = io.open(path, "w") -- Check that file is open if (file == nil) then -- Write a log LG("pkodev.mod.promo", string.format("Can't save the list with promocodes to the file '%s': '%s'!", path, msg)) return false end -- Write data for key, value in promo.list do -- Write a line local ret = file:write(string.format("{%s, %d, %d}\n", value.code, value.id, value.count)) -- Check that line is written if (ret == false) then -- Write a log LG("pkodev.mod.promo", string.format("Can't write the data to the file '%s'!", path)) return false end end -- Flush the data file:flush() -- Close the file file:close() -- Write a log LG("pkodev.mod.promo", string.format("The list with promocodes has been successfully saved to the file '%s'!", path)) return true end -- Load data from file promo.load = function(path) -- Remove old promocodes for k in pairs (promo.list) do promo.list[k] = nil end -- Open the file local file, msg = io.open(path, "r") -- Check that file is open if (file == nil) then -- Write a log LG("pkodev.mod.promo", string.format("Can't load the list with promocodes from the file '%s': '%s'!", path, msg)) return false end -- Read file line by line for line in file:lines() do -- Extract data from the line local ret, _, code_, id_, count_ = string.find(line, "^{([A-Za-z0-9]+)%s*,%s*([0-9]+)%s*,%s*([0-9]+)}$") -- Check that string matches the pattern if (ret ~= nil) then -- Add data to the list table.insert( promo.list, { code = code_, id = id_, count = count_, } ) end end -- Close the file file:close() -- Write a log LG("pkodev.mod.promo", string.format("%d promocodes have been succsessfully loaded from file '%s'!", table.getn(promo.list), path)) return true end -- Handle chat function hook promo.hadle_chat__original = HandleChat HandleChat = function(role, msg) -- Check that message has the '/' symbol if ( string.sub(msg, 1, 1) == "/" ) then -- Get promocode local ret, _, code_ = string.find(msg, "^/([A-Za-z0-9]+)%s*$") -- Check that promocode is found if (ret ~= nil) then -- Search the promocode in the list for key, value in pairs(promo.list) do -- Compare promocodes if (value.code == code_) then -- Write a message BickerNotice(role, string.format("You entered the promocode '%s': %s x %d!", value.code, GetItemName(value.id), value.count) ) -- Give an item GiveItem(role, 0, value.id, value.count, 0) -- Write a log LG("pkodev.mod.promo", string.format("Player '%s' entered a promocode '%s' and received '%s' x %d!", GetChaDefaultName(role), value.code, GetItemName(value.id), value.count) ) -- Remove the promocode from the list promo.list[key] = nil -- Save the list to the file promo.save(promo.file) -- Synchronize the promocodes list local packet = GetPacket() WriteCmd(packet, 4015) WriteDword(packet, GetRoleID(role)) WriteString(packet, string.format("promo.list[%d]=nil", key)) SendPacket(role, packet) -- Do not call the original function HandleChat() return 0 end end end end -- Call the original function HandleChat() return promo.hadle_chat__original(role, msg) end promo.load(promo.file) 3) Подключите файл "pkodev.promo.lua" в начале файла "SkillEffect.lua" (\GameServer\resource\script\calculate) после включения файла "functions.lua": dofile(GetResPath("script\\calculate\\mods\\pkodev.promo.lua")) 4) В корневой директории GameServer.exe создайте файл "promocodes.dat" и запишите в него список промокодов в следующем формате: {<Промокод>, <ID предмета>, <Количество предметов>} Например: {agjtjSfsaAS34, 1849, 45} {kgjKKKsnggklsaa, 885, 1} {0004121aAf, 1848, 10} Использование скрипта 1) Чтобы задействовать промокод, игрок должен ввести его в канал местного чата, например: /agjtjSfsaAS34 В результате игрок получит Кекс х 45. 2) Логи использования промокодов можно найти в файле: GameServer\LOG\log\pkodev.mod.promo.txt Что можно улучшить 1) В качестве награды можно также выдавать золото, бафы и другие бонусы; 2) Список промокодов можно хранить в базе данных, например, с применением библиотеки LuaSQL; 3) Можно сделать промокоды многоразовыми, но один игрок может использовать промокод только раз.
  45. 3 points
    Hello @Masuka00! It looks cool, thank you! Added your work to the first post. Hello @K1D0! I made a smart icon mod compatible with this mod:
  46. 3 points
    [Мод] Отображение дополнительных параметров на форме с характеристиками персонажа (frmState) Каждый персонаж обладает порядка 74 характеристиками, но на форме "Персонаж" выводятся только некоторые из них. Данный мод позволяет добавлять на форму с характеристиками персонажа (frmState) дополнительные параметры, например, "удача", "скорость бега", "шанс критического удара" и другие. Требования Установленный Загрузчик модов для сервера и клиента (PKOdev.NET mod loader). Информация о моде Название: pkodev.mod.extendedstats; Версия: 1.0; Автор: V3ct0r; Тип: для клиента (Game.exe); Поддерживаемые исполняемые .exe файлы: GAME_13X_0, GAME_13X_1, GAME_13X_2, GAME_13X_3, GAME_13X_4, GAME_13X_5. Установка 1) В директории "mods" Вашего клиента создайте папку "pkodev.mod.extendedstats"; 2) Поместите в неё файл DLL-библиотеки мода "pkodev.mod.extendedstats.13x_<ID>.dll" для Вашей версии Game.exe; 3) Поместите в неё файл настроек мода "pkodev.mod.extendedstats.cfg"; 4) Отредактируйте файл "pkodev.mod.extendedstats.cfg" по своему усмотрению: добавьте список новых текстовых меток с дополнительными характеристиками персонажа в следующем формате: <название_метки> = <ID_характеристики_из_файла_AttrType.lua> Например: labLukShow = 30 labMfShow = 38 labCriticalShow = 39 Таким образом, метка "labLukShow" будет отображать количество удачи (ATTR_LUK), метка "labMfShow" - шанс дропа (ATTR_MF), а метка "labCriticalShow" - шанс критического удара (ATTR_CRT). Файл "AttrType.lua" находится в папке "GameServer\resource\script\calculate" на стороне сервера; 5) Добавьте GUI-скрипты для новых меток в файл "preperty.clu": -- Lucky labLukShow = UI_CreateCompent( frmState, LABELEX_TYPE, "labLukShow", 26, 8, 16, 370 ) UI_SetCaption( labLukShow, "L" ) UI_SetTextColor( labLukShow, COLOR_PURPLE ) UI_SetLabelExFont( labLukShow, DEFAULT_FONT, TRUE, COLOR_WHITE ) -- Critical chance labCriticalShow = UI_CreateCompent( frmState, LABELEX_TYPE, "labCriticalShow", 26, 8, 80, 370 ) UI_SetCaption( labCriticalShow, "C" ) UI_SetTextColor( labCriticalShow, COLOR_PURPLE ) UI_SetLabelExFont( labCriticalShow, DEFAULT_FONT, TRUE, COLOR_WHITE ) -- MF chance labMfShow = UI_CreateCompent( frmState, LABELEX_TYPE, "labMfShow", 26, 8, 144, 370 ) UI_SetCaption( labMfShow, "M" ) UI_SetTextColor( labMfShow, COLOR_PURPLE ) UI_SetLabelExFont( labMfShow, DEFAULT_FONT, TRUE, COLOR_WHITE ) Скачать 1) Бинарные файлы мода (.dll); 2) Исходный код мода для Visual Studio 2019 Community (C++). Если Вы столкнулись с какой-либо проблемой, багом или у Вас возникли вопросы, то пишите в данной теме.
  47. 3 points
    Продолжаем баловать вас новостями: наконец-то успешно запустили игру на IOS(на скриншоте игра запущена на 8 iPhone).
  48. 3 points
  49. 3 points
  50. 3 points
  • Newsletter

    Want to keep up to date with all our latest news and information?
    Sign Up
×
×
  • Create New...