Jump to content

Search the Community

Showing results for tags 'игра'.



More search options

  • Search By Tags

    Type tags separated by commas.
  • Search By Author

Content Type


Forums

  • Russian Section
    • Новости и объявления
    • Пиратия: Документация
    • Пиратия: Релизы
    • Пиратия: Разработка
    • Пиратия: Web
    • Пиратия: Помощь
    • Совместные проекты / набор команды
    • Доска объявлений
    • Программирование
    • Оффтопик
    • Корзина
  • English Section
    • News & Announcements
    • Guides
    • Releases
    • Development
    • Web
    • Questions & Help
    • Shared Projects / Team search
    • Paid services & Requests
    • Programming
    • Offtopic
    • Recycle bin
  • Portuguese Section
    • Dúvidas & Ajuda
  • Spanish Section
    • Preguntas y Ayuda
  • Servers
    • Russian servers
    • English servers

Find results in...

Find results that contain...


Date Created

  • Start

    End


Last Updated

  • Start

    End


Filter by number of...

Joined

  • Start

    End


Group


Found 3 results

  1. [Гайд] Пример создания модификации: Вывод дополнительных характеристик персонажа Привет! В данной статье я расскажу как создать мод для клиента игры, который позволит выводить дополнительные характеристики персонажа на форме "Персонаж" (см. скриншот выше). Благодарю участника нашего форума @Graf за идею мода и гайда: Вам понадобится 1) Game.exe для которого будет создаваться модификация; 2) OllyDbg v1.10; 3) IDA Pro (необязательно, можно пользоваться только OllyDbg); 4) Visual Studio 2022 Community Edition и библиотека MS Detours; 5) Исходный код клиента; 6) Знание основ программирования на C/C++ и ассемблере. Навыки написания DLL-библиотек. Опыт работы с вышеуказанными программами. Создание мода В качестве примера реализуем вывод трех дополнительных характеристик: удача (ATTR_LUK ), шанс критического удара (ATTR_CRT ) и шанс дропа (ATTR_MF). 1) Поместим на форму с характеристиками (frmState) персонажа 3 текстовые метки: удача (labLukShow), шанс критического удара (labCriticalShow), шанс дропа (labMfShow). 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 ) -- Drop 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 ) 2) Изучив исходный код клиента, находим функцию void CStateMgr::RefreshStateFrm(), в которой происходит обновление меток с характеристиками персонажа. Далее нам будет необходимо перехватывать её вызов и обновлять наши новые метки. Так же есть функция void CStateMgr::_evtMainShow(CGuiData *pSender), она вызывается при открытии формы характеристик персонажа и её можно использовать для получения указателей на объекты текстовых меток в памяти игры. Параметр pSender это указатель на форму frmState, объекта класса CCompent, у которого есть метод CCompent* CForm::Find(const char* str), этот метод понадобится для получения указателей на метки по их именам, указанных в lua скриптах GUI клиента. Чтобы установить текст меток, нам будет нужен метод void CLabel::SetCaption(const char * str). Наконец, для доступа к параметрам нашего персонажа, нам будет нужен указатель на персонажа, которым управляет игрок. 3) Для поиска адресов в Game.exe будем использовать программу IDA Pro. void CStateMgr::RefreshStateFrm(). Данный метод можно найти по какой-либо уникальной строке, например, "%4.2f%%". Ищем эту строку в IDA Pro и находим её использование только в одной функции по адресу 0x0047F190 - это и есть искомый метод. void CStateMgr::_evtMainShow(CGuiData *pSender). Это обработчик события открытия формы характеристик персонажа, значит он где-то "вешается" на объект в формы. Проверим в исходном коде клиента игры в методе инициализации формы frmState: bool CStateMgr::Init() { CFormMgr &mgr = CFormMgr::s_Mgr; frmState = _FindForm("frmState"); if( !frmState ) return false; frmState->evtShow = _evtMainShow; labStateName = dynamic_cast<CLabelEx*>(frmState->Find("labStateName")); if( !labStateName ) return Error( g_oLangRec.GetString(45), frmState->GetName(), "labStateName" ); labStateName->SetIsCenter(true); Теперь необходимо найти этот код в Game.exe. Для этого выполняем поиск по строке "frmState". В этот раз нам повезло меньше, найдено 3 использования такой строки: Смотрим первое использование: Рядом так же видно использование строк "btnState", "btnSkill", и "frmSkill". Но в искомом коде таких строк рядом нет. Очевидно, этот адрес нам не подходит. Смотрим второе использование: Строка находится в самом начале функции и рядом есть строка "labStateName". Судя по всему, это наш искомый метод инициализации. Здесь видно, как загружается указатель на форму frmState в регистр EAX, а далее по смещению 0x78, относительно адреса в регистре EAX, помещается какая-то функция. Наверняка, это и есть метод void CStateMgr::_evtMainShow(CGuiData *pSender). Итак, адрес метода void CStateMgr::_evtMainShow(CGuiData *pSender) - 0x0047F7F0. CCompent* CForm::Find(const char* str). Этот метод скорее всего находится в функции инициализации формы, такую мы уже видели: bool CStateMgr::Init(). Просмотрев исходный код, видим следующее: labStateName = dynamic_cast<CLabelEx*>(frmState->Find("labStateName")); if( !labStateName ) return Error( g_oLangRec.GetString(45), frmState->GetName(), "labStateName" ); labStateName->SetIsCenter(true); Это код получения указателя на метку labStateName, нам предстоит сделать то же самое с нашими новыми метками. Идем по адресу 0x0047F9F0 метода bool CStateMgr::Init() в IDA Pro и видим следующий код: .text:0047FA25 push offset aLabstatename ; "labStateName" .text:0047FA2A call dword ptr [eax+48h] Похоже на вызов метода CCompent* CForm::Find(const char* str) для получения указателя на метку labStateName, но его адрес не указан явно. Это говорит о том, что метод виртуальный. Проверим это в исходном коде: virtual CCompent* Find( const char* str ) { return _frmOwn->Find( str ); } Метод действительно является виртуальным. Как же получить его адрес? Как вариант, открыть Game.exe в отладчике, поставить точку останова на адрес 0x0047FA2A и проверить адрес вызываемой функции, но есть проблема - мы не можем запустить клиент напрямую через отладчик, а после запуска эта функция уже не вызывается. Есть второй вариант: поставить точку останова на метод void CStateMgr::_evtMainShow(CGuiData *pSender) (его адрес мы уже знаем), получить адрес формы frmState через параметр pSender, прибавить к нему смещение 0x48 и посмотреть адрес искомого метода. Идем в игру и открываем форму характеристик персонажа: На стеке смотрим адрес параметра pSender - 0x109D5568. По этому адресу находится адрес объекта CStateMgr - 0x006089B4. Прибавляем к этому адресу смещение 0x48, получаем адрес 0x006089FC и переходим по данному адресу в окне отображения памяти процесса: Итак, адрес метода CCompent* CForm::Find(const char* str) равен 0x004941F0. void CLabel::SetCaption(const char * str), в исходном коде вызов этого метода встретится в методе void CStateMgr::RefreshStateFrm(), например: if ( labStateEXP) { if (max!=0) sprintf( pszCha , "%4.2f%%" , num*100.0f/max ); else sprintf( pszCha , "0.00%"); labStateEXP->SetCaption( pszCha ); } Снова ищем строку "%4.2f%%" в IDA Pro и переходим по адресу её использования: Очевидно, что вызов неизвестной функции после двух вызовов библиотечной функции sprintf устанавливает текст метки labStateEXP. Функция является виртуальной, поэтому вновь открываем отладчик, ставим точку останова по адресу 0x0047F2A1 и открываем форму характеристик персонажа в игре: Отладчик подсказывает нам, что по адресу [EDX+3C] находится адрес метода void CLabel::SetCaption(const char * str) - 0x0042B1A0. Указатель на персонажа игрока можно посмотреть в том же методе void CStateMgr::RefreshStateFrm(): CForm * f = g_stUIState.frmState; if( !f->GetIsShow() ) return; CCharacter* pCha = g_stUIBoat.GetHuman(); if( !pCha ) return; SGameAttr* pCChaAttr = pCha->getGameAttr(); if (!pCChaAttr ) return; Переходим на начало метода в IDA Pro: Анализ ассемблерного листинга показывает, что указатель на персонажа игрока находится по адресу 0x00668B6C. Мы нашли все необходимые адреса: 0x0047F7F0 void CStateMgr::_evtMainShow(CGuiData *pSender) 0x0047F190 void CStateMgr::RefreshStateFrm() 0x004941F0 CCompent* CForm::Find(const char* str) 0x0042B1A0 void CLabel::SetCaption(const char * str) 0x00668B6C CCharacter* CBoatMgr::_pHuman 4) Все готово для создания DLL. В качестве языка программирования будем использовать C++. Создаем новый проект Dynamic-Link Library (DLL) в Visual Studio 2022 Community. Поскольку мы будем перехватывать вызовы void CStateMgr::_evtMainShow(CGuiData *pSender) и void CStateMgr::RefreshStateFrm(), то нам понадобится библиотека MS Detours, подключаем её к проекту. Записываем код DLL: #include <windows.h> #include <detours.h> #include <cstdio> namespace pkodev { // Addresses of imported functions from Game.exe namespace address { // void CStateMgr::_evtMainShow(CGuiData *pSender) const unsigned int CStateMgr___evtMainShow = 0x0047F7F0; // void CStateMgr::RefreshStateFrm() const unsigned int CStateMgr__RefreshStateFrm = 0x0047F190; // CCompent* CForm::Find( const char* str ) const unsigned int CForm__Find = 0x004941F0; // void CLabel::SetCaption( const char * str ) const unsigned int CLabel__SetCaption = 0x0042B1A0; // CCharacter* CBoatMgr::_pHuman const unsigned int CBoatMgr___pHuman = 0x00668B6C; } namespace pointer { // void CStateMgr::_evtMainShow(CGuiData *pSender) typedef void(__cdecl* CStateMgr___evtMainShow__Ptr)(void*); CStateMgr___evtMainShow__Ptr CStateMgr___evtMainShow = (CStateMgr___evtMainShow__Ptr)(void*)(address::CStateMgr___evtMainShow); // void CStateMgr::RefreshStateFrm() typedef void(__cdecl* CStateMgr__RefreshStateFrm__Ptr)(void*); CStateMgr__RefreshStateFrm__Ptr CStateMgr__RefreshStateFrm = (CStateMgr__RefreshStateFrm__Ptr)(void*)(address::CStateMgr__RefreshStateFrm); // CCompent* CForm::Find( const char* str ) typedef void* (__thiscall* CForm__Find__Ptr)(void*, const char*); CForm__Find__Ptr CForm__Find = (CForm__Find__Ptr)(void*)(address::CForm__Find); // void CLabel::SetCaption( const char * str ) typedef void (__thiscall* CLabel__SetCaption__Ptr)(void*, const char*); CLabel__SetCaption__Ptr CLabel__SetCaption = (CLabel__SetCaption__Ptr)(void*)(address::CLabel__SetCaption); } namespace hook { // void CStateMgr::_evtMainShow(CGuiData *pSender) void __cdecl CStateMgr___evtMainShow(void* pSender); // void CStateMgr::RefreshStateFrm() void __fastcall CStateMgr__RefreshStateFrm(void* This, void* NotUsed); } // Label "labLukShow" void* labLukShow = nullptr; // Label "labCriticalShow" void* labCriticalShow = nullptr; // Label "labMfShow" void* labMfShow = nullptr; } // Entry point BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { switch (ul_reason_for_call) { // DLL attached to the proccess case DLL_PROCESS_ATTACH: // Enable hooks DetourRestoreAfterWith(); DetourTransactionBegin(); DetourUpdateThread(GetCurrentThread()); DetourAttach(&(PVOID&)pkodev::pointer::CStateMgr___evtMainShow, pkodev::hook::CStateMgr___evtMainShow); DetourAttach(&(PVOID&)pkodev::pointer::CStateMgr__RefreshStateFrm, pkodev::hook::CStateMgr__RefreshStateFrm); DetourTransactionCommit(); break; // DLL detached from the proccess case DLL_PROCESS_DETACH: // Disable hooks DetourTransactionBegin(); DetourUpdateThread(GetCurrentThread()); DetourDetach(&(PVOID&)pkodev::pointer::CStateMgr___evtMainShow, pkodev::hook::CStateMgr___evtMainShow); DetourDetach(&(PVOID&)pkodev::pointer::CStateMgr__RefreshStateFrm, pkodev::hook::CStateMgr__RefreshStateFrm); DetourTransactionCommit(); break; } return TRUE; } // void CStateMgr::_evtMainShow(CGuiData *pSender) void __cdecl pkodev::hook::CStateMgr___evtMainShow(void* pSender) { // Get pointers to the labels pkodev::labLukShow = pkodev::pointer::CForm__Find(pSender, "labLukShow"); pkodev::labCriticalShow = pkodev::pointer::CForm__Find(pSender, "labCriticalShow"); pkodev::labMfShow = pkodev::pointer::CForm__Find(pSender, "labMfShow"); // Call original CStateMgr___evtMainShow() function pkodev::pointer::CStateMgr___evtMainShow(pSender); } // void CStateMgr::RefreshStateFrm() void __fastcall pkodev::hook::CStateMgr__RefreshStateFrm(void* This, void* NotUsed) { // Call original function CStateMgr::RefreshStateFrm() pkodev::pointer::CStateMgr__RefreshStateFrm(This); // Get pointer to the main character // CCharacter* pCha = g_stUIBoat.GetHuman(); void* pCha = reinterpret_cast<void*>( *reinterpret_cast<unsigned int*>(pkodev::address::CBoatMgr___pHuman) ); if (pCha == nullptr) { // Exit from the hook return; } // Define ATTR constants const unsigned int ATTR_LUK = 30; const unsigned int ATTR_MF = 38; const unsigned int ATTR_CRT = 39; // Get offset to the attribute auto attr_get = [&pCha](unsigned int id) -> unsigned int { return *reinterpret_cast<unsigned int*>( (0xD0 + 4 * id + reinterpret_cast<unsigned int>(pCha)) ); }; // Buffer for labels captions char buf[128]{ 0x00 }; // Show character's ATTR_LUK if (pkodev::labLukShow != nullptr) { sprintf_s(buf, sizeof(buf), "LUK: %d", attr_get(ATTR_LUK)); pkodev::pointer::CLabel__SetCaption(pkodev::labLukShow, buf); } // Show character's ATTR_CRT if (pkodev::labCriticalShow != nullptr) { sprintf_s(buf, sizeof(buf), "CRT: %d", attr_get(ATTR_CRT)); pkodev::pointer::CLabel__SetCaption(pkodev::labCriticalShow, buf); } // Show character's ATTR_MF if (pkodev::labMfShow != nullptr) { sprintf_s(buf, sizeof(buf), "MF: %d", attr_get(ATTR_MF)); pkodev::pointer::CLabel__SetCaption(pkodev::labMfShow, buf); } } 1. В начале определяем найденные нами в пункте 3 адреса методов, функций и объектов; 2. Далее определяем указатели на необходимые функции и методы; 3. Затем определяем функции-перехватчики и глобальные переменные под указатели на текстовые метки; 4. В функции DllMain() записываем код для установки и снятия перехватчиков с помощью библиотеки Detours; 5. Реализуем перехватчик pkodev::hook::CStateMgr___evtMainShow(). В этой функции получаем указатели на объекты новых меток labLukShow, labCriticalShow и labMfShow с помощью метода CCompent* CForm::Find(const char* str); 6. Реализуем перехватчик pkodev::hook::CStateMgr__RefreshStateFrm(). Сначала получаем указатель на персонажа, которым управляет игрок. Далее записываем константы, обозначающие ID требуемых характеристик. Теперь стоит задача получения этих характеристик из памяти игры. В исходном коде клиента для этого используется указатель на объект типа SGameAttr, связанный с персонажем: SGameAttr* pCChaAttr = pCha->getGameAttr(); if (!pCChaAttr ) return; Анализ ассемблерного листинга показывает, что этот указатель находится по смещению 0xD0 относительно указателя на персонажа: .text:0047F1D2 mov ebx, dword_668B6C . . . .text:0047F1E4 add ebx, 0D0h Посмотрим что представляет собой объект SGameAttr в исходном коде: struct SGameAttr { long lAttr[MAX_ATTR_CLIENT]; // MAX_ATTR_CLIENT = 74 . . . }; Это структура, которая содержит только одно поле - массив из 74 целых чисел по 4 байта каждое, индексы элементов которого соответствует ID характеристик персонажа (см. файл AttrType.lua из скриптов GameServer). Из курса программирования мы знаем, что все элементы массива хранятся в памяти друг за другом. Значит, чтобы получить адрес характеристики персонажа с определенным ID, мы можем воспользоваться следующей формулой: 0xD0 + 4 * <ID> + <Адрес персонажа в памяти> Осталось самое простое: вывести требуемые характеристики персонажа в новые текстовые метки с помощью метода void CLabel::SetCaption(const char * str). 5) Компилируем проект и присоединяем DLL библиотеку к процессу игры. В результате мы получим следующее: После успешного тестирования, процесс создания модификации клиента завершен. Отмечу, что в примере я использовал GAME_13X_2, в Вашем Game.exe найденные адреса могут отличаться. Если у Вас возникли вопросы, то смело задавайте их в этой теме. Ниже прикладываю проект DLL-библиотеки и DLL-библиотеку мода. Скачать Архив с проектом DLL библиотеки модификации для Visual Studio 2022 Community и DLL библиотекой модификации из примера (286 Кб) Также на основе данной статьи был создан полноценный мод для вывода характеристик персонажа, который не ограничивается тремя характеристиками:
  2. [C++] Игра "Угадай число!" Привет! В данной статье мы напишем на языке программирования C++ простую игру "Угадай число". Компьютер загадывает натуральное число от 1 до 100 включительно, а игрок в свою очередь должен его отгадать. Если игрок назвал неправильное число, то компьютер дает подсказку: загаданное число больше или меньше числа игрока. Игра продолжается до тех пор, пока игрок не отгадает число. Статья предназначена для начинающих программистов. Код будет выполнен в рамках стандарта C++11, автор будет использовать среду разработки Microsoft Visual Studio Community 2017 (скачать). Код должен успешно компилироваться как под Windows, так и под Linux, то есть является кроссплатформенным. У игры очень простой алгоритм: 1) Компьютер "загадывает" случайное натуральное число от 1 до 100 включительно; 2) Игрок вводит предполагаемое число (ответ) с клавиатуры; 3) Программа сравнивает два числа и выдает результат. 4) Если числа не равны, то "сказать" пользователю больше его ответ или меньше числа, загаданного компьютером. Перейти на шаг 2; 5) Числа равны. Поздравить игрока с победой и перейти на шаг 1. Приступим к реализации игры. Сначала компьютер загадывает случайное натуральное число от 1 до 100. Для этого используется генератор случайных чисел. Для работы с генератором случайных чисел будем применять 2 функции из стандартной библиотеки: srand() и rand(). Функция srand() нужна чтобы задать начало псевдослучайной последовательности чисел, генерируемой функцией rand(). Обычно, в функцию srand() передается текущее системное время. Чтобы получить текущее системное время можно использовать функцию time(). Функция srand() должна вызываться перед вызовом функции rand(), как правило, это делается один раз в начале работы программы. Если этого не сделать, то функция rand() все время будет "отдавать" одинаковые "случайные числа", и наша игра будет загадывать одни и те же числа. // Запускаем генератор случайных чисел std::srand(static_cast<unsigned int>(std::time(nullptr))); Мы инициализировали генератор случайных чисел и теперь можем загадывать число от 1 до 100 с помощью функции rand(). Чтобы загадать очередное число будем использовать следующее выражение: // Загадываем натуральное число // от 1 до 100 int n = (std::rand() % 100) + 1; Функция rand() может возвращать числа от 0 до 32767 включительно. Чтобы преобразовать этот "первичный" интервал в нужный нам интервал от 1 до 100, можно с помощью оператора % взять остаток от деления на 100 у любого числа из первичного интервала и прибавить к нему 1. Например, функция rand() вернула число 256. Остаток от деления на 100 будет равен 56. Прибавляем единицу и получаем число 57, которое и должен будет отгадать игрок: 256 % 100 = 56 56 + 1 = 57 Далее, после того, как компьютер загадал случайное число, просим игрока ввести его предполагаемый ответ: // Ответ игрока int guess = 0; // Просим игрока ввести ответ std::cout << "Введите число:" << std::endl; std::cout << ">> "; std::cin >> guess; С помощью оператора cin получаем целое число с клавиатуры - ответ игрока, и записываем данное число в переменную guess. Будем спрашивать игрока до тех пор, пока он не отгадает число. Для этого воспользуемся циклом do-while (см. ниже). На данном этапе у нас есть два числа: загаданное компьютером и ответ игрока. Осталось их сравнить. Для сравнения двух чисел воспользуемся оператором if и операторами больше (>) - меньше (<): // Ответ игрока int guess = 0; do { /* Тут получаем предполагаемое число (ответ) от игрока с клавиатуры */ // Проверяем ответ if (n > guess) { std::cout << "Не угадал! Моё число больше." << std::endl; } else if (n < guess) { std::cout << "Не угадал! Моё число меньше." << std::endl; } } while (n != guess); Если игрок не угадал число, то выводится соответствующее сообщение и цикл повторяется. В случае, если игрок угадал число, цикл прерывается и выводится сообщение о победе: // Игрок угадал число std::cout << "Верно! Загадать еще число? (Y/N)" << std::endl; std::cout << ">> "; std::cin >> answer; В конце игры можно просто выйти из программы, а можно спросить игрока, хочет ли он чтобы компьютер загадал еще одно число и тем самым продолжить игру. Для этого поместим написанный выше код в цикл do-while (весь лишний код был заменен на комментарии): // Ответ на вопрос "Загадать еще число?" char answer = 0; // Запускаем генератор случайных чисел // Запускаем игровой цикл do { // Загадываем натуральное число // от 1 до 100 do { // Получаем ответ от игрока // Сравниваем ответ игрока с загаднным компьютером числом } while (/* игрок не угадал число */); // Игрок угадал число std::cin >> answer; } while (std::strchr("Nn", answer) == nullptr); В символьную переменную answer записываем ответ игрока с клавиатуры. Предполагается, что игрок введет символ Y (продолжить игру) или символ N (выйти из игры). Далее с помощью функции strchr() ищем введенный символ в строке "Nn". Таким образом, неважно в каком регистре игрок ввел символ: N или n. while (std::strchr("Nn", answer) == nullptr); Если в строке "Nn" не будет найден символ, введенный игроком с клавиатуры, то функция strchr() вернет нулевой указатель (nullptr) и цикл продолжится. Иначе функция вернет указатель на найденный в строке символ и цикл завершится. То есть, если игрок введет символ N или n, то программа завершится. Если он введет любой другой символ, то будет загадано новое число и игра продолжится. После цикла происходит выход из программы - игра закрывается: return 0; Итак, были отмечены все ключевые особенности реализации варианта игры "Угадай число", поэтому далее приведу полный код программы: #include <iostream> #include <limits> #include <ctime> #include <cstdlib> // Точка входа int main(int argc, char *argv[]) { // Ответ на вопрос "Загадать еще число?" char answer = 0; // Поддержка русского языка setlocale(LC_ALL, "Russian"); // Запускаем генератор случайных чисел std::srand(static_cast<unsigned int>(std::time(nullptr))); // Выводим правила игры std::cout << "Игра \"Угадай число\"" << std::endl; std::cout << "Привет! Я загадал число от 1 до 100. Угадай его!" << std::endl << std::endl; // Запускаем игровой цикл do { // Загадываем натуральное число // от 1 до 100 int n = (std::rand() % 100) + 1; // Ответ игрока int guess = 0; do { // Просим игрока ввести ответ std::cout << "Введите число:" << std::endl; std::cout << ">> "; std::cin >> guess; // Проверим, что пользователь ввел число if (std::cin.fail() == true || (guess <= 0 || guess > 100)) { std::cin.clear(); std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); std::cout << "Введите натуральное число от 1 до 100!" << std::endl; continue; } // Проверяем ответ if (n > guess) { std::cout << "Не угадал! Моё число больше." << std::endl; } else if (n < guess) { std::cout << "Не угадал! Моё число меньше." << std::endl; } } while (n != guess); // Игрок угадал число std::cout << "Верно! Загадать еще число? (Y/N)" << std::endl; std::cout << ">> "; std::cin >> answer; } while (std::strchr("Nn", answer) == nullptr); return 0; } При желании Вы можете добавить выбор игроком уровня сложности, например: Легкий уровень - загадывается число в интервале от 1 до 100, неограниченное число попыток; Средний уровень - загадывается число в интервале от 1 до 1000, число попыток 25; Сложный уровень - загадывается число в интервале от 1 до 10000, число попыток 50. Также можно добавить учет очков, набранных игроками. Чем меньше попыток угадать число сделал игрок, тем больше он зарабатывает очков: <Заработанные очки> = max(0, 100 - <Число ходов>) Очки хранить в памяти приложения или в файле: // score.txt Вася 100 Петя 53 Катя 42 Саша 65 Если у Вас есть какие-либо вопросы или замечания, то пишите о них в этой теме!
  3. Новые игровые возможности из Китая Всем привет! В данной теме я хочу Вам показать некоторые новые игровые возможности, которые создали наши коллеги из Китая. О них нам рассказал пользователь HeitorLPO (@Heitor) в нашем чате Discord (сервер TOP/PKO/KOP, канал #general-english). Так же пользователь @Sk3let0n дал нам ссылку на китайский сервер, где были реализованы фишки, о которых пойдет речь: www.syhai.com О некоторых новых возможностях нам пока мало что известно, поэтому приходится только догадываться для чего они нужны. Так же есть вопросы относительно китайского сервера: Официальный это сервер или нет? Задумывались ли эти возможности разработчиками игры, либо это уникальная разработка данного сервера? Работает ли администрация сервера с разработчиками игры? Есть ли еще серверы с такими возможностями? Итак: 1. Питомцы, на которых можно ездить верхом - "маунты" (ride-system): 2. Новый инвентарь. Теперь феи, крылья, ездовые питомцы одеваются в отдельные слоты (inventory interface with new items equipeable [pet , wings ....] ): 3. Система талантов (talent interface system): 4. Новая система ковки снаряжения (special forge system interface): 5. Встроенный в клиент игры бот (auto atk boot system interface in game): На этом пока все. Пишите в данной теме свое мнение по поводу новых возможностей!
×
×
  • Create New...