Это популярное сообщение. Kondr48 314 Опубликовано 15 Августа 2016 Это популярное сообщение. Поделиться Опубликовано 15 Августа 2016 (изменено) Ковыряемся в исходниках SoC. На данный момент тема ориентирована в большей степени на новичков. Здесь будут собираться готовые решения по мелкому ковырянию исходников движка SoC. Собственно приглашаю всех желающих присоединиться. Сборка исходников, необходимые программы. Расширения для диалогов: Скрытый текст Один из вариантов реализации случайных фраз у диалогов. Автор: Winsor. Часть 2. + немного переделанная функция дампа xml Автор: Winsor. Исправление ошибок: Скрытый текст Исправление отображения зеленым цветом прочитанных записей в разделе КПК "Дневник". Автор: lvg_brest Маленькое исправление колбека before save. Нашел: Карлан. Исправление сохранения клиентских объектов. Автор: Shoker Фикс вертикальной синхронизации (r2) Автор: SkyLoader Фикс не отключения ПНВ при удалении броника ф-циями release\transfer_item или продаже\выкладывании в другой инвентарь, автор: UnLoaded Исправление вылета по отсутствию звука. Путь до звука выводится в лог (как с текстурами в ЗП). Исправление пулестойкости костюма. Расширение скриптового функционала: Скрытый текст Функции, возвращающие текущий год и месяц. Функция перемотки времени из CoP. Создание колбеков для Актора на примере колбека на удар ножом. Назначение скриптам горячих клавиш, изменяемых в главном меню. Создание функции, перебирающей предметы на поясе. Работа с интерфейсом (худ, инвентарь и т.п.): визуальная часть: Скрытый текст Редактирование загрузочного экрана. Создание нового индикатора на худе. Расширение геймплея: Скрытый текст Создание нового слота. Новые параметры для бронежилетов. Восстановление функции рождения артефактов при срабатывании аномалии. Автор: Bak Добавление изменения переносимого веса в свойства артефактов. Массовое перемещение предметов между окнами, Автор: UnLoaded Зум в один клик. Автор: Shkiper2012. Дополнение: Kondr48 Порция мелких правок от Shkiper2012. Работа с рендером: Скрытый текст Скриншоты в формате png. Изменено 2 Ноября 2017 пользователем Kondr48 4 13 Ссылка на комментарий
Kondr48 314 Опубликовано 1 Апреля 2017 Автор Поделиться Опубликовано 1 Апреля 2017 В файле xray\xr_3da\xrRender\r__screenshot.cpp находим: case IRender_interface::SM_NORMAL: Заменяем: CHK_DX (D3DXSaveSurfaceToFileInMemory (&saved,D3DXIFF_JPG,pFB,0,0)); на: CHK_DX (D3DXSaveSurfaceToFileInMemory (&saved,D3DXIFF_PNG,pFB,0,0)); Теперь расширение, чуть выше меняем: ss_%s_%s_(%s).jpg на, соответственно: ss_%s_%s_(%s).png P. S. на самом деле, кроме формата png есть и другие варианты) typedef enum _D3DXIMAGE_FILEFORMAT { D3DXIFF_BMP = 0, D3DXIFF_JPG = 1, D3DXIFF_TGA = 2, D3DXIFF_PNG = 3, D3DXIFF_DDS = 4, D3DXIFF_PPM = 5, D3DXIFF_DIB = 6, D3DXIFF_HDR = 7, //high dynamic range formats D3DXIFF_PFM = 8, // D3DXIFF_FORCE_DWORD = 0x7fffffff } Т. е, доступны такие расширения, как: bmp, jpg, tga, png, dds, ppm, dib, hdr, pfm. 2 2 Ссылка на комментарий
Kondr48 314 Опубликовано 2 Апреля 2017 Автор Поделиться Опубликовано 2 Апреля 2017 Исправление вылета по отсутствию звука. Путь до звука выводится в лог (как с текстурами в ЗП). Автор: Zagolski Добавлено Kondr48, 2 Апреля 2017 Проверил, действительно работает, сюда продублирую ссылку, чтобы не затерялось потом в той теме. 1 Ссылка на комментарий
Romann 619 Опубликовано 28 Апреля 2017 Поделиться Опубликовано 28 Апреля 2017 Для сборки нам понадобится установить на ПК: 2. Visual Studio 2010 Service Pack 1 4. DirectX SDK June 2007. Если ставили 2010, то 2007 ОБЯЗАТЕЛЬНО нужно ставить после 10. 5. Windows SDK Может кто подсказать, где всё это взять? Сутки шарюсь по сети, или везде всё мертвое(ссылки), или не пойми чего попадается.. Добавлено Kondr48, 19 Июня 2017 DirectX SDK June 2007 https://yadi.sk/d/qVnFuMeP3KGta2 Мать: ASRock X470 Master SLI. Процессор: AMD Ryzen 9 3900X 12-Core(4200 MHz). Память: Patriot Memory 3200 C16 Series. DDR4-3200(1600МГц), 16Гбх2(32Гб). Видео: GeForce GTX 1060 6GB. Блок питания: CoolerMaster 750 Вт. Корпус: Zalman i3 Edge. Химера конечно сильный хищник, а все держится дома. Чего же ты пришел к ней домой и пытаешься её убить? © Болотный Доктор Ссылка на комментарий
Kirgudu 1 143 Опубликовано 28 Апреля 2017 Поделиться Опубликовано 28 Апреля 2017 @Romann,DX SDK - попробуй августовский за тот же год: https://www.microsoft.com/en-us/download/details.aspx?id=13287Студию поищи сам, это всё-таки платный продукт (пункт 8.1 правил форума). 1 1 Инструмент Ссылка на комментарий
Это популярное сообщение. Kondr48 314 Опубликовано 26 Июня 2017 Автор Это популярное сообщение. Поделиться Опубликовано 26 Июня 2017 (изменено) Исправление пулестойкости костюмов. Скрытый текст Кто-то слышал, кто-то нет, как разработчики некоторых глобальных модов упоминали (ну по крайней мере я что-то подобное помню), что в движок закралась какая-то чудовищная ошибка и на самом деле бронежилеты от пуль не защищают и чуть ли не чем больше показатель, тем хуже. Однако, в принципе, не так все страшно. На самом деле в этом плане никакой ошибки нет. Просто в Сталкере (речь идет о ТЧ, насчет других частей серии - не уверен, хотя суть та же скорее всего) расчет хита от пули происходит иначе, чем от любого другого воздействия. А конкретно, берутся настройки костей, что позволяет более гибко эту самую пулестойкость настроить. Подробнее можно почитать здесь. Пулестойкость ГГ рассчитывается также, как у НПС. На самом деле, это легко исправить. Возможно ,кому-то не понравится такой способ, ибо если выставить у костюма 100% защиты, то новый костюм будет полностью защищать от пуль (ну пока не износится само собой) не учитывая, что какие-то участки защищены сильнее/слабее. Как по мне, защита по костям, конечно, реалистичнее, но вариант просто в процентах - более играбельный, ведь игрок видит в инвентаре насколько его защищает данный костюм и эта цифра соответствует действительности. Итак. Как сделать работу пулестойкости такой же, как остальные воздействия? Для начала стоит вынести это дело под дефайн, дабы иметь возможность при необходимости включить/отключить данную правку. Для этого, в файл build_config_defines.h нужно добавить: #define FIRE_WOUND_HIT_FIXED // Kondr48: "Фикс" пулестойкости для шлемов и брони. По факту просто выключен механизм расчета хита по костям. Считается также, как остальные хиты. Затем, нам нужен файл EntityCondition.cpp Находим: float CEntityCondition::HitOutfitEffect(float hit_power, ALife::EHitType hit_type, s16 element, float AP) { CInventoryOwner* pInvOwner = smart_cast<CInventoryOwner*>(m_object); if(!pInvOwner) return hit_power; CCustomOutfit* pOutfit = (CCustomOutfit*)pInvOwner->inventory().m_slots[OUTFIT_SLOT].m_pIItem; if(!pOutfit) return hit_power; float new_hit_power = hit_power; if (hit_type == ALife::eHitTypeFireWound) new_hit_power = pOutfit->HitThruArmour(hit_power, element, AP); else new_hit_power *= pOutfit->GetHitTypeProtection(hit_type,element); //увеличить изношенность костюма pOutfit->Hit (hit_power, hit_type); return new_hit_power; } и переписываем вот так: float CEntityCondition::HitOutfitEffect(float hit_power, ALife::EHitType hit_type, s16 element, float AP) { CInventoryOwner* pInvOwner = smart_cast<CInventoryOwner*>(m_object); if(!pInvOwner) return hit_power; CCustomOutfit* pOutfit = (CCustomOutfit*)pInvOwner->inventory().m_slots[OUTFIT_SLOT].m_pIItem; if(!pOutfit) return hit_power; float new_hit_power = hit_power; #ifndef FIRE_WOUND_HIT_FIXED if (hit_type == ALife::eHitTypeFireWound) new_hit_power = pOutfit->HitThruArmour(hit_power, element, AP); else #endif new_hit_power *= pOutfit->GetHitTypeProtection(hit_type,element); //увеличить изношенность костюма pOutfit->Hit (hit_power, hit_type); return new_hit_power; } В принципе, на этом можно было бы и закончить, однако можно под дефайн вынести и неиспользуемые функции в CustomOutfit. Это будет более правильно, потому что исключит неиспользуемые участки кода. Итак, дальше я буду приводить только участки под дефайном. Соответственно, Вам нужно будет найти эту часть в файле и сделать также. 1. CustomOutfit.h Добавим инклуд вначале: #include "..\..\..\build_config_defines.h" #ifndef FIRE_WOUND_HIT_FIXED struct SBoneProtections; #endif #ifndef FIRE_WOUND_HIT_FIXED float HitThruArmour (float hit_power, s16 element, float AP); #endif #ifndef FIRE_WOUND_HIT_FIXED SBoneProtections* m_boneProtection; #endif #ifndef FIRE_WOUND_HIT_FIXED virtual BOOL BonePassBullet (int boneID); #endif 2. CustomOutfit.cpp #ifndef FIRE_WOUND_HIT_FIXED #include "BoneProtections.h" #endif #ifndef FIRE_WOUND_HIT_FIXED m_boneProtection = xr_new<SBoneProtections>(); #endif #ifndef FIRE_WOUND_HIT_FIXED xr_delete(m_boneProtection); #endif Функцию CCustomOutfit::GetHitTypeProtection приводим к такому виду: float CCustomOutfit::GetHitTypeProtection(ALife::EHitType hit_type, s16 element) { float fBase = m_HitTypeProtection[hit_type]*GetCondition(); #ifndef FIRE_WOUND_HIT_FIXED float bone = m_boneProtection->getBoneProtection(element); return 1.0f - fBase*bone; #else return 1.0f - fBase; #endif } #ifndef FIRE_WOUND_HIT_FIXED float CCustomOutfit::HitThruArmour(float hit_power, s16 element, float AP) { float BoneArmour = m_boneProtection->getBoneArmour(element)*GetCondition()*(1-AP); float NewHitPower = hit_power - BoneArmour; if (NewHitPower < hit_power*m_boneProtection->m_fHitFrac) return hit_power*m_boneProtection->m_fHitFrac; return NewHitPower; }; BOOL CCustomOutfit::BonePassBullet (int boneID) { return m_boneProtection->getBonePassBullet(s16(boneID)); }; #endif #ifndef FIRE_WOUND_HIT_FIXED if(pSettings->line_exist(cNameSect(),"bones_koeff_protection")) m_boneProtection->reload( pSettings->r_string(cNameSect(),"bones_koeff_protection"), smart_cast<CKinematics*>(pActor->Visual()) ); #endif Вот и всё, если есть какие-то вопросы - пишите, возможно, я забыл что-то указать. Изменено 26 Июня 2017 пользователем Kondr48 1 2 4 Ссылка на комментарий
Demosfen 142 Опубликовано 15 Июля 2017 Поделиться Опубликовано 15 Июля 2017 @Kondr48 Это хорошо, т.е если у костюма 80% пулестойкости то стреляем ему хоть в руку, хоть в голову, эффект будет одинаковый так? Добавлено Kondr48, 15 Июля 2017 Именно. Добавлено Kondr48, 15 Июля 2017 Пройдёт 80% хита. Ссылка на комментарий
Shkiper2012 35 Опубликовано 15 Сентября 2017 Поделиться Опубликовано 15 Сентября 2017 Ссылка на "Сборка исходников, необходимые программы" не работает, либо пост удалён/перенесён. Если перенесён, то куда? Адаптация мода "AtmosFear" для мода "Боевая Подготовка" v.2.0.2. Адаптация мода "Магазинное питание" для мода "Боевая Подготовка" v.2.0.2. Ссылка на комментарий
Это популярное сообщение. Shkiper2012 35 Опубликовано 6 Октября 2017 Это популярное сообщение. Поделиться Опубликовано 6 Октября 2017 (изменено) Порция мелких правок. Скрытый текст Движок 1.0007rc1 (xp-dev), для других версий, возможно будет по-другому. Делал с дефайнами для возможности вкл/выкл. Тут элементарные фишки, которые мне были нужны, решил выложить, может пригодится кому-нибудь. Дефайны можно добавить в 'build_config_defines.h' (если такой есть), либо в начало файла с правкой. // Убираем возможность переключаться между слотами колесиком мыши + небольшая правка для зума. // Скрытый текст #define NO_MOUSE_WHELL_SWITCH_SLOT // Убираем возможность переключаться между слотами колесиком мыши + небольшая правка для зума. /* Убираем возможность переключаться между слотами колесиком мыши. Мне это было нужно, по-этому решил убрать. И тут же поправим кратность зума. Зум будет меняться, только если целимся или смотрим в бинокль. В конфиги бинокля и оружия (у которого хотите сделать динамический зум) нужно добавить: scope_dynamic_zoom = true X:\trunk\xray\xr_3da\xrGame\ActorInput.cpp */ void CActor::IR_OnMouseWheel(int direction) { /* Это убрал: if(inventory().Action( (direction>0)? kWPN_ZOOM_DEC:kWPN_ZOOM_INC , CMD_START)) return; Короткие записи - они, конечно, компактнее, но их читабельность ниже. */ if( IsZoomAimingMode() ) { if( direction > 0 ){ inventory().Action( kWPN_ZOOM_INC, CMD_START ); return; }else{ inventory().Action( kWPN_ZOOM_DEC, CMD_START ); return; } } #ifndef NO_MOUSE_WHELL_SWITCH_SLOT if (direction>0) OnNextWeaponSlot(); else OnPrevWeaponSlot(); #endif } // Блокируем авто-перезарядку и сброс зума, когда закончились патроны. // Скрытый текст #define NO_AUTO_RELOAD_WPN // Блокируем авто-перезарядку и сброс зума, когда закончились патроны. /* Когда в оружие закончаться патроны анимация "прицеливания" не будет уходить в исходное положение "от бедра". X:\trunk\xray\xr_3da\xrGame\WeaponMagazined.cpp */ void CWeaponMagazined::FireEnd() { inherited::FireEnd(); // 1/2 // Блокируем авто-перезарядку и сброс зума, когда закончились патроны. // #ifndef NO_AUTO_RELOAD_WPN // Если делать без дефайна, то этот код нужно закомментировать. // --> // CActor *actor = smart_cast<CActor*>(H_Parent()); if (!iAmmoElapsed && actor && GetState() != eReload){ Reload(); } // <-- // #endif } void CWeaponMagazined::switch2_Empty() { // 2/2 // Блокируем авто-перезарядку и сброс зума, когда закончились патроны. // #ifdef NO_AUTO_RELOAD_WPN if (smart_cast<CActor*>(H_Parent()) != NULL) { OnEmptyClick(); return; } #endif OnZoomOut(); ... } // Bug_Fix: Убираем звук перезарядки, если прячем оружие. // Скрытый текст // Bug_Fix: Убираем звук перезарядки, если прячем оружие. // /* Когда оружие только начало перезаряжаться, и тут же его спрятали или переключились на другой слот - звук перезарядки продолжается проигрываться. Чтобы остановить звук перезарядки, нужно добавить в функции ниже: HUD_SOUND::StopSound(sndReload); X:\trunk\xray\xr_3da\xrGame\WeaponMagazined.cpp */ void CWeaponMagazined::switch2_Hiding() { CWeapon::FireEnd(); HUD_SOUND::StopSound(sndReload); // <--- // PlaySound(sndHide, get_LastFP()); PlayAnimHide(); m_bPending = true; } void CWeaponMagazined::switch2_Hidden() { CWeapon::FireEnd(); HUD_SOUND::StopSound(sndReload); // <--- // if (m_pHUD) m_pHUD->StopCurrentAnimWithoutCallback(); signal_HideComplete(); RemoveShotEffector(); } // Спрячем/показываем предмет в руках, когда откр./закр. инвентарь. // Скрытый текст #define HIDE_WEAPON_IN_INV // Спрячем/показываем предмет в руках, когда откр./закр. инвентарь. /* Из названия, думаю, всё понятно: Открыли инвентарь - оружие(или что-либо в руках) убрали, Закрыли инвентарь - снова достали, то что было в руках. X:\trunk\xray\xr_3da\xrGame\ui\UIInventoryWnd.cpp */ void CUIInventoryWnd::Show() { ... Update (); PlaySnd (eInvSndOpen); // в конец функции нужно добавить: #ifdef HIDE_WEAPON_IN_INV if( IsGameTypeSingle() ) { CActor* pAct = smart_cast<CActor*>(Level().CurrentEntity()); if( pAct ){ pAct->SetWeaponHideState(INV_STATE_BLOCK_ALL, true); } } #endif } void CUIInventoryWnd::Hide() { ... ... SendInfoToActor ("ui_inventory_hide"); ClearAllLists (); // тут нужно добавить: #ifdef HIDE_WEAPON_IN_INV if( IsGameTypeSingle() ) { CActor* pAct = smart_cast<CActor*>(Level().CurrentEntity()); if( pAct ){ pAct->SetWeaponHideState(INV_STATE_BLOCK_ALL, false); } } #endif //достать вещь в активный слот CActor *pActor = smart_cast<CActor*>(Level().CurrentEntity()); ... ... } Изменено 6 Октября 2017 пользователем Shkiper2012 2 2 3 Адаптация мода "AtmosFear" для мода "Боевая Подготовка" v.2.0.2. Адаптация мода "Магазинное питание" для мода "Боевая Подготовка" v.2.0.2. Ссылка на комментарий
Это популярное сообщение. Shkiper2012 35 Опубликовано 10 Октября 2017 Это популярное сообщение. Поделиться Опубликовано 10 Октября 2017 // Зум в один клик. Теперь не нужно удерживать клавишу для прицеливания. // Скрытый текст #define ONE_CLICK_ZOOM // Зум в один клик. Теперь не нужно удерживать клавишу прицеливания. /* В оригинальной игре чтобы целится через мушку/прицел/наблюдение в бинокль, - нужно было удерживать клавишу зума. Не знаю точно, это баг или так и задумано. Эта правка делает прицеливание в одно нажатие клавиши(без удержания): нажал - целишься, нажал снова - оружие к бедру. X:\trunk\xray\xr_3da\xrGame\Weapon.cpp Сделал через дефайн, для возможности вкл./выкл. этой правки. В функции: bool CWeapon::Action(s32 cmd, u32 flags) нужно дополнить: case kWPN_ZOOM: */ bool CWeapon::Action(s32 cmd, u32 flags) { ... switch (cmd) { ... ... case kWPN_ZOOM: if (IsZoomEnabled()) { #ifdef ONE_CLICK_ZOOM if( flags&CMD_START && !IsPending() && !IsZoomed() ) OnZoomIn(); else if( flags&CMD_START && IsZoomed() ) OnZoomOut(); #else if (flags&CMD_START && !IsPending()) OnZoomIn(); else if (IsZoomed()) OnZoomOut(); #endif return true; } else return false; case kWPN_ZOOM_INC: case kWPN_ZOOM_DEC: ... ... } ... } 2 1 5 Адаптация мода "AtmosFear" для мода "Боевая Подготовка" v.2.0.2. Адаптация мода "Магазинное питание" для мода "Боевая Подготовка" v.2.0.2. Ссылка на комментарий
Это популярное сообщение. Kondr48 314 Опубликовано 24 Октября 2017 Автор Это популярное сообщение. Поделиться Опубликовано 24 Октября 2017 (изменено) В дополнение к посту @Shkiper2012 Скрытый текст Эту же фичу можно сделать опциональной. case kWPN_ZOOM: Скрытый текст case kWPN_ZOOM: if (IsZoomEnabled()) { if (psActorFlags.test(AF_ZOOM_CLICK_ENABLE)) { if (flags&CMD_START && !IsPending()) OnZoomIn(); else if (IsZoomed()) OnZoomOut(); } else { if( flags&CMD_START && !IsPending() && !IsZoomed() ) OnZoomIn(); else if( flags&CMD_START && IsZoomed() ) OnZoomOut(); } return true; } else return false; Затем, добавляем новый флаг в Actor_Flags.h AF_ZOOM_CLICK_ENABLE = (1<<11), И регистрируем консольную команду в файле console_commands.cpp void CCC_RegisterCommands() { ... CMD1(CCC_GameDifficulty, "g_game_difficulty" ); CMD3(CCC_Mask, "zoom_click_enable", &psActorFlags, AF_ZOOM_CLICK_ENABLE); ... } Осталось лишь зарегистрировать новый пункт меню в файлах игры. 1. ui_mm_opt_gameplay.script : _st = xml:InitStatic("tab_gameplay:templ_item", self.scroll_v) xml:InitCheck("tab_gameplay:check_zoom_click_enable", _st) 2. ui_mm_opt(_16).xml: <check_zoom_click_enable x="10" y="0" width="243" height="21"> <options_item entry="zoom_click_enable" group="mm_opt_gameplay"/> <text font="letterica18" r="215" g="195" b="170">ui_mm_zoom_click_enable</text> </check_zoom_click_enable> 3. Любой текстовый файл: <string id="ui_mm_zoom_click_enable"> <text>Удерживать ($$ACTION_WPN_ZOOM$$) для прицеливания</text> </string> Изменено 24 Октября 2017 пользователем Kondr48 2 3 2 Ссылка на комментарий
alexus95 1 Опубликовано 29 Октября 2017 Поделиться Опубликовано 29 Октября 2017 Всем привет.недавно попытался адаптировать фичу от bak,которая возвращает функцию рождения артефактов.так вот только возникли проблемы в файлах customzone.cpp и customzone.h. использовал ревизию 201 с xp-dev.кто хорошо разбирается в движке,прошу пожалуйста помогите мне.вас отблагодарю Добавлено Kondr48, 29 Октября 2017 О каких конкретно проблемах-то речь?) Ссылка на комментарий
Это популярное сообщение. Shkiper2012 35 Опубликовано 1 Ноября 2017 Это популярное сообщение. Поделиться Опубликовано 1 Ноября 2017 ТЧ 1.0007rc1 // Уменьшаем вес и цену предмета после использования. // Скрытый текст /* #define EAT_PORTIONS_INFLUENCE // Уменьшаем вес и цену предмета после использования. Автор идеи: Real Wolf. В движке из репо на 'xp-dev.com' [ТЧ 1.0007rc1] - есть наработки от Real Wolf по этой теме. В файле "eatable_item.cpp" есть строки: #if defined(EAT_PORTIONS_INFLUENCE) но дефайн нигде не был объявлен. Собрав движок с объявленным #define EAT_PORTIONS_INFLUENCE - ничего не изменилось. Правка не работала. Немного доработал правку. Работает. Файлы для правки: X:\trunk\xray\xr_3da\xrGame\eatable_item.h X:\trunk\xray\xr_3da\xrGame\eatable_item.cpp X:\trunk\xray\xr_3da\xrGame\inventory_item.h */ // eatable_item.h // Скрытый текст //////////////////// // eatable_item.h // //////////////////// class CEatableItem : public CInventoryItem { // ... // После строки: int GetPortionsNum() const { return m_iPortionsNum; }; // Добавляем это: int GetStartPortionsNum() const { return m_iStartPortionsNum; }; // <--- // Не используется, но может пригодится. // float GetOnePortionWeight(); // <--- // u32 GetOnePortionCost(); // <--- // }; // eatable_item.cpp // Скрытый текст ////////////////////// // eatable_item.cpp // ////////////////////// BOOL CEatableItem::net_Spawn (CSE_Abstract* DC) { // ... if (CSE_ALifeItemEatable* se_eat = smart_cast<CSE_ALifeItemEatable*>(DC)) { m_iPortionsNum = se_eat->m_portions_num; #if defined(EAT_PORTIONS_INFLUENCE) // Уменьшаем вес и цену после использования. // by Real Wolf // /* Это можно удалять, если было! m_weight -= m_weight / m_iStartPortionsNum * m_iPortionsNum; m_cost -= m_cost / m_iStartPortionsNum * m_iPortionsNum; */ if( m_iPortionsNum > 0 ){ float w = GetOnePortionWeight(); float weight = w * m_iPortionsNum; u32 c = GetOnePortionCost(); u32 cost = c * m_iPortionsNum; SetWeight ( weight ); SetCost ( cost ); } #endif } else m_iPortionsNum = m_iStartPortionsNum; return TRUE; } void CEatableItem::UseBy (CEntityAlive* entity_alive) { // ... //уменьшить количество порций if(m_iPortionsNum > 0) --(m_iPortionsNum); else m_iPortionsNum = 0; #if defined(EAT_PORTIONS_INFLUENCE) // Уменьшаем вес и цену после использования. // by Real Wolf // /* Это можно удалять, если было! auto sect = object().cNameSect().c_str(); auto weight = READ_IF_EXISTS(pSettings, r_float, sect, "inv_weight", 0.0f); auto cost = READ_IF_EXISTS(pSettings, r_float, sect, "cost", 0.0f); m_weight -= weight / m_iStartPortionsNum; m_cost -= cost / m_iStartPortionsNum; */ float w = GetOnePortionWeight(); float weight = m_weight - w; u32 c = GetOnePortionCost(); u32 cost = m_cost - c; SetWeight ( weight ); SetCost ( cost ); #endif // ... } // В конце файла, добавляем новые методы класса: // float CEatableItem::GetOnePortionWeight() { float rest = 0.0f; LPCSTR sect = object().cNameSect().c_str(); float weight = READ_IF_EXISTS( pSettings, r_float, sect, "inv_weight", 0.100f ); s32 portions = pSettings->r_s32( sect, "eat_portions_num" ); if( portions > 0 ){ rest = weight / portions; }else{ rest = weight; } return rest; } u32 CEatableItem::GetOnePortionCost() { u32 rest = 0; LPCSTR sect = object().cNameSect().c_str(); u32 cost = READ_IF_EXISTS( pSettings, r_u32, sect, "cost", 1); s32 portions = pSettings->r_s32( sect, "eat_portions_num" ); if( portions > 0 ){ rest = cost / portions; }else{ rest = cost; } return rest; } // inventory_item.h // Скрытый текст ////////////////////// // inventory_item.h // ////////////////////// class CInventoryItem : public CAttachableItem, public CHitImmunity #ifdef DEBUG , public pureRender #endif { // ... // После строк: virtual u32 Cost () const { return m_cost; } virtual void SetCost (u32 cost) { m_cost = cost; } virtual float Weight () { return m_weight;} // Добавить это: virtual void SetWeight (float w) { m_weight = w; } // <--- // // ... }; // У бинокля меньшая кратность зума изначально. // Скрытый текст /* Когда пользуешься биноклем, изначально кратность зума почему-то всегда максимальная. Это не всегда удобно. Правка делает кратность зума(при загрузке локации) равной = g_fov актора, т.е. как будто смотришь без бинокля. Вместо g_fov можно использовать свои настройки. !!! Обратите внимание. !!! Если делать оружие на классе бинокля, то эту правку нужно откорректировать под ваши задачи/оружие. X:\trunk\xray\xr_3da\xrGame\WeaponBinoculars.cpp */ BOOL CWeaponBinoculars::net_Spawn (CSE_Abstract* DC) { // m_fRTZoomFactor = m_fScopeZoomFactor; // <--- Было <--- // m_fRTZoomFactor = g_fov; // <--- Стало <--- // // ... } // Убираем троеточие в строках, при загрузке локации, типа: "Клиент: Синхронизация..." // Скрытый текст /* Вроде мелочь, а (по моему скромному мнению) выглядит лучше без точек. X:\trunk\xray\xr_3da\xrGame\GamePersistent.cpp */ void CGamePersistent::LoadTitle(LPCSTR str) { // ... // sprintf_s (buff, "%s...", CStringTable().translate(str).c_str()); // <--- Было <--- // sprintf_s (buff, "%s", CStringTable().translate(str).c_str()); // <--- Стало <--- // // ... } // Убираем прогресс-бары "точности, скорострельности и т.д." для ножа. // Скрытый текст /* Правка убирает прогресс-бары в описании предметов: ножа, ПБС/глушителей, и бинокля. Для ПБС и бинокля они были убраны изначально. А для ножа - нет. Сделал так, что бы проверка на "Показывать прогресс-бар?" была не по секции предмета, как было изначально в оригинале игры, а по классу предмета. Тем самым, можно на этих классах делать другие предметы, не опасаясь, что в описании будут "полоски" характеристик для оружия. !!! Обратите внимание. !!! Если делать оружие на классе бинокля, то эту правку нужно откорректировать под ваши задачи/оружие. X:\trunk\xray\xr_3da\xrGame\ui\UIWpnParams.cpp */ bool CUIWpnParams::Check(const shared_str& wpn_section){ if (pSettings->line_exist(wpn_section, "fire_dispersion_base")) { /* Это можно удалять! if (0==xr_strcmp(wpn_section, "wpn_addon_silencer")) return false; if (0==xr_strcmp(wpn_section, "wpn_binoc")) return false; if (0==xr_strcmp(wpn_section, "mp_wpn_binoc")) return false; */ const char* wpn_clsid_str = pSettings->r_string( wpn_section, "class" ); if( strstr( wpn_clsid_str, "KNIFE") || strstr( wpn_clsid_str, "SILENC") || strstr( wpn_clsid_str, "BINOC") ){ return false; } return true; } else return false; } 1 2 1 4 Адаптация мода "AtmosFear" для мода "Боевая Подготовка" v.2.0.2. Адаптация мода "Магазинное питание" для мода "Боевая Подготовка" v.2.0.2. Ссылка на комментарий
aromatizer 4 400 Опубликовано 2 Ноября 2017 Поделиться Опубликовано 2 Ноября 2017 В 27.06.2017 в 00:03, Kondr48 сказал: Исправление пулестойкости костюмов. Хочу уточнить: это работает только для ГГ? Добавлено Kondr48, 2 Ноября 2017 Скорее всего для НПС тоже, но лучше проверить. Отношения между людьми- главная ценность в человеческом обществе.Любая полученная информация- это только повод для размышлений, а не побуждение к действию.Это должен знать каждый: уроки боевой подготовки Дяди Саши https://yadi.sk/d/60Ec2B06goLAEНакопано и накнопано:https://yadi.sk/d/mzVY5jQEspwpt Ссылка на комментарий
Fagot. 400 Опубликовано 2 Ноября 2017 Поделиться Опубликовано 2 Ноября 2017 (изменено) Ссылка из шапки "Сборка исходников, необходимые программы" ведёт не туда, куда надо. Прошёл опять по ссылке - всё также. Ссылка ведёт на пост, в котором нет "необходимых программ". Изменено 2 Ноября 2017 пользователем Fagot. Добавлено Kondr48, 2 Ноября 2017 Я вообще этот свой пост что-то не наблюдаю в теме... Добавлено Kondr48, 2 Ноября 2017 Все на месте. Там просто в некоторых постах спойлеры побились. При случае поправлю. 1 С.Т.А.Л.К.Е.Р. - Равновесие-2 Проект виртуальной реконструкции г.Припять. Ссылка на комментарий
Это популярное сообщение. Zander_driver 10 319 Опубликовано 29 Ноября 2019 Это популярное сообщение. Поделиться Опубликовано 29 Ноября 2019 Делаю первые шаги в C++ Так что сильно не пинайте. Но, правочки такой, почему-то никто не выкладывал. Выложу тогда я. Скрытый текст Добавление возможности автокоррекции размеров иконок и сеток, в окнах слотов и инвентаря. Править потребовалось один единственный файл: xrGame/ui/UIXmlInit.cpp Один метод в нем, изменил вот так: bool CUIXmlInit::InitDragDropListEx(CUIXml& xml_doc, const char* path, int index, CUIDragDropListEx* pWnd) { R_ASSERT3(xml_doc.NavigateToNode(path,index), "XML node not found", path); float x = xml_doc.ReadAttribFlt(path, index, "x"); float y = xml_doc.ReadAttribFlt(path, index, "y"); float width = xml_doc.ReadAttribFlt(path, index, "width"); float height = xml_doc.ReadAttribFlt(path, index, "height"); InitAlignment (xml_doc, path, index, x, y, pWnd); pWnd->Init (x,y, width,height); Ivector2 w_cell_sz, w_cells, w_cell_sp; // Add by Zander Fvector2 device_scale; device_scale.x = 1024.0f / _max((float)Device.dwWidth, 1.0f); device_scale.y = 768.0f / _max((float)Device.dwHeight, 1.0f); int autclc = xml_doc.ReadAttribInt(path, index, "autocalc", 0); int cellmin = xml_doc.ReadAttribInt(path, index, "cell_minimals", 0); // end w_cell_sz.x = xml_doc.ReadAttribInt(path, index, "cell_width"); w_cell_sz.y = xml_doc.ReadAttribInt(path, index, "cell_height"); // Add by Zander if (autclc == 1) { w_cell_sz.x = (int)round(w_cell_sz.x * device_scale.x); w_cell_sz.y = (int)round(w_cell_sz.y * device_scale.y); } if (autclc == 2) { w_cell_sz.x = (int)round(50.0f * device_scale.x); w_cell_sz.y = (int)round(50.0f * device_scale.y); } // end w_cells.y = xml_doc.ReadAttribInt(path, index, "rows_num"); w_cells.x = xml_doc.ReadAttribInt(path, index, "cols_num"); // Add by Zander if (cellmin == 1) { // Приоритет - необходимое число ячеек в указанном объеме int w_cell_sz_x = (int)trunc(width / _max((float)w_cells.x, 1.0f)); int w_cell_sz_y = (int)trunc(height / _max((float)w_cells.y, 1.0f)); if (w_cell_sz_x < w_cell_sz.x) w_cell_sz.x = w_cell_sz_x; if (w_cell_sz_y < w_cell_sz.y) w_cell_sz.y = w_cell_sz_y; } else { // Приоритет - правильный размер иконок и сетки if (autclc == 1) { // Заполняем сетку максимально w_cells.x = (int)trunc(width / _max((float)w_cell_sz.x, 1.0f)); w_cells.y = (int)trunc(height / _max((float)w_cell_sz.y, 1.0f)); } } // end w_cell_sp.x = xml_doc.ReadAttribInt(path, index, "cell_sp_x", 0); w_cell_sp.y = xml_doc.ReadAttribInt(path, index, "cell_sp_y", 0); pWnd->SetCellSize (w_cell_sz); pWnd->SetCellsSpacing (w_cell_sp); pWnd->SetStartCellsCapacity (w_cells); int tmp = xml_doc.ReadAttribInt(path, index, "unlimited", 0); pWnd->SetAutoGrow (tmp!=0); tmp = xml_doc.ReadAttribInt(path, index, "group_similar", 0); pWnd->SetGrouping (tmp!=0); tmp = xml_doc.ReadAttribInt(path, index, "custom_placement", 1); pWnd->SetCustomPlacement(tmp!=0); tmp = xml_doc.ReadAttribInt(path, index, "vertical_placement", 0); pWnd->SetVerticalPlacement(tmp != 0); tmp = xml_doc.ReadAttribInt(path, index, "show_grid", 1); pWnd->SetDrawGrid (tmp != 0); tmp = xml_doc.ReadAttribInt(path, index, "condition_progress_bar", 0); pWnd->SetConditionProgBarVisibility(tmp!=0); if (xr_strlen(path)) pWnd->SetWindowName (path, TRUE); return true; } В результате этой правки, движок начинает понимать в конфигах xml инвентаря, два новых атрибута в окнах с инвентарными сетками: autocalc (возможные значения - 0,1,2) - необходимость пересчитывать размер ячеек сетки и иконок. cell_minimals (возможные значения - 0,1) - необходимость во что бы то ни стало вместить указанное количество ячеек в заданные размеры окна. Если эти атрибуты в конфигах отсутствуют, или указано значение 0 - то поведение в точности такое же, как и раньше. Сетка/иконки выводятся в координатах 1024х768, в тех размерах и координатах, что указаны в xml. autocalc="1" - ячейки иконок примут размер в пикселах, указанный в xml, на мониторе конечного пользователя с учетом его разрешения. Т.е. если например у нас написано <dragdrop_bag cell_width="42" cell_height="42" autocalc="1"/> То 1 клетка сетки/иконок примет размер 42х42 пиксела на мониторе юзера. И не важно, какое у него разрешение, и насколько оно (не)похоже на то, что имели в виду составители xml конфига. Ненужные в данном вопросе атрибуты xml в этой строке опущены, но удалять их конечно не надо. autocalc="2" - для ленивых) Поведение то же, что и в предыдущем варианте, но подгонять сетку будет к размеру 50х50, игнорируя указания cell_width, cell_height. cell_minimals="1" - Это для слотов. Если указано 1, окно слота маленькое, и указанное число ячеек в нем не помещается, то размер ячейки дополнительно ужимается до того чтобы поместилось. Это все опять же на экране пользователя с учетом его разрешения. Ну и бонусом, если для окна инвентаря указать autocalc 1 или 2, и cell_minimals 0, то размер ячейки будет изменен с учетом разрешения монитора пользователя, а сетка инвентаря переформирована под то число ячеек, которое в нее поместится с учетом этого изменения. Игнорируя указанные в xml значения rows_num и cols_num. У себя проверил - работает... может быть, пригодится кому-то) 1 3 4 Мод, где не бывает одинаковых путей - Судьба Зоны. (Лучшее, что у меня получилось на X-Ray) На базе модифицированного движка OGSR Engine. Бывший мододел на X-Ray / Начинающий игродел на Unreal Engine. Программист. AMD Ryzen 9 7950X (16 ядер, 32 потока, 5.75 ГГц); RTX 3080; 128 ГБ DDR5; Arctic Liquid Freezer II-420; 3 ТБ SSD PCIe 4.0; 4ТБ HDD. Ссылка на комментарий
Zander_driver 10 319 Опубликовано 12 Января 2020 Поделиться Опубликовано 12 Января 2020 Подкину еще немножко своих правок, для движка OGSR Скрытый текст Описание: в качестве имен текстур, движок понимает в т.ч. секции конфига. В этом случае, в качестве текстуры будет использована иконка соответствующего предмета. xrGame/ui/uiTextureMaster.h // file: UITextureMaster.h // description: holds info about shared textures. able to initialize external // through IUITextureControl interface // created: 11.05.2005 // author: Serge Vynnychenko // mail: narrator@gsc-game.kiev.ua // // copyright 2005 GSC Game World #pragma once #include "ui_defs.h" class IUISimpleTextureControl; struct TEX_INFO{ shared_str file; Frect rect; LPCSTR get_file_name () {return *file;} Frect get_rect () {return rect;} }; class CUITextureMaster{ public: static void ParseShTexInfo (LPCSTR xml_file); static void ParseConfigIcon (LPCSTR section); static LPCSTR CheckName(LPCSTR texture_name); static void InitTexture (LPCSTR texture_name, IUISimpleTextureControl* tc); static void InitTexture (LPCSTR texture_name, const char* shader_name, IUISimpleTextureControl* tc); static float GetTextureHeight (LPCSTR texture_name); static float GetTextureWidth (LPCSTR texture_name); static Frect GetTextureRect (LPCSTR texture_name); static LPCSTR GetTextureFileName (LPCSTR texture_name); static void GetTextureShader (LPCSTR texture_name, ui_shader& sh); static TEX_INFO FindItem (LPCSTR texture_name, LPCSTR def_texture_name); static void WriteLog(); static bool CheckTextureExist (LPCSTR texture_name); protected: IC static bool IsSh (const char* texture_name); // typedef xr_string region_name; // typedef xr_string shader_name; // typedef xr_map<region_name, Frect> regions; // typedef xr_map<region_name, Frect>::iterator regions_it; // typedef xr_map<shader_name, regions> shared_textures; // typedef xr_map<shader_name, regions>::iterator shared_textures_it; static xr_map<shared_str, TEX_INFO> m_textures; // static shared_textures m_shTex; #ifdef DEBUG static u32 m_time; #endif }; xrGame/ui/uiTextureMaster.cpp // file: UITextureMaster.h // description: holds info about shared textures. able to initialize external controls // through IUITextureControl interface // created: 11.05.2005 // author: Serge Vynnychenko // mail: narrator@gsc-game.kiev.ua // // copyright 2005 GSC Game World #include "StdAfx.h" #include "UITextureMaster.h" #include "uiabstract.h" #include "xrUIXmlParser.h" xr_map<shared_str, TEX_INFO> CUITextureMaster::m_textures; #ifdef DEBUG u32 CUITextureMaster::m_time = 0; #endif void CUITextureMaster::WriteLog(){ #ifdef DEBUG Msg("UI texture manager work time is %d ms", m_time); #endif } void CUITextureMaster::ParseShTexInfo(LPCSTR xml_file){ CUIXml xml; xml.Init(CONFIG_PATH, UI_PATH, xml_file); shared_str file = xml.Read("file_name",0,""); // shared_textures_it sht_it = m_shTex.find(texture); // if (m_shTex.end() == sht_it) // { int num = xml.GetNodesNum("",0,"texture"); // regions regs; for (int i = 0; i<num; i++) { TEX_INFO info; info.file = file; info.rect.x1 = xml.ReadAttribFlt("texture",i,"x"); info.rect.x2 = xml.ReadAttribFlt("texture",i,"width") + info.rect.x1; info.rect.y1 = xml.ReadAttribFlt("texture",i,"y"); info.rect.y2 = xml.ReadAttribFlt("texture",i,"height") + info.rect.y1; shared_str id = xml.ReadAttrib("texture",i,"id"); m_textures.insert(mk_pair(id,info)); } // m_shTex.insert(mk_pair(texture, regs)); // } } LPCSTR CUITextureMaster::CheckName(const char* texture_name){ LPCSTR r; if (pSettings->section_exist(texture_name)) { shared_str subsection = pSettings->r_string(texture_name, "icon_section", texture_name); subsection = pSettings->r_string(subsection, "used_icon_texture", subsection.c_str()); r = subsection.c_str(); } else { r = texture_name; } if (!CheckTextureExist(r)) ParseConfigIcon(r); if (!CheckTextureExist(r)) r = texture_name; return r; } void CUITextureMaster::ParseConfigIcon(LPCSTR section){ if (pSettings->section_exist(section)) { shared_str subsection = pSettings->r_string(section, "icon_section", section); subsection = pSettings->r_string(subsection, "used_icon_texture", subsection); int place_id = pSettings->r_float(subsection, "icon_group", 0); TEX_INFO info; shared_str file = "ui\\ui_icon_equipment"; if (place_id != 0) file.sprintf("ui\\ui_icon_equipment_%u", place_id); info.file = file; info.rect.x1 = pSettings->r_float(subsection, "inv_grid_x", 0) * 50; info.rect.x2 = (pSettings->r_float(subsection, "inv_grid_width", 0) * 50) + info.rect.x1; info.rect.y1 = pSettings->r_float(subsection, "inv_grid_y", 0) * 50; info.rect.y2 = (pSettings->r_float(subsection, "inv_grid_height", 0) * 50) + info.rect.y1; //shared_str id = subsection; if (!CheckTextureExist(subsection.c_str())) m_textures.insert(mk_pair(subsection,info)); } } bool CUITextureMaster::IsSh(const char* texture_name){ return strstr(texture_name,"\\") ? false : true; } void CUITextureMaster::InitTexture(const char* texture_name, IUISimpleTextureControl* tc){ const char* ntn = CheckName(texture_name); #ifdef DEBUG CTimer T; T.Start(); #endif xr_map<shared_str, TEX_INFO>::iterator it; it = m_textures.find(ntn); if (it != m_textures.end()) { tc->CreateShader(*((*it).second.file)); tc->SetOriginalRectEx((*it).second.rect); #ifdef DEBUG m_time += T.GetElapsed_ms(); #endif return; } tc->CreateShader(ntn); #ifdef DEBUG m_time += T.GetElapsed_ms(); #endif } void CUITextureMaster::InitTexture(const char* texture_name, const char* shader_name, IUISimpleTextureControl* tc){ const char* ntn = CheckName(texture_name); #ifdef DEBUG CTimer T; T.Start(); #endif xr_map<shared_str, TEX_INFO>::iterator it; it = m_textures.find(ntn); if (it != m_textures.end()) { tc->CreateShader(*((*it).second.file), shader_name); tc->SetOriginalRectEx((*it).second.rect); #ifdef DEBUG m_time += T.GetElapsed_ms(); #endif return; } tc->CreateShader(ntn, shader_name); #ifdef DEBUG m_time += T.GetElapsed_ms(); #endif } float CUITextureMaster::GetTextureHeight(const char* texture_name){ const char* ntn = CheckName(texture_name); xr_map<shared_str, TEX_INFO>::iterator it; it = m_textures.find(ntn); if (it != m_textures.end()) return (*it).second.rect.height(); // KD: we don't need to die :) // R_ASSERT3(false,"CUITextureMaster::GetTextureHeight Can't find texture", texture_name); //ParseConfigIcon(texture_name); Msg("! CUITextureMaster::GetTextureHeight Can't find texture", texture_name); return 0; } bool CUITextureMaster::CheckTextureExist(const char* texture_name){ //const char* ntn = CheckName(texture_name); xr_map<shared_str, TEX_INFO>::iterator it; it = m_textures.find(texture_name); if (it != m_textures.end()) return true; // Zander: I want to know if such a texture exists in advance return false; } Frect CUITextureMaster::GetTextureRect(const char* texture_name){ const char* ntn = CheckName(texture_name); xr_map<shared_str, TEX_INFO>::iterator it; it = m_textures.find(ntn); if (it != m_textures.end()) return (*it).second.rect; // KD: we don't need to die :) // R_ASSERT3(false,"CUITextureMaster::GetTextureHeight Can't find texture", texture_name); //ParseConfigIcon(texture_name); Msg("! CUITextureMaster::GetTextureRect Can't find texture", texture_name); return Frect(); } float CUITextureMaster::GetTextureWidth(const char* texture_name){ const char* ntn = CheckName(texture_name); xr_map<shared_str, TEX_INFO>::iterator it; it = m_textures.find(ntn); if (it != m_textures.end()) return (*it).second.rect.width(); // KD: we don't need to die :) // R_ASSERT3(false,"CUITextureMaster::GetTextureHeight Can't find texture", texture_name); //ParseConfigIcon(texture_name); Msg("! CUITextureMaster::GetTextureWidth Can't find texture", texture_name); return 0; } LPCSTR CUITextureMaster::GetTextureFileName(const char* texture_name){ const char* ntn = CheckName(texture_name); xr_map<shared_str, TEX_INFO>::iterator it; it = m_textures.find(ntn); if (it != m_textures.end()) return *((*it).second.file); // KD: we don't need to die :) // R_ASSERT3(false,"CUITextureMaster::GetTextureHeight Can't find texture", texture_name); Msg("! CUITextureMaster::GetTextureFileName Can't find texture", texture_name); //ParseConfigIcon(texture_name); return 0; } TEX_INFO CUITextureMaster::FindItem(LPCSTR texture_name, LPCSTR def_texture_name) { const char* ntn = CheckName(texture_name); xr_map<shared_str, TEX_INFO>::iterator it; it = m_textures.find(ntn); if (it != m_textures.end()) return (it->second); else{ R_ASSERT2(m_textures.find(def_texture_name)!=m_textures.end(),ntn); return FindItem (def_texture_name,NULL); } } void CUITextureMaster::GetTextureShader(LPCSTR texture_name, ui_shader& sh){ const char* ntn = CheckName(texture_name); xr_map<shared_str, TEX_INFO>::iterator it; it = m_textures.find(ntn); // R_ASSERT3(it != m_textures.end(), "can't find texture", texture_name); if (it == m_textures.end()) Msg("! CUITextureMaster::GetTextureShader Can't find texture", texture_name); sh->create("hud\\default", *((*it).second.file)); } Скрытый текст Описание: Функции чтения данных из конфига, принимают значения по умолчанию, возвращаемые в случае если нет такой строки/секции. + Эта правка необходима для предыдущей. xrCore/xr_ini.h #pragma once class CInifile; struct xr_token; class XRCORE_API CInifile { public: using Item = std::pair<shared_str, shared_str>; struct XRCORE_API Sect { shared_str Name; string_unordered_map<shared_str, shared_str> Data; std::vector<Item> Unordered; BOOL line_exist ( LPCSTR, LPCSTR* = nullptr ); u32 line_count(); LPCSTR r_string( LPCSTR ); u32 r_u32( LPCSTR ); float r_float( LPCSTR ); Ivector2 r_ivector2( LPCSTR ); Fvector3 r_fvector3( LPCSTR ); }; using Root = string_unordered_map<shared_str, Sect*>; static_assert(std::is_same_v<Root::key_equal, string_hash::transparent_key_equal>, "Invalid key_equal"); //Нужная проверка в будущем, не убирать! // factorisation static CInifile* Create ( LPCSTR, BOOL = TRUE ); static void Destroy ( CInifile* ); static IC BOOL IsBOOL ( LPCSTR B ) { return ( xr_strcmp( B, "on" ) == 0 || xr_strcmp( B, "yes" ) == 0 || xr_strcmp( B, "true" ) == 0 || xr_strcmp( B, "1" ) == 0 ); } private: LPSTR fName; Root DATA; void Load ( IReader*, LPCSTR ); public: bool bReadOnly; BOOL bSaveAtEnd; public: CInifile ( IReader*, LPCSTR = 0 ); CInifile ( LPCSTR, BOOL = TRUE, BOOL = TRUE, BOOL = TRUE ); virtual ~CInifile (); bool save_as ( LPCSTR = 0 ); std::string get_as_string(); LPCSTR fname () { return fName; }; Sect& r_section ( LPCSTR ); Sect& r_section ( const shared_str& ); BOOL line_exist ( LPCSTR, LPCSTR ); BOOL line_exist ( const shared_str&, const shared_str& ); u32 line_count ( LPCSTR ); u32 line_count ( const shared_str& ); BOOL section_exist ( LPCSTR ); BOOL section_exist ( const shared_str& ); Root& sections () { return DATA; } const Root& sections () const { return DATA; } CLASS_ID r_clsid ( LPCSTR, LPCSTR ); CLASS_ID r_clsid ( const shared_str& S, LPCSTR L ) { return r_clsid( S.c_str(), L ); } LPCSTR r_string ( LPCSTR, LPCSTR ); // оставляет кавычки LPCSTR r_string ( const shared_str& S, LPCSTR L ) { return r_string( S.c_str(), L ); } // оставляет кавычки shared_str r_string_wb ( LPCSTR, LPCSTR ); // убирает кавычки shared_str r_string_wb ( const shared_str& S, LPCSTR L ) { return r_string_wb( S.c_str(), L ); } // убирает кавычки shared_str r_string( LPCSTR, LPCSTR, shared_str ); LPCSTR r_string( LPCSTR, LPCSTR, LPCSTR ); LPCSTR r_string ( const shared_str& S, LPCSTR L, LPCSTR Defstr ) { return r_string( S.c_str(), L, Defstr ); } LPCSTR r_string ( const shared_str& S, LPCSTR L, shared_str Defstr ) { return r_string( S.c_str(), L, Defstr.c_str() ); } u8 r_u8 ( LPCSTR, LPCSTR ); u8 r_u8 ( const shared_str& S, LPCSTR L ) { return r_u8( S.c_str(), L ); } u16 r_u16 ( LPCSTR, LPCSTR ); u16 r_u16 ( const shared_str& S, LPCSTR L ) { return r_u16( S.c_str(), L ); } u32 r_u32 ( LPCSTR, LPCSTR ); u32 r_u32 ( const shared_str& S, LPCSTR L ) { return r_u32( S.c_str(), L ); } s8 r_s8 ( LPCSTR, LPCSTR ); s8 r_s8 ( const shared_str& S, LPCSTR L ) { return r_s8( S.c_str(), L ); } s16 r_s16 ( LPCSTR, LPCSTR ); s16 r_s16 ( const shared_str& S, LPCSTR L ) { return r_s16( S.c_str(), L ); } s32 r_s32 ( LPCSTR, LPCSTR ); s32 r_s32 ( const shared_str& S, LPCSTR L ) { return r_s32( S.c_str(), L ); } float r_float ( LPCSTR, LPCSTR ); float r_float ( const shared_str& S, LPCSTR L ) { return r_float( S.c_str(), L ); } float r_float ( LPCSTR, LPCSTR, float ); float r_float ( const shared_str& S, LPCSTR L, float Defval ) { return r_float( S.c_str(), L, Defval ); } Fcolor r_fcolor ( LPCSTR, LPCSTR ); Fcolor r_fcolor ( const shared_str& S, LPCSTR L ) { return r_fcolor( S.c_str(), L ); } u32 r_color ( LPCSTR, LPCSTR ); u32 r_color ( const shared_str& S, LPCSTR L ) { return r_color( S.c_str(), L ); } Ivector2 r_ivector2 ( LPCSTR, LPCSTR ); Ivector2 r_ivector2 ( const shared_str& S, LPCSTR L ) { return r_ivector2( S.c_str(), L ); } Ivector3 r_ivector3 ( LPCSTR, LPCSTR ); Ivector3 r_ivector3 ( const shared_str& S, LPCSTR L ) { return r_ivector3( S.c_str(), L ); } Ivector4 r_ivector4 ( LPCSTR, LPCSTR ); Ivector4 r_ivector4 ( const shared_str& S, LPCSTR L ) { return r_ivector4( S.c_str(), L ); } Fvector2 r_fvector2 ( LPCSTR, LPCSTR ); Fvector2 r_fvector2 ( const shared_str& S, LPCSTR L ) { return r_fvector2( S.c_str(), L ); } Fvector3 r_fvector3 ( LPCSTR, LPCSTR ); Fvector3 r_fvector3 ( const shared_str& S, LPCSTR L ) { return r_fvector3( S.c_str(), L ); } Fvector4 r_fvector4 ( LPCSTR, LPCSTR ); Fvector4 r_fvector4 ( const shared_str& S, LPCSTR L ) { return r_fvector4( S.c_str(), L ); } // Add by Zander Fvector2 r_fvec2 ( LPCSTR, LPCSTR, LPCSTR, u8 ); Fvector2 r_fvec2 ( const shared_str& S, LPCSTR L, LPCSTR K, u8 I ) { return r_fvec2( S.c_str(), L, K, I ); } Fvector3 r_fvec3 ( LPCSTR, LPCSTR, LPCSTR, LPCSTR, u8 ); Fvector3 r_fvec3 ( const shared_str& S, LPCSTR L, LPCSTR K, LPCSTR M, u8 I ) { return r_fvec3( S.c_str(), L, K, M, I ); } Fvector4 r_fvec4 ( LPCSTR, LPCSTR, LPCSTR, LPCSTR, LPCSTR, u8 ); Fvector4 r_fvec4 ( const shared_str& S, LPCSTR L, LPCSTR K, LPCSTR M, LPCSTR N, u8 I ) { return r_fvec4( S.c_str(), L, K, M, N, I ); } // end add BOOL r_bool ( LPCSTR, LPCSTR ); BOOL r_bool ( const shared_str& S, LPCSTR L ) { return r_bool( S.c_str(), L ); } int r_token ( LPCSTR, LPCSTR, const xr_token *token_list ); BOOL r_line ( LPCSTR, int, LPCSTR*, LPCSTR* ); BOOL r_line ( const shared_str&, int, LPCSTR*, LPCSTR* ); void w_string ( LPCSTR, LPCSTR, LPCSTR ); void w_u8 ( LPCSTR, LPCSTR, u8 ); void w_u16 ( LPCSTR, LPCSTR, u16 ); void w_u32 ( LPCSTR, LPCSTR, u32 ); void w_s8 ( LPCSTR, LPCSTR, s8 ); void w_s16 ( LPCSTR, LPCSTR, s16 ); void w_s32 ( LPCSTR, LPCSTR, s32 ); void w_float ( LPCSTR, LPCSTR, float ); void w_fcolor ( LPCSTR, LPCSTR, const Fcolor& ); void w_color ( LPCSTR, LPCSTR, u32 ); void w_ivector2 ( LPCSTR, LPCSTR, const Ivector2& ); void w_ivector3 ( LPCSTR, LPCSTR, const Ivector3& ); void w_ivector4 ( LPCSTR, LPCSTR, const Ivector4& ); void w_fvector2 ( LPCSTR, LPCSTR, const Fvector2& ); void w_fvector3 ( LPCSTR, LPCSTR, const Fvector3& ); void w_fvector4 ( LPCSTR, LPCSTR, const Fvector4& ); void w_bool ( LPCSTR, LPCSTR, bool ); void remove_line ( LPCSTR, LPCSTR ); void remove_section( LPCSTR ); }; // Main configuration file extern XRCORE_API CInifile *pSettings; xrCore/xr_ini.cpp #include "stdafx.h" #include "fs_internal.h" XRCORE_API CInifile *pSettings = nullptr; CInifile* CInifile::Create( const char* szFileName, BOOL ReadOnly ) { return xr_new<CInifile>( szFileName, ReadOnly ); } void CInifile::Destroy( CInifile* ini ) { xr_delete( ini ); } //Тело функций Inifile XRCORE_API void _parse( LPSTR dest, LPCSTR src ) { if ( src ) { bool bInsideSTR = false; while ( *src ) { if ( isspace( (u8)*src ) ) { if ( bInsideSTR ) { *dest++ = *src++; continue; } while ( *src && iswspace( *src ) ) src++; continue; } else if ( *src == '"' ) { bInsideSTR = !bInsideSTR; } *dest++ = *src++; } } *dest = 0; } XRCORE_API void _decorate( LPSTR dest, LPCSTR src ) { if (src) { bool bInsideSTR = false; while ( *src ) { if ( *src == ',' ) { if ( bInsideSTR ) *dest++ = *src++; else { *dest++ = *src++; *dest++ = ' '; } continue; } else if ( *src=='"' ) { bInsideSTR = !bInsideSTR; } *dest++ = *src++; } } *dest = 0; } BOOL CInifile::Sect::line_exist( LPCSTR L, LPCSTR* val ) { shared_str s( L ); const auto A = Data.find( s ); if (A != Data.end() ){ if ( val ) *val = *A->second; return TRUE; } return FALSE; } LPCSTR CInifile::Sect::r_string( LPCSTR L ) { if (!L || !strlen(L)) //--#SM+#-- [fix for one of "xrDebug - Invalid handler" error log] Msg("!![ERROR] CInifile::Sect::r_string: S = [%s], L = [%s]", Name.c_str(), L); shared_str k(L); const auto A = Data.find(k); if (A != Data.end()) return A->second.c_str(); else FATAL("Can't find variable %s in [%s]", L, Name.c_str()); return 0; } float CInifile::Sect::r_float( LPCSTR L ) { LPCSTR C = r_string(L); return float(atof(C)); } u32 CInifile::Sect::r_u32( LPCSTR L ) { LPCSTR C = r_string(L); return u32(atoi(C)); } Fvector3 CInifile::Sect::r_fvector3( LPCSTR L ) { LPCSTR C = r_string(L); Fvector3 V = { 0.f, 0.f, 0.f }; sscanf(C, "%f,%f,%f", &V.x, &V.y, &V.z); return V; } Ivector2 CInifile::Sect::r_ivector2( LPCSTR L ) { LPCSTR C = r_string(L); Ivector2 V = { 0, 0 }; sscanf(C, "%d,%d", &V.x, &V.y); return V; } u32 CInifile::Sect::line_count() { return u32( Data.size() ); } CInifile::CInifile( IReader* F, LPCSTR path ) { fName = 0; bReadOnly = true; bSaveAtEnd = FALSE; Load( F, path ); } CInifile::CInifile( LPCSTR szFileName, BOOL ReadOnly, BOOL bLoad, BOOL SaveAtEnd ) { fName = szFileName ? xr_strdup( szFileName ) : 0; bReadOnly = !!ReadOnly; bSaveAtEnd = SaveAtEnd; if ( bLoad ) { string_path path, folder; _splitpath( fName, path, folder, 0, 0 ); strcat( path, folder ); IReader* R = FS.r_open( szFileName ); if ( R ) { Load( R, path ); FS.r_close( R ); } } } CInifile::~CInifile() { if ( !bReadOnly && bSaveAtEnd ) { if ( !save_as() ) Log( "!Can't save inifile:", fName ); } xr_free( fName ); for ( auto &I : DATA ) xr_delete( I.second ); } static void insert_item( CInifile::Sect *tgt, const CInifile::Item& I ) { auto sect_it = tgt->Data.find( I.first ); if ( sect_it != tgt->Data.end() && sect_it->first.equal( I.first ) ) { sect_it->second = I.second; auto found = std::find_if( tgt->Unordered.begin(), tgt->Unordered.end(), [&]( const auto &it ) { return xr_strcmp( *it.first, *I.first ) == 0; } ); if ( found != tgt->Unordered.end() ) { found->second = I.second; } } else { tgt->Data.insert({ I.first, I.second }); tgt->Unordered.push_back( I ); } } void CInifile::Load ( IReader* F, LPCSTR path ) { R_ASSERT( F ); Sect *Current = nullptr; string4096 str; string4096 str2; while ( !F->eof() ) { F->r_string( str, sizeof( str ) ); _Trim( str ); LPSTR semi = strchr( str, ';' ); LPSTR semi_1 = strchr( str, '/' ); if ( semi_1 && ( *(semi_1 + 1) == '/' ) && ( (!semi) || ( semi && ( semi_1 < semi ) ) ) ) semi = semi_1; if ( semi ) *semi = 0; if ( str[ 0 ] && ( str[ 0 ] == '#' ) && strstr( str, "#include" ) ) { string64 inc_name; R_ASSERT( path && path[ 0 ] ); if ( _GetItem( str, 1, inc_name, '"' ) ) { string_path fn, inc_path, folder; strconcat( sizeof( fn ), fn, path, inc_name ); _splitpath( fn, inc_path, folder, 0, 0 ); strcat( inc_path, folder ); IReader* I = FS.r_open( fn ); R_ASSERT3( I, "Can't find include file:", inc_name ); Load( I, inc_path ); FS.r_close( I ); } } else if ( str[ 0 ] && ( str[ 0 ] == '[' ) ) { // insert previous filled section if ( Current ) { auto I = DATA.find( Current->Name ); if ( I != DATA.end() ) FATAL( "Duplicate section '%s' found.", Current->Name.c_str() ); DATA.insert({ Current->Name, Current }); } Current = xr_new<Sect>(); Current->Name = 0; // start new section R_ASSERT3( strchr( str, ']' ), "Bad ini section found: ", str ); LPCSTR inherited_names = strstr( str, "]:" ); if ( 0 != inherited_names ) { VERIFY2( bReadOnly, "Allow for readonly mode only." ); inherited_names += 2; int cnt = _GetItemCount( inherited_names ); for ( int k = 0; k < cnt; ++k ) { xr_string tmp; _GetItem( inherited_names, k, tmp ); Sect& inherited = r_section( tmp.c_str() ); for ( auto &it : inherited.Data ) { Item I = { it.first, it.second }; insert_item( Current, I ); } } } *strchr( str, ']' ) = 0; Current->Name = strlwr( str + 1 ); } else { if ( Current ) { char* name = str; char* t = strchr( name, '=' ); if ( t ) { *t = 0; _Trim( name ); _parse( str2, ++t ); } else { _Trim( name ); str2[ 0 ] = 0; } if ( name[ 0 ] ) { Item I; I.first = name; I.second = str2[ 0 ] ? str2 : 0; if ( bReadOnly ) { if ( *I.first ) insert_item( Current, I ); } else { if ( *I.first || *I.second ) insert_item( Current, I ); } } } } } if ( Current ) { auto I = DATA.find( Current->Name ); if ( I != DATA.end() ) FATAL( "Duplicate section '%s' found.", Current->Name.c_str() ); DATA.insert({ Current->Name, Current }); } } bool CInifile::save_as( LPCSTR new_fname ) { // save if needed if ( new_fname && new_fname[ 0 ] ) { xr_free( fName ); fName = xr_strdup( new_fname ); } R_ASSERT( fName && fName[ 0 ] ); IWriter* F = FS.w_open_ex( fName ); if ( F ) { string512 temp, val; for ( const auto &r_it : DATA ) { sprintf_s( temp, sizeof( temp ), "[%s]", r_it.first.c_str() ); F->w_string( temp ); for ( const auto &I : r_it.second->Unordered ) { if ( *I.first ) { if ( *I.second ) { _decorate( val, *I.second ); { // only name and value sprintf_s( temp, sizeof( temp ), "%8s%-32s = %-32s", " ", *I.first, val ); } } else { { // only name sprintf_s( temp, sizeof( temp ), "%8s%-32s = ", " ", *I.first ); } } } else { // no name, so no value temp[ 0 ] = 0; } _TrimRight( temp ); if ( temp[ 0 ] ) F->w_string( temp ); } F->w_string( " " ); } FS.w_close( F ); return true; } return false; } BOOL CInifile::section_exist( LPCSTR S ) { shared_str k( S ); const auto I = DATA.find( k ); return I != DATA.end(); } BOOL CInifile::line_exist( LPCSTR S, LPCSTR L ) { if ( !section_exist( S ) ) return FALSE; Sect& I = r_section( S ); shared_str k( L ); const auto A = I.Data.find( k ); return A != I.Data.end(); } u32 CInifile::line_count( LPCSTR Sname ) { Sect& S = r_section( Sname ); return S.line_count(); } CInifile::Sect& CInifile::r_section ( const shared_str& S ) { return r_section( S.c_str() ); } BOOL CInifile::line_exist ( const shared_str& S, const shared_str& L ) { return line_exist( S.c_str(), L.c_str() ); } u32 CInifile::line_count ( const shared_str& S ) { return line_count( S.c_str() ); } BOOL CInifile::section_exist ( const shared_str& S ) { return section_exist( S.c_str() ); } CInifile::Sect& CInifile::r_section( LPCSTR S ) { R_ASSERT( S && strlen( S ), "Empty section (null\\'') passed into CInifile::r_section(). See info above ^, check your configs and 'call stack'." ); //--#SM+#-- char section[ 256 ]; strcpy_s( section, sizeof( section ), S ); shared_str k = strlwr( section ); const auto I = DATA.find( k ); if ( I == DATA.end() ) FATAL( "Can't open section '%s'", S ); return *I->second; } LPCSTR CInifile::r_string ( LPCSTR S, LPCSTR L ) { if ( !S || !L || !strlen( S ) || !strlen( L ) ) //--#SM+#-- [fix for one of "xrDebug - Invalid handler" error log] Msg( "!![ERROR] CInifile::r_string: S = [%s], L = [%s]", S, L ); Sect& I = r_section( S ); shared_str k( L ); const auto A = I.Data.find( k ); if ( A != I.Data.end() ) return A->second.c_str(); else FATAL( "Can't find variable %s in [%s]", L, S ); return 0; } shared_str CInifile::r_string ( LPCSTR S, LPCSTR L, shared_str Defstr ) { if ( !S || !L || !strlen( S ) || !strlen( L ) ) //--#SM+#-- [fix for one of "xrDebug - Invalid handler" error log] Msg( "!![ERROR] CInifile::r_string: S = [%s], L = [%s]", S, L ); Sect& I = r_section( S ); shared_str k( L ); const auto A = I.Data.find( k ); if ( A != I.Data.end() ) return A->second.c_str(); else return Defstr; } LPCSTR CInifile::r_string ( LPCSTR S, LPCSTR L, LPCSTR Defstr ) { if ( !S || !L || !strlen( S ) || !strlen( L ) ) //--#SM+#-- [fix for one of "xrDebug - Invalid handler" error log] Msg( "!![ERROR] CInifile::r_string: S = [%s], L = [%s]", S, L ); Sect& I = r_section( S ); shared_str k( L ); const auto A = I.Data.find( k ); if ( A != I.Data.end() ) return A->second.c_str(); else return Defstr; } shared_str CInifile::r_string_wb( LPCSTR S, LPCSTR L ) { LPCSTR _base = r_string( S, L ); if ( 0 == _base ) return shared_str( 0 ); string512 _original; strcpy_s( _original, _base ); u32 _len = xr_strlen( _original ); if ( 0 == _len ) return shared_str( "" ); if ( '"' == _original[ _len - 1 ] ) _original[ _len - 1 ] = 0; // skip end if ( '"' == _original[ 0 ] ) return shared_str( &_original[ 0 ] + 1 ); // skip begin return shared_str( _original ); } u8 CInifile::r_u8 ( LPCSTR S, LPCSTR L ) { LPCSTR C = r_string( S, L ); return u8( atoi( C ) ); } u16 CInifile::r_u16 ( LPCSTR S, LPCSTR L ) { LPCSTR C = r_string( S, L ); return u16( atoi( C ) ); } u32 CInifile::r_u32 ( LPCSTR S, LPCSTR L ) { LPCSTR C = r_string( S, L ); return u32( atoi( C ) ); } s8 CInifile::r_s8 ( LPCSTR S, LPCSTR L ) { LPCSTR C = r_string( S, L ); return s8( atoi( C ) ); } s16 CInifile::r_s16 ( LPCSTR S, LPCSTR L ) { LPCSTR C = r_string( S, L ); return s16( atoi( C ) ); } s32 CInifile::r_s32 ( LPCSTR S, LPCSTR L ) { LPCSTR C = r_string( S, L ); return s32( atoi( C ) ); } float CInifile::r_float ( LPCSTR S, LPCSTR L ) { LPCSTR C = r_string( S, L ); return float( atof( C ) ); } float CInifile::r_float ( LPCSTR S, LPCSTR L, float Defval ) { if(!line_exist( S, L )) return Defval; LPCSTR C = r_string( S, L); return float( atof( C ) ); } Fcolor CInifile::r_fcolor ( LPCSTR S, LPCSTR L ) { LPCSTR C = r_string( S, L ); Fcolor V = { 0, 0, 0, 0 }; sscanf( C, "%f,%f,%f,%f", &V.r, &V.g, &V.b, &V.a ); return V; } u32 CInifile::r_color ( LPCSTR S, LPCSTR L ) { LPCSTR C = r_string( S, L ); u32 r = 0, g = 0, b = 0, a = 255; sscanf( C, "%d,%d,%d,%d", &r, &g, &b, &a ); return color_rgba( r, g, b, a ); } Ivector2 CInifile::r_ivector2 ( LPCSTR S, LPCSTR L ) { LPCSTR C = r_string( S, L ); Ivector2 V = { 0, 0 }; sscanf( C, "%d,%d", &V.x, &V.y ); return V; } Ivector3 CInifile::r_ivector3 ( LPCSTR S, LPCSTR L ) { LPCSTR C = r_string( S, L ); Ivector V = { 0, 0, 0 }; sscanf( C, "%d,%d,%d", &V.x, &V.y, &V.z ); return V; } Ivector4 CInifile::r_ivector4 ( LPCSTR S, LPCSTR L ) { LPCSTR C = r_string( S, L ); Ivector4 V = { 0, 0, 0, 0 }; sscanf( C, "%d,%d,%d,%d", &V.x, &V.y, &V.z, &V.w ); return V; } Fvector2 CInifile::r_fvector2 ( LPCSTR S, LPCSTR L ) { LPCSTR C = r_string( S, L ); Fvector2 V = { 0.f, 0.f }; sscanf( C, "%f,%f", &V.x, &V.y ); return V; } Fvector3 CInifile::r_fvector3 ( LPCSTR S, LPCSTR L ) { LPCSTR C = r_string( S, L ); Fvector3 V = { 0.f, 0.f, 0.f }; sscanf( C, "%f,%f,%f", &V.x, &V.y, &V.z ); return V; } Fvector4 CInifile::r_fvector4 ( LPCSTR S, LPCSTR L ) { LPCSTR C = r_string( S, L ); Fvector4 V = { 0.f, 0.f, 0.f, 0.f }; sscanf( C, "%f,%f,%f,%f", &V.x, &V.y, &V.z, &V.w ); return V; } // Add by Zander Fvector2 CInifile::r_fvec2 ( LPCSTR S, LPCSTR L, LPCSTR K, u8 I ) { Msg("CInifile::r_fvec2 [%s], [%s], [%s], [%f]", S, L, K, I); LPCSTR C1 = r_string( S, L, "0.0" ); LPCSTR C2 = r_string( S, K, "0.0" ); string128 a; float f = 0.f; shared_str tl; Fvector2 V = { 0.f, 0.f }; if (_GetItemCount( C1 ) > I) { f = float(atof(_GetItem(C1, I, a, ',', "0.0", true))); tl = shared_str(_GetItem(C1, I, a, ',', "0.0", true)); sscanf(tl.c_str(), "%f", &V.x); } else { f = 0.f; V.x = 0.f; } Msg("CInifile::r_fvec2 549 [%f], [%s]", f, tl.c_str()); if (_GetItemCount( C2 ) > I) { f = float(atof(_GetItem(C2, I, a, ',', "0.0", true))); tl = shared_str(_GetItem(C2, I, a, ',', "0.0", true)); sscanf(tl.c_str(), "%f", &V.y); } else { f = 0.f; V.y = 0.f; } Msg("CInifile::r_fvec2 556 [%f], [%s]", f, tl.c_str()); Msg("Return: V.x[%f], V.y[%f]", V.x, V.y); return V; } Fvector3 CInifile::r_fvec3 ( LPCSTR S, LPCSTR L, LPCSTR K, LPCSTR M, u8 I ) { Msg("CInifile::r_fvec3 [%s], [%s], [%s], [%s], [%f]", S, L, K, M, I); LPCSTR C1 = r_string( S, L, "0.0" ); LPCSTR C2 = r_string( S, K, "0.0" ); LPCSTR C3 = r_string( S, M, "0.0" ); string128 a; float f = 0.f; shared_str tl; Fvector3 V = { 0.f, 0.f, 0.f }; if (_GetItemCount( C1 ) > I) { f = float(atof(_GetItem(C1, I, a, ',', "0.0", true))); tl = shared_str(_GetItem(C1, I, a, ',', "0.0", true)); sscanf(tl.c_str(), "%f", &V.x); } else { f = 0.f; V.x = 0.f; } Msg("CInifile::r_fvec3 577 [%f], [%s]", f, tl.c_str()); if (_GetItemCount( C2 ) > I) { f = float(atof(_GetItem(C2, I, a, ',', "0.0", true))); tl = shared_str(_GetItem(C2, I, a, ',', "0.0", true)); sscanf(tl.c_str(), "%f", &V.y); } else { f = 0.f; V.y = 0.f; } Msg("CInifile::r_fvec3 584 [%f], [%s]", f, tl.c_str()); if (_GetItemCount( C3 ) > I) { f = float(atof(_GetItem(C3, I, a, ',', "0.0", true))); tl = shared_str(_GetItem(C3, I, a, ',', "0.0", true)); sscanf(tl.c_str(), "%f", &V.z); } else { f = 0.f; V.z = 0.f; } Msg("CInifile::r_fvec3 591 [%f], [%s]", f, tl.c_str()); Msg("Return: V.x[%f], V.y[%f], V.z[%f]", V.x, V.y, V.z); return V; } Fvector4 CInifile::r_fvec4 ( LPCSTR S, LPCSTR L, LPCSTR K, LPCSTR M, LPCSTR N, u8 I ) { Msg("CInifile::r_fvec4 [%s], [%s], [%s], [%s], [%s], [%f]", S, L, K, M, N, I); LPCSTR C1 = r_string( S, L, "0.0" ); LPCSTR C2 = r_string( S, K, "0.0" ); LPCSTR C3 = r_string( S, M, "0.0" ); LPCSTR C4 = r_string( S, N, "0.0" ); string128 a; float f = 0.f; shared_str tl; Fvector4 V = { 0.f, 0.f, 0.f, 0.f }; if (_GetItemCount( C1 ) > I) { f = float(atof(_GetItem(C1, I, a, ',', "0.0", true))); tl = shared_str(_GetItem(C1, I, a, ',', "0.0", true)); sscanf(tl.c_str(), "%f", &V.x); } else { f = 0.f; V.x = 0.f; } Msg("CInifile::r_fvec4 613 [%f], [%s]", f, tl.c_str()); if (_GetItemCount( C2 ) > I) { f = float(atof(_GetItem(C2, I, a, ',', "0.0", true))); tl = shared_str(_GetItem(C2, I, a, ',', "0.0", true)); sscanf(tl.c_str(), "%f", &V.y); } else { f = 0.f; V.y = 0.f; } Msg("CInifile::r_fvec4 620 [%f], [%s]", f, tl.c_str()); if (_GetItemCount( C3 ) > I) { f = float(atof(_GetItem(C3, I, a, ',', "0.0", true))); tl = shared_str(_GetItem(C3, I, a, ',', "0.0", true)); sscanf(tl.c_str(), "%f", &V.z); } else { f = 0.f; V.z = 0.f; } Msg("CInifile::r_fvec4 627 [%f], [%s]", f, tl.c_str()); if (_GetItemCount( C4 ) > I) { f = float(atof(_GetItem(C4, I, a, ',', "0.0", true))); tl = shared_str(_GetItem(C4, I, a, ',', "0.0", true)); sscanf(tl.c_str(), "%f", &V.w); } else { f = 0.f; V.w = 0.f; } Msg("CInifile::r_fvec4 634 [%f], [%s]", f, tl.c_str()); Msg("Return: V.x[%f], V.y[%f], V.z[%f], V.w[%f]", V.x, V.y, V.z, V.w); return V; } // end add BOOL CInifile::r_bool ( LPCSTR S, LPCSTR L ) { LPCSTR C = r_string( S, L ); char B[ 8 ]; strncpy( B, C, 7 ); strlwr( B ); return IsBOOL( B ); } CLASS_ID CInifile::r_clsid ( LPCSTR S, LPCSTR L) { LPCSTR C = r_string( S, L ); return TEXT2CLSID( C ); } int CInifile::r_token ( LPCSTR S, LPCSTR L, const xr_token *token_list ) { LPCSTR C = r_string( S, L ); for( int i = 0; token_list[ i ].name; i++ ) if( !stricmp( C, token_list[ i ].name ) ) return token_list[ i ].id; return 0; } BOOL CInifile::r_line( LPCSTR S, int L, const char** N, const char** V ) { Sect& SS = r_section( S ); if ( L >= (int)SS.Unordered.size() || L < 0 ) return FALSE; const auto &I = SS.Unordered.at( L ); *N = I.first.c_str(); *V = I.second.c_str(); return TRUE; } BOOL CInifile::r_line( const shared_str& S, int L, const char** N, const char** V ) { return r_line( S.c_str(), L, N, V ); } void CInifile::w_string ( LPCSTR S, LPCSTR L, LPCSTR V ) { R_ASSERT( !bReadOnly ); // section char sect[ 256 ]; _parse( sect, S ); _strlwr( sect ); ASSERT_FMT( sect[ 0 ], "[%s]: wrong section name [%s]", __FUNCTION__, S ); if ( !section_exist( sect ) ) { // create _new_ section Sect *NEW = xr_new<Sect>(); NEW->Name = sect; DATA.insert({ NEW->Name, NEW }); } // parse line/value char line [ 256 ]; _parse( line, L ); ASSERT_FMT( line[ 0 ], "[%s]: wrong param name [%s]", __FUNCTION__, L ); char value[ 256 ]; _parse( value, V ); // duplicate & insert Item I; I.first = line; I.second = value[ 0 ] ? value : 0; Sect* data = &r_section( sect ); insert_item( data, I ); } void CInifile::w_u8 ( LPCSTR S, LPCSTR L, u8 V ) { string128 temp; sprintf_s( temp, sizeof( temp ), "%d", V ); w_string( S, L, temp ); } void CInifile::w_u16 ( LPCSTR S, LPCSTR L, u16 V ) { string128 temp; sprintf_s( temp, sizeof( temp ), "%d", V ); w_string( S, L, temp ); } void CInifile::w_u32( LPCSTR S, LPCSTR L, u32 V ) { string128 temp; sprintf_s( temp, sizeof( temp ), "%d", V ); w_string( S, L, temp ); } void CInifile::w_s8 ( LPCSTR S, LPCSTR L, s8 V ) { string128 temp; sprintf_s( temp, sizeof( temp ), "%d", V ); w_string( S, L, temp ); } void CInifile::w_s16 ( LPCSTR S, LPCSTR L, s16 V ) { string128 temp; sprintf_s( temp, sizeof( temp ), "%d", V ); w_string( S, L, temp ); } void CInifile::w_s32 ( LPCSTR S, LPCSTR L, s32 V ) { string128 temp; sprintf_s( temp, sizeof( temp ), "%d", V ); w_string( S, L, temp); } void CInifile::w_float ( LPCSTR S, LPCSTR L, float V ) { string128 temp; sprintf_s( temp, sizeof( temp ), "%f", V ); w_string( S, L, temp ); } void CInifile::w_fcolor ( LPCSTR S, LPCSTR L, const Fcolor& V ) { string128 temp; sprintf_s( temp, sizeof( temp ), "%f,%f,%f,%f", V.r, V.g, V.b, V.a ); w_string( S, L, temp ); } void CInifile::w_color ( LPCSTR S, LPCSTR L, u32 V ) { string128 temp; sprintf_s( temp, sizeof( temp ), "%d,%d,%d,%d", color_get_R( V ), color_get_G( V ), color_get_B( V ), color_get_A( V ) ); w_string( S, L, temp ); } void CInifile::w_ivector2 ( LPCSTR S, LPCSTR L, const Ivector2& V ) { string128 temp; sprintf_s( temp, sizeof( temp ), "%d,%d", V.x, V.y ); w_string( S, L, temp ); } void CInifile::w_ivector3 ( LPCSTR S, LPCSTR L, const Ivector3& V ) { string128 temp; sprintf_s( temp, sizeof( temp ), "%d,%d,%d", V.x, V.y, V.z ); w_string( S, L, temp ); } void CInifile::w_ivector4 ( LPCSTR S, LPCSTR L, const Ivector4& V ) { string128 temp; sprintf_s( temp, sizeof( temp ), "%d,%d,%d,%d", V.x, V.y, V.z, V.w ); w_string( S, L, temp ); } void CInifile::w_fvector2 ( LPCSTR S, LPCSTR L, const Fvector2& V ) { string128 temp; sprintf_s( temp, sizeof( temp ), "%f,%f", V.x, V.y ); w_string( S, L, temp ); } void CInifile::w_fvector3 ( LPCSTR S, LPCSTR L, const Fvector3& V ) { string128 temp; sprintf_s( temp, sizeof( temp ), "%f,%f,%f", V.x, V.y, V.z ); w_string( S, L, temp ); } void CInifile::w_fvector4 ( LPCSTR S, LPCSTR L, const Fvector4& V ) { string128 temp; sprintf_s( temp, sizeof( temp ), "%f,%f,%f,%f", V.x, V.y, V.z, V.w ); w_string( S, L, temp ); } void CInifile::w_bool ( LPCSTR S, LPCSTR L, bool V ) { w_string( S, L, V ? "true" : "false" ); } void CInifile::remove_line( LPCSTR S, LPCSTR L ) { R_ASSERT( !bReadOnly ); if ( line_exist( S, L ) ) { Sect& data = r_section( S ); shared_str k( L ); auto A = data.Data.find( k ); R_ASSERT( A != data.Data.end() ); data.Data.erase( A ); auto found = std::find_if( data.Unordered.begin(), data.Unordered.end(), [&]( const auto& it ) { return xr_strcmp( *it.first, L ) == 0; } ); R_ASSERT( found != data.Unordered.end() ); data.Unordered.erase( found ); } } void CInifile::remove_section( LPCSTR S ) { R_ASSERT( !bReadOnly ); if ( section_exist( S ) ) { shared_str k( S ); const auto I = DATA.find( k ); R_ASSERT( I != DATA.end() ); DATA.erase( I ); } } #include <sstream> std::string CInifile::get_as_string() { std::stringstream str; bool first_sect = true; for ( const auto &r_it : DATA ) { if ( !first_sect ) str << "\r\n"; first_sect = false; str << "[" << r_it.first.c_str() << "]\r\n"; for ( const auto &I : r_it.second->Unordered ) { if ( I.first.c_str() ) { if ( I.second.c_str() ) { string512 val; _decorate( val, I.second.c_str() ); _TrimRight( val ); // only name and value str << I.first.c_str() << " = " << val << "\r\n"; } else { // only name str << I.first.c_str() << " =\r\n"; } } } } return str.str(); } 1 2 Мод, где не бывает одинаковых путей - Судьба Зоны. (Лучшее, что у меня получилось на X-Ray) На базе модифицированного движка OGSR Engine. Бывший мододел на X-Ray / Начинающий игродел на Unreal Engine. Программист. AMD Ryzen 9 7950X (16 ядер, 32 потока, 5.75 ГГц); RTX 3080; 128 ГБ DDR5; Arctic Liquid Freezer II-420; 3 ТБ SSD PCIe 4.0; 4ТБ HDD. Ссылка на комментарий
macron 1 811 Опубликовано 15 Июля 2021 Поделиться Опубликовано 15 Июля 2021 (изменено) Обновленный фикс детекции EAX в бинарниках скомпилированных из исходников v2 (проверено на ТЧ 1.0007).https://disk.yandex.ru/d/TRArwmnEmTtCGg Изменено 15 Июля 2021 пользователем macron Старый фикс стер. Новый оптимизирован по советам vlad_54rus. 1 2 Ссылка на комментарий
StormBreaker 1 Опубликовано 30 Октября 2021 Поделиться Опубликовано 30 Октября 2021 06.10.2017 в 23:11, Shkiper2012 сказал: // Bug_Fix: Убираем звук перезарядки, если прячем оружие. // Прошу прощения за неосведомлённость, но куда кидать эти правки? Ссылка на комментарий
Shkiper2012 35 Опубликовано 31 Октября 2021 Поделиться Опубликовано 31 Октября 2021 23 часа назад, StormBreaker сказал: куда кидать эти правки? "Кидать" не надо. Эти правки вводятся "ручками" в соответствующие файлы исходников движка. 1 Адаптация мода "AtmosFear" для мода "Боевая Подготовка" v.2.0.2. Адаптация мода "Магазинное питание" для мода "Боевая Подготовка" v.2.0.2. Ссылка на комментарий
StormBreaker 1 Опубликовано 31 Октября 2021 Поделиться Опубликовано 31 Октября 2021 3 часа назад, Shkiper2012 сказал: "Кидать" не надо. Эти правки вводятся "ручками" в соответствующие файлы исходников движка. Вопрос заключался в том, в какие именно файлы? Ссылка на комментарий
Рекомендуемые сообщения
Создайте аккаунт или авторизуйтесь, чтобы оставить комментарий
Комментарии могут оставлять только зарегистрированные пользователи
Создать аккаунт
Зарегистрировать новый аккаунт в нашем сообществе. Это несложно!
Зарегистрировать новый аккаунтВойти
Есть аккаунт? Войти.
Войти