Исходники правок, Различные исходники правок, собранные с форумов |
Здравствуйте, гость ( Авторизация | Регистрация )
Сайт S.T.A.L.K.E.R. Inside / [ЗП] Параметры командной строки / Распаковщик ресурсов
Исходники правок, Различные исходники правок, собранные с форумов |
02.02.2017, 20:44
Сообщение
#21
|
|
Почти Игроман Репутация: 91 Куратор темы Сообщений: 516 Регистрация: 19.07.2015 |
Ковыряясь на форумах находил много интересных постов, касательно готовых исходников правок. Сейчас появилось свободное время, в связи с чем решил собрать их в этой теме. Конечно же, тут собрано не всё, в ближайшее время(возможно) будет дополнено. Большая часть правок портируется под другие версии, так что, если я не написал вариант для используемой вами платформы, вы можете попробовать сделать порт сами. Особенно это относится к 1.5.10, т.к. копи-пастить куски кода я не счёл нужным. 1.0007(rc1) от Alpet & KD Vampir35: Ошибка в before save Ошибка-опечатка в оригинальном репозитории xp-dev в каллбеке на before save (вызывается перед созданием сейва, насколько я понял), точно есть с r180 и до финальной так и осталось. script_game_object_script.cpp: находим: Код value("on_before_save", int(GameObject::ePostSave)), и заменяем на: Код value("on_before_save", int(GameObject::eBeforeSave)), Создание нового слота Я использую ревизию с XP DEV, там уже проведена работа над слотами. Если кто-то использует другую версию исходников, могут быть различия. Создадим слот для второго детектора: В UIInventoryWnd.cpp: после: Код m_pUISlotQuickAccessList_3 = xr_new<CUIDragDropListEx>(); AttachChild(m_pUISlotQuickAccessList_3); m_pUISlotQuickAccessList_3->SetAutoDelete(true); xml_init.InitDragDropListEx (uiXml, "dragdrop_slot_quick_access_3", 0, m_pUISlotQuickAccessList_3); BindDragDropListEnents (m_pUISlotQuickAccessList_3); добавим: Код m_pUIDetAdvList = xr_new<CUIDragDropListEx>(); AttachChild(m_pUIDetAdvList); m_pUIDetAdvList->SetAutoDelete(true); xml_init.InitDragDropListEx (uiXml, "dragdrop_slot_det_adv", 0, m_pUIDetAdvList); BindDragDropListEnents (m_pUIDetAdvList); после: Код m_slots_array[SLOT_QUICK_ACCESS_3] = m_pUISlotQuickAccessList_3; добавить: Код m_slots_array[DET_ADV_SLOT] = m_pUIDetAdvList; В UIInventoryWnd.h: после: Код CUIDragDropListEx* m_pUISlotQuickAccessList_3; добавить: Код CUIDragDropListEx* m_pUIDetAdvList; В файле: uiinventorywnd2.cpp сразу после: Код _itm = m_pInv->m_slots[SLOT_QUICK_ACCESS_3].m_pIItem; if(_itm) { CUICellItem* itm = create_cell_item(_itm); m_pUISlotQuickAccessList_3->SetItem (itm); } добавим: Код _itm = m_pInv->m_slots[DET_ADV_SLOT].m_pIItem; if(_itm) { CUICellItem* itm = create_cell_item(_itm); m_pUIDetAdvList->SetItem (itm); } после: Код m_pUISlotQuickAccessList_3->ClearAll (true); добавим: Код m_pUIDetAdvList->ClearAll (true); В файле UIInventoryWnd3.cpp после: Код case INVENTORY_TO_SLOT15_ACTION: CurrentIItem()->SetSlot(SLOT_QUICK_ACCESS_3); break; добавим: Код case INVENTORY_TO_SLOT16_ACTION: CurrentIItem()->SetSlot(DET_ADV_SLOT); break; В файле inventory_space.h после: Код #define SLOT_QUICK_ACCESS_3 15 добавить: Код #define DET_ADV_SLOT 16 также вносим изменения в slots_total. Число должно быть на один больше последнего номера слотов. В нашем случае будет вот так: Код #define SLOTS_TOTAL 17 В файле UIMessages.h после: Код INVENTORY_TO_SLOT15_ACTION, пишем: Код INVENTORY_TO_SLOT16_ACTION, Осталось только зарегистрировать наш новый слот в конфигах игры по аналогии с остальными: В inventory_new.xml и в inventory_new_16: Код <dragdrop_slot_det_adv x="581" y="673" width="100" height="50" cell_width = "48" cell_height="50" rows_num="1" cols_num="2" custom_placement="0" show_grid = "0"/> И в system.ltx: Код slot_persistent_1 = false;нож 0 slot_persistent_2 = false;пистолет 1 slot_persistent_3 = false;автомвт 2 slot_persistent_4 = true;гранаты 3 slot_persistent_5 = false;бинокль 4 slot_persistent_6 = true;болт 5 slot_persistent_7 = false;костюм 6 slot_persistent_8 = false;пда 7 slot_persistent_9 = false;детектор 8 slot_persistent_10 = false;фонарь 9 slot_persistent_11 = true;артефакт 10 slot_persistent_12 = false;шлем 11 slot_persistent_13 = false;яч1 12 slot_persistent_14 = false;яч2 13 slot_persistent_15 = false;яч3 14 slot_persistent_16 = false;яч4 15 slot_persistent_17 = false;детектор 2 16 1.0007(rc1) Zagolski: Фикс вылета звука на ТЧ Код void CSoundRender_Source::load(LPCSTR name) { string_path fn,N; strcpy (N,name); strlwr (N); if(strext(N)) *strext(N) = 0; fname = N; strconcat (sizeof(fn),fn,N,".ogg"); if(!FS.exist("$level$",fn)) FS.update_path (fn,"$game_sounds$",fn); if (!FS.exist(fn)) { Msg("! Can't find sound '%s.ogg'",N); FS.update_path (fn,"$game_sounds$","$no_sound.ogg"); } LoadWave (fn); SoundRender->cache.cat_create (CAT, dwBytesTotal); }[code][/hide] [i]Shoker[/i]: [hide=Сохранение клиентских объектов] В файле xr_3da\xrGame\Level_network.cpp в начале функции void CLevel::ClientSend() Перед проверкой [b]GameID() == GAME_SINGLE[/b] нужно поставить отрицание: [code]if (GameID() != GAME_SINGLE && OnClient()) Более подробно о ошибке Из за этой опечатки в оригинале есть баг, что при сохранении игры в серверный объект попадают данные клиентского объекта, устаревшие на несколько апдейтов - именно в момент сохранения синхронизации не происходит. (Например если убрать в оружии сохранение патронов у клиентского объекта в CWeaponMagazined::save, оставив сохранение патронов только у серверного объекта - то если выстрелить и сразу сохраниться -> при загрузке число патронов будет прежним) Кто хочет понять природу бага - надо начинать смотреть с функции void CALifeStorageManager::prepare_objects_for_save() в alife_storage_manager.cpp. Она вызывается во время сохранения и в свою очередь вызывает CLevel::ClientSend(), однако там из за опечатки происходит проверка на пропускную способность сети net_HasBandwith() (для МП), которая в 99% возвращает false. Баг не то, чтобы критичный но всё же серьёзный. lvg_brest: Исправление не отключения света после выключения аномалии CustomZone.cpp Код //загрузить параметры световой вспышки от взрыва m_zone_flags.set(eBlowoutLight, pSettings->r_bool (section, "blowout_light")); if(m_zone_flags.test(eBlowoutLight) ){ sscanf(pSettings->r_string(section,"light_color"), "%f,%f,%f", &m_LightColor.r, &m_LightColor.g, &m_LightColor.b); m_fLightRange = pSettings->r_float(section,"light_range"); m_fLightTime = pSettings->r_float(section,"light_time"); m_fLightTimeLeft = 0.f; // Правильно задать тип переменной m_fLightHeight = pSettings->r_float(section,"light_height"); } void CCustomZone::UpdateBlowoutLight () { if(m_fLightTimeLeft>0.f) { m_fLightTimeLeft -= Device.fTimeDelta; // Исправление не отключения света после выключения аномалии if (m_fDistanceToCurEntity>29.f) if (m_fLightTime<=1.f) m_fLightTimeLeft = m_fLightTimeLeft/1.45f; else m_fLightTimeLeft = m_fLightTimeLeft/1.15f; clamp(m_fLightTimeLeft,0.0f,m_fLightTime); .... Исправление отображения параметра "отношение" при обыске тел монстров. Исправление заливки иконки красным цветом при обыске тел монстров и людей 1) UICarBodyWnd.cpp Код void CUICarBodyWnd::InitCarBody(CInventoryOwner* pOur, CInventoryOwner* pOthers) { m_pOurObject = pOur; m_pOthersObject = pOthers; m_pInventoryBox = NULL; u16 our_id = smart_cast<CGameObject*>(m_pOurObject)->ID(); u16 other_id = smart_cast<CGameObject*>(m_pOthersObject)->ID(); m_pUICharacterInfoLeft->InitCharacter (our_id); m_pUIOthersIcon->Show (true); // Исправление отображения параметра "отношение" при обыске тел монстров m_pUICharacterInfoRight->ClearFlags (); CBaseMonster *monster = NULL; if(m_pOthersObject) { monster = smart_cast<CBaseMonster *>(m_pOthersObject); if (monster || m_pOthersObject->use_simplified_visual() ) { m_pUICharacterInfoRight->ClearInfo (); if(monster) { // Исправление отображения параметра "отношение" при обыске тел монстров m_pUICharacterInfoRight->SetMonsterFlag (); shared_str monster_tex_name = pSettings->r_string(monster->cNameSect(),"icon"); m_pUICharacterInfoRight->UIIcon().InitTexture(monster_tex_name.c_str()); m_pUICharacterInfoRight->UIIcon().SetStretchTexture(true); } }else { // Исправление заливки иконки красным цветом при обыске тел монстров и людей m_pUICharacterInfoRight->SetHumanFlag (); m_pUICharacterInfoRight->InitCharacter (other_id); } } m_pUIPropertiesBox->Hide (); EnableAll (); UpdateLists (); .... void CUICarBodyWnd::Hide() { InventoryUtilities::SendInfoToActor ("ui_car_body_hide"); m_pUIOurBagList->ClearAll (true); m_pUIOthersBagList->ClearAll (true); // Исправление отображения параметра "отношение" при обыске тел монстров m_pUICharacterInfoRight->ClearFlags (); inherited::Hide (); if(m_pInventoryBox) m_pInventoryBox->m_in_use = false; } 2) UICharacterInfo.cpp Код // Исправление отображения параметра "отношение" при обыске тел монстров bool MonsterFlag = false; bool HumanFlag = false; void CUICharacterInfo::Update() { inherited::Update(); if(hasOwner() && (m_bForceUpdate||(Device.dwFrame%100==0)) ){ m_bForceUpdate = false; CSE_ALifeTraderAbstract* T = ch_info_get_from_id (m_ownerID); if (NULL==T){ m_ownerID = u16(-1); return; }else UpdateRelation(); if(m_icons[eUIIcon]){ CSE_ALifeCreatureAbstract* pCreature = smart_cast<CSE_ALifeCreatureAbstract*>(T); // Исправление отображения параметра "отношение" при обыске тел монстров if((pCreature && !pCreature->g_Alive() && MonsterFlag) || (Actor()->ID()==m_ownerID || !hasOwner())) { if(m_icons[eUIRelationCaption]) m_icons[eUIRelationCaption]->Show (false); if(m_icons[eUIRelation]) m_icons[eUIRelation]->Show (false); } // Исправление заливки иконки красным цветом при обыске тел монстров и людей if(pCreature && !pCreature->g_Alive() && !MonsterFlag && !HumanFlag) { m_icons[eUIIcon]->SetColor (color_argb(255,255,160,160)); } } } } В конце UICharacterInfo.cpp (после void CUICharacterInfo::ClearInfo()) дописать: Код // Исправление отображения параметра "отношение" при обыске тел монстров void CUICharacterInfo::SetMonsterFlag() { MonsterFlag = true; } void CUICharacterInfo::SetHumanFlag() { HumanFlag = true; } void CUICharacterInfo::ClearFlags() { MonsterFlag = false; HumanFlag = false; } 3) UICharacterInfo.h Код public: ... u16 OwnerID () const {return m_ownerID;} CUIStatic& UIIcon () {VERIFY(m_icons[eUIIcon]);return *m_icons[eUIIcon];} CUIStatic& UIName() {VERIFY(m_icons[eUIName]);return *m_icons[eUIName];} const shared_str& IconName () {return m_texture_name;} // Исправление отображения параметра "отношение" при обыске тел монстров void SetMonsterFlag (); void SetHumanFlag (); void ClearFlags (); }; Исправление отображения зеленым цветом прочитанных записей в разделе КПК "Дневник 1) UIDiaryWnd2.cpp Код void CUIDiaryWnd::LoadJournalTab (ARTICLE_DATA::EArticleType _type) { delete_data (m_ArticlesDB); m_UILeftWnd->AttachChild (m_SrcListWnd); m_SrcListWnd->Show (true); m_UIRightWnd->AttachChild (m_DescrView); m_DescrView->Show (true); if(Actor()->encyclopedia_registry->registry().objects_ptr()){ ARTICLE_VECTOR::const_iterator it = Actor()->encyclopedia_registry->registry().objects_ptr()->begin(); for(; it != Actor()->encyclopedia_registry->registry().objects_ptr()->end(); it++) if (_type == it->article_type) // Исправление отображения зеленым цветом прочитанных записей в дневнике КПК AddDiaryArticle(it->article_id, it->readed); } g_pda_info_state &= !pda_section::journal; } void CUIDiaryWnd::OnSrcListItemClicked (CUIWindow* w,void* p) { CUITreeViewItem* pSelItem = (CUITreeViewItem*)p; m_DescrView->Clear (); if (!pSelItem->IsRoot()) { CUIEncyclopediaArticleWnd* article_info = xr_new<CUIEncyclopediaArticleWnd>(); article_info->Init ("encyclopedia_item.xml","encyclopedia_wnd:objective_item"); article_info->SetArticle (m_ArticlesDB[pSelItem->GetValue()]); m_DescrView->AddWindow (article_info, true); // Исправление отображения зеленым цветом прочитанных записей в дневнике КПК if (!pSelItem->IsArticleReaded() && Actor()->encyclopedia_registry->registry().objects_ptr()) for(ARTICLE_VECTOR::iterator it = Actor()->encyclopedia_registry->registry().objects().begin(); it != Actor()->encyclopedia_registry->registry().objects().end(); it++) if (ARTICLE_DATA::eJournalArticle == it->article_type && m_ArticlesDB[pSelItem->GetValue()]->Id() == it->article_id) { it->readed = true; break; } } } В конце UIDiaryWnd2.cpp дописать: Код // Исправление отображения зеленым цветом прочитанных записей в дневнике КПК void CUIDiaryWnd::AddDiaryArticle(shared_str article_id, bool bReaded) { m_ArticlesDB.resize(m_ArticlesDB.size() + 1); CEncyclopediaArticle*& a = m_ArticlesDB.back(); a = xr_new<CEncyclopediaArticle>(); a->Load(article_id); CreateTreeBranch(a->data()->group, a->data()->name, m_SrcListWnd, m_ArticlesDB.size()-1, m_pTreeRootFont, m_uTreeRootColor, m_pTreeItemFont, m_uTreeItemColor, bReaded); } Код [b]2)[/b] UIDiaryWnd.h void UnloadNewsTab (); void LoadNewsTab (); void Reload (EDiaryFilter new_filter); // Исправление отображения зеленым цветом прочитанных записей в дневнике КПК void AddDiaryArticle (shared_str, bool bReaded); Исправление учета статистики убийства сталкеров и мутантов, выполненных квестов actor_statistic_mgr.cpp Код void CActorStatisticMgr::AddPoints(const shared_str& key, const shared_str& detail_key, s32 cnt, s32 pts) { SStatSectionData& sect = GetSection (key); SStatDetailBData& d = sect.GetData (detail_key); d.int_count += cnt; // Исправление учета статистики убийства сталкеров и мутантов, выполненных квестов d.int_points = pts; } Исправление работы статика биографии в разделе КПК "Ранги UICharacterInfo.cpp Код if (chInfo.Bio().size()) { CUIStatic* pItem = xr_new<CUIStatic>(); pItem->SetWidth (pUIBio->GetDesiredChildWidth()); // Исправление работы статика биографии pItem->SetTextComplexMode (true); pItem->SetText (*(chInfo.Bio())); pItem->AdjustHeightToText (); pUIBio->AddWindow (pItem, true); } Исправление "залипания" курсора мыши в главном меню после просмотра титров 1) UIGameTutorialSimpleItem.cpp Код bool CUISequenceSimpleItem::Stop (bool bForce) { if(!m_flags.test(etiCanBeStopped)&&!bForce) return false; m_owner->MainWnd()->DetachChild (m_UIWindow); m_sound.stop (); if(m_flags.test(etiNeedPauseOn) && !m_flags.test(etiStoredPauseState)) Device.Pause (FALSE, TRUE, FALSE, "simpleitem_stop"); if(m_flags.test(etiNeedPauseOff) && m_flags.test(etiStoredPauseState)) Device.Pause (TRUE, TRUE, FALSE, "simpleitem_stop"); if(m_flags.test(etiNeedPauseSound)) Device.Pause (FALSE, FALSE, TRUE, "simpleitem_stop"); // Исправление "залипания" курсора мыши в главном меню после просмотра титров if (!g_pGameLevel){ GetUICursor()->SetUICursorPosition (m_desired_cursor_pos); } if (g_pGameLevel){ CUIGameSP* ui_game_sp = smart_cast<CUIGameSP*>(HUD().GetUI()->UIGame()); if( ui_game_sp && ui_game_sp->PdaMenu->IsShown() ) HUD().GetUI()->StartStopMenu (ui_game_sp->PdaMenu, true); } inherited::Stop (); return true; } KD: Окна редактора в xrCore::_initialize и _destroy уберите Код CoInitializeEx (NULL, COINIT_MULTITHREADED) Иначе GetOpenFileName/GetSaveFileName повисают на висте и выше. SkyLoader: Не работает вертикальная синхронизация (r2) HW.cpp: Код DevPP.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; И Код P.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; Меняем D3DPRESENT_INTERVAL_IMMEDIATE на selectPresentInterval() Очень странный вылет Данная проблема была в свое в ЛА еще в 2013 году, и я очень долго не мог найти причину вылета, так как вылет каждый раз ссылался на разные некорректные по его мнению объекты. Причем возникал не всегда и можно было его поймать только при выходе из игры. Спустя несколько месяцев чудом проблема была найдена. Оказывается, проблема была в лампочках, которые включались и выключались скриптово. Игра ловила крэш при 255 и более включении и выключении лампочки. Фиксится в HangingLamp.cpp в строках: Код } if(!PPhysicsShell())//if we have physiccs_shell it will call processing deactivate when disable processing_deactivate (); Удаляем if(!PPhysicsShell()), теперь processing_deactivate(); будет срабатывать всегда, как и должен, и мы можем включать и выключать лампочки сколько угодно раз. Фикс полосы загрузки x_ray.cpp: Код if (g_pGamePersistent->GameType()==1 && strstr(Core.Params,"alife")) max_load_stage = 17; else max_load_stage = 14; Как можно заметить по названию, max_load_stage, это переменная, которая показывает количество стадий загрузки, т.е. загрузка моделей, шейдеров, звуков, синхронизация объектов и тд. В сингле их целых 17, в мультиплеере 14. Вот эту переменную потом получает рендер и рисует шкалу загрузки в соответствии с текущей стадией загрузки. Но тут есть ошибка, а именно сравнение strstr(Core.Params,"alife"). Но у нас никогда не происходит такого, так как никто не пишет батник запуска игры с добавлением alife. Именно это и проверяется. Из-за этого для игры переменная max_load_stage всегда равна 14. Поэтому в ЗП полоса загрузки очень быстро достигает конца и долго висит. Код if (g_pGamePersistent->GameType()==1 && !xr_strcmp(p.m_alife, "alife")) max_load_stage = 17; else max_load_stage = 14; Полтергейст: Vampir35: Исправление пулестойкости костюмов SHoC Кто-то слышал, кто-то нет, как разработчики некоторых глобальных модов упоминали (ну по крайней мере я что-то подобное помню), что в движок закралась какая-то чудовищная ошибка и на самом деле бронежилеты от пуль не защищают и чуть ли не чем больше показатель, тем хуже. Однако, в принципе, не так все страшно. На самом деле в этом плане никакой ошибки нет. Просто в Сталкере (речь идет о ТЧ, насчет других частей серии - не уверен, хотя суть та же скорее всего) расчет хита от пули происходит иначе, чем от любого другого воздействия. А конкретно, берутся настройки костей, что позволяет более гибко эту самую пулестойкость настроить. Подробнее можно почитать здесь. Пулестойкость ГГ рассчитывается также, как у НПС. На самом деле, это легко исправить. Возможно ,кому-то не понравится такой способ, ибо если выставить у костюма 100% защиты, то новый костюм будет полностью защищать от пуль (ну пока не износится само собой) не учитывая, что какие-то участки защищены сильнее/слабее. Как по мне, защита по костям, конечно, реалистичнее, но вариант просто в процентах - более играбельный, ведь игрок видит в инвентаре насколько его защищает данный костюм и эта цифра соответствует действительности. Итак. Как сделать работу пулестойкости такой же, как остальные воздействия? Для начала стоит вынести это дело под дефайн, дабы иметь возможность при необходимости включить/отключить данную правку. Для этого, в файл build_config_defines.h(или в любой другой header) нужно добавить: Код #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 Вот и всё, если есть какие-то вопросы - пишите, возможно, я забыл что-то указать. SHoC. Новые параметры для бронежилетов В CoP некоторые модификации броников увеличивают скорость восстановления здоровья, энергии и т.д. В оригинале ТЧ есть пара уникальных костюмов, в которых даже прописан параметр health_restore_speed, но конечно же, он не работает. Добавить эти параметры очень просто: В CustomOutfit.cpp после: Код m_HitTypeProtection[ALife::eHitTypePhysicStrike]= READ_IF_EXISTS(pSettings, r_float, section, "physic_strike_protection", 0.0f); Добавим: Код m_fHealthRestoreSpeed = READ_IF_EXISTS(pSettings, r_float, section, "health_restore_speed", 0.0f ); m_fRadiationRestoreSpeed = READ_IF_EXISTS(pSettings, r_float, section, "radiation_restore_speed", 0.0f ); m_fSatietyRestoreSpeed = READ_IF_EXISTS(pSettings, r_float, section, "satiety_restore_speed", 0.0f ); m_fPowerRestoreSpeed = READ_IF_EXISTS(pSettings, r_float, section, "power_restore_speed", 0.0f ); m_fBleedingRestoreSpeed = READ_IF_EXISTS(pSettings, r_float, section, "bleeding_restore_speed", 0.0f ); Сразу хочу заметить, что если в конфиге будет отсутствовать один из новых параметров, его значение будет равным 0.0. Идем дальше. В файле CustomOutfit.h после: Код public: float m_additional_weight; float m_additional_weight2; добавим: Код float m_fHealthRestoreSpeed; float m_fRadiationRestoreSpeed; float m_fSatietyRestoreSpeed; float m_fPowerRestoreSpeed; float m_fBleedingRestoreSpeed; Теперь эти параметры читаются, но пока ещё никак не используются. Для их использования в Actor.cpp после, например: Код float CActor::HitArtefactsOnBelt (float hit_power, ALife::EHitType hit_type) { float res_hit_power_k = 1.0f; float _af_count = 0.0f; ................................................................................ res_hit_power_k -= _af_count; return res_hit_power_k * hit_power; } Добавим: Код #define OUTFIT_UPDATE_TIME 0.100f #include "CustomOutfit.h" void CActor::UpdtateOutfitInSlot() { static float update_time = 0; float f_update_time = 0; if(update_time<OUTFIT_UPDATE_TIME) { update_time += conditions().fdelta_time(); return; } else { f_update_time = update_time; update_time = 0.0f; } CCustomOutfit* outfit = GetOutfit(); if(outfit) { conditions().ChangeBleeding(outfit->m_fBleedingRestoreSpeed*f_update_time); conditions().ChangeHealth(outfit->m_fHealthRestoreSpeed*f_update_time); conditions().ChangePower(outfit->m_fPowerRestoreSpeed*f_update_time); conditions().ChangeSatiety(outfit->m_fSatietyRestoreSpeed*f_update_time); #ifndef OBJECTS_RADIOACTIVE // alpet: отключается для избежания двойного хита conditions().ChangeRadiation (outfit->m_fRadiationRestoreSpeed*f_update_time); #endif } } Теперь после Код //для свойств артефактов, находящихся на поясе UpdateArtefactsOnBelt (); добавим: Код UpdtateOutfitInSlot (); Теперь в Actor.h после: Код //свойства артефактов virtual void UpdateArtefactsOnBelt (); virtual void MoveArtefactBelt (const CArtefact* artefact, bool on_belt); virtual float HitArtefactsOnBelt (float hit_power, ALife::EHitType hit_type); const xr_vector<const CArtefact*>& ArtefactsOnBelt() {return m_ArtefactsOnBelt;} добавим: Код //свойства брони virtual void UpdtateOutfitInSlot (); SHoC. Создание нового индикатора на худе Все мы с Вами знаем, что в ЗП добавлен ряд интересных и полезных индикаторов на худе. На самом деле добавить их легко. Разберем на примере индикатора поломки брони. Для начала, в движке CoP есть такой удобный инструмент как UIHelper, для дальнейшей работы он нам понадобится, поэтому добавляем в xrGame\ui: Код 1. UIHelper.h //////////////////////////////////////////////////////////////////////////// // Module : UIHelper.h // Created : 17.01.2008 // Author : Evgeniy Sokolov // Description : UI Helper class //////////////////////////////////////////////////////////////////////////// #ifndef UI_HELPER_H_INCLUDED #define UI_HELPER_H_INCLUDED class CUIXml; class CUIWindow; class CUIStatic; class UIHelper { public: UIHelper () {}; ~UIHelper () {}; static CUIStatic* CreateStatic ( CUIXml& xml, LPCSTR ui_path, CUIWindow* parent ); }; #endif // UI_HELPER_H_INCLUDED 2. UIHelper.cpp: Код //////////////////////////////////////////////////////////////////////////// // Module : UIHelper.cpp // Created : 17.01.2008 // Author : Evgeniy Sokolov // Description : UI Helper class implementation //////////////////////////////////////////////////////////////////////////// #include "StdAfx.h" #include "UIHelper.h" #include "UIXmlInit.h" CUIStatic* UIHelper::CreateStatic( CUIXml& xml, LPCSTR ui_path, CUIWindow* parent ) { CUIStatic* ui = new CUIStatic(); if(parent) { parent->AttachChild ( ui ); ui->SetAutoDelete ( true ); } CUIXmlInit::InitStatic ( xml, ui_path, 0, ui ); return ui; } Здесь я оставил только добавление статика, на самом деле в ЗП с помощью этого инструмента можно все что угодно добавлять. Переносите себе по мере необходимости , идем дальше. Нам нужен файл UIMainIngameWnd.h в группе protected: находим: Код CUIZoneMap* UIZoneMap; И после добавляем: Код CUIStatic* m_ind_outfit_broken; Теперь файл UIMainIngameWnd.cpp. Сначала не забудьте прописать Код #include "UIHelper.h" в начале файла там где все остальные. Находим: Код void CUIMainIngameWnd::Init() К примеру, после: Код m_UIIcons = xr_new<CUIScrollView>(); m_UIIcons->SetAutoDelete(true); xml_init.InitScrollView (uiXml, "icons_scroll_view", 0, m_UIIcons); AttachChild (m_UIIcons); Добавим: Код m_ind_outfit_broken = UIHelper::CreateStatic(uiXml, "indicator_outfit_broken", this); Затем находим: Код void CUIMainIngameWnd::Update() И, например, перед: Код // health&power UIHealthBar.SetProgressPos (m_pActor->GetfHealth()*100.0f); UIMotionIcon.SetPower (m_pActor->conditions().GetPower()*100.0f); Добавим: Код PIItem pItem = m_pActor->inventory().ItemFromSlot(OUTFIT_SLOT); m_ind_outfit_broken->Show(false); if (pItem) { float condition = pItem->GetCondition(); if (condition<0.75f) { m_ind_outfit_broken->Show(true); if(condition>0.5f) m_ind_outfit_broken->InitTexture("ui_inGame2_circle_Armorbroken_green"); else if(condition>0.25f) m_ind_outfit_broken->InitTexture("ui_inGame2_circle_Armorbroken_yellow"); else m_ind_outfit_broken->InitTexture("ui_inGame2_circle_Armorbroken_red"); } } Теперь разберем что нужно будет сделать в конфигах. Код indicator_outfit_broken это имя статика. Добавить надо его в maingame.xml вот так: Код <indicator_outfit_broken x="980" y="410" width="26" height="35" stretch="1"/> ну и, соответственно, "зарегистрировать" в игре вот эти текстуры: Код "ui_inGame2_circle_Armorbroken_green" "ui_inGame2_circle_Armorbroken_yellow" "ui_inGame2_circle_Armorbroken_red" На этом всё . Собственно у меня по такой схеме сделаны все подобные иконки, потому что система ТЧ показалась мне неоправданно сложной и громоздкой. Ну, быть может, это на мой дилетантский взгляд. P.S. Конечно, лучше совместить прогресс бар, который показывает состояние брони и этот индикатор. Чтобы два раза не дергать состояние костюма на апдейте. Но я не стал усложнять урок) SHoC. Назначение скриптам горячих клавиш, изменяемых в главном меню. Думаю из названия всё понятно. Создадим кнопку, которую можно будет легко изменять в опциях, а при нажатии будет вызываться функция из скрипта. В файле: ActorInput.cpp после: Код #include "../../build_config_defines.h" добавим: Код #include "pch_script.h" #include "InventoryOwner.h" #include "script_game_object.h" #include "script_game_object_impl.h" На самом деле я точно не уверен, что нужны все четыре инклуда, возможно в этом файле я прописывал инклуд для чего-то ещё. Но на всякий случай добавьте все четыре. Также, например после: Код case kCROUCH_TOGGLE: Добавим:{ g_bAutoClearCrouch = !g_bAutoClearCrouch; if (!g_bAutoClearCrouch) mstate_wishful |= mcCrouch; }break; Код case kCLOCK: { luabind::functor<void> clock_key; if (ai().script_engine().functor("gz_items_hud.clock_key",clock_key)) clock_key(); }break; Как видите у меня здесь кнопка показа часов. "gz_items_hud.clock_key" это как раз скрипт и функция, которые будут вызваны при нажатии кнопки. Теперь в файле key_binding_registrator_script.cpp в: Код class_<enum_exporter<EGameActions> >("key_bindings") .enum_("commands") [ по аналогии с остальным добавим: Код value("kCLOCK", int(kCLOCK)), Если будете добавлять в самый конец, не забудьте убрать запятую после двойной скобки. Потом в файле: xr_level_controller.cpp добавим по аналогии с остальными: Код { "clock", kCLOCK ,_sp}, Как я понял, _sp - работает в одиночной игре, _both в одиночной и мультиплеере, _mp - только в мультиплеере. Но это нужно проверять. Я мультиплеер не использую, стоит _sp и пускай себе стоит . Теперь в xr_level_controller.h добавим: Код kCLOCK, к другим кнопкам. Кстати таким образом, если это необходимо, можно заменить какое-то движковое действие на скриптовое. Просто ищем case kНУЖНАЯ КНОПКА: и меняем "начинку" на свою. Всё, в движке кнопка имеется, переходим к конфигам: Файл u\ui_keybinding.xml добавим в нужную группу кнопок: Код <command id="kb_clock" exe="clock"/> Теперь в test\rus\ui_st_keybinding.xml <string id="kb_clock"> <text>Часы</text> </string> Если вы хотите чтобы по умолчанию кнопка была уже установлена, ищем файл default_controls.ltx в папке config оттуда берутся данные о том, какую кнопку на какое действие назначить при создании игрой файла user.ltx Просто пишем: Код bind clock kC Функция в скрипте самая обычная: Код --//*** ЧАСЫ НА РУКЕ function clock_key() -- вызывается из движка при нажатии кнопки часов --действия при нажатии кнопки end На этом всё. Правда я не проверял, что будет, если скрипта или функции не существует. Функции для работы с временем xrGame: level_script.cpp: В началo файла, перед: Код using namespace luabind; добавим инклуды: Код #include "alife_time_manager.h" #include "game_sv_single.h" #include "alife_simulator.h" Потом после: Код u32 get_time_minutes() { u32 year = 0, month = 0, day = 0, hours = 0, mins = 0, secs = 0, milisecs = 0; split_time(Level().GetGameTime(), year, month, day, hours, mins, secs, milisecs); return mins; } добавить: Код void change_game_time(u32 days, u32 hours, u32 mins) { game_sv_Single* tpGame = smart_cast<game_sv_Single *>(Level().Server->game); if (tpGame && ai().get_alife()) { u32 value = days * 86400 + hours * 3600 + mins * 60; float fValue = static_cast<float>(value); value *= 1000; // msec g_pGamePersistent->Environment().ChangeGameTime(fValue); tpGame->alife().time_manager().change_game_time(value); } } и в этом же файле, после: Код def("get_time_minutes", get_time_minutes), добавим:Код def("change_game_time", change_game_time), Теперь в файле alife_time_manager.h, после: Код IC float normal_time_factor () const; добавим: Код IC void change_game_time (u32 value); В файле alife_time_manager_inline.h добавим в конце: Код IC void CALifeTimeManager::change_game_time(u32 value) { m_game_time += value; } XR_3DA: Environment.h: после: Код shared_str GetWeather () { return CurrentWeatherName;} добавим:Код void ChangeGameTime (float game_time); Environment.cpp: перед: Код void CEnvironment::SetGameTime(float game_time, float time_factor) добавим: Код void CEnvironment::ChangeGameTime(float game_time) { fGameTime = NormalizeTime(fGameTime + game_time); }; 1.5.10 Stalker_Monolit: Купол над актером Код r2_sun_depth_near_scale = 1.00001f но разрабы наверно забыли что диапазон стоит от 0,5 до 1,5 думаю что ставить 1.00001f было бесполезно если переключение идет только 0.5-1.0-1.5 r2_sun_depth_near_bias = 0.00005f диапазон -0.5 до 0,5 исправил на r2_sun_depth_near_scale = 1.f я поставил средние значения r2_sun_depth_near_bias = 0.f я поставил средние значения Max Warlock: Изменение кол-ва отображаемых группировок в PDA UIRankingWnd.h: Параметр max_factions Forser: Исправляем инвизибл кровососа Привести метод "Hit" в файле Bloodsucker.cpp к следующему виду: Код void CAI_Bloodsucker::Hit(SHit* pHDS) { if (!collision_hit_off) inherited::Hit(pHDS); } 1.6.02 Stalker_Monolit: Купол над актером Код r2_sun_depth_near_scale = 1.00001f но разрабы наверно забыли что диапазон стоит от 0,5 до 1,5 думаю что ставить 1.00001f было бесполезно если переключение идет только 0.5-1.0-1.5 r2_sun_depth_near_bias = 0.00005f диапазон -0.5 до 0,5 исправил на r2_sun_depth_near_scale = 1.f я поставил средние значения r2_sun_depth_near_bias = 0.f я поставил средние значения Shoker: Проблемы динамических моделей и их решение Фикс сохранения клиентских объектов В файле xrGame\Level_network.cpp в начале функции void CLevel::ClientSend() Перед проверкой GameID() == eGameIDSingle нужно поставить отрицание: Код if (GameID() != eGameIDSingle && OnClient()) Тогда при сохранении игры для всех клиентских объектов будет вызываться net_Export (клиентские объекты будут синхронизироваться с серверным чётко при сохранении) Более подробно о ошибке Из за этой опечатки в оригинале есть баг, что при сохранении игры в серверный объект попадают данные клиентского объекта, устаревшие на несколько апдейтов - именно в момент сохранения синхронизации не происходит. (Например если убрать в оружии сохранение патронов у клиентского объекта в CWeaponMagazined::save, оставив сохранение патронов только у серверного объекта - то если выстрелить и сразу сохраниться -> при загрузке число патронов будет прежним) Кто хочет понять природу бага - надо начинать смотреть с функции void CALifeStorageManager::prepare_objects_for_save() в alife_storage_manager.cpp. Она вызывается во время сохранения и в свою очередь вызывает CLevel::ClientSend(), однако там из за опечатки происходит проверка на пропускную способность сети net_HasBandwith() (для МП), которая в 99% возвращает false. Баг не то, чтобы критичный но всё же серьёзный. SkyLoader: Вертикальная синхронизация (дополнение для r3/r4) dxRenderDeviceRender.cpp: Код HW.m_pSwapChain->Present( 0, 0); Добавляем проверку на включение вертикальной синхронизации: Код HW.m_pSwapChain->Present(psDeviceFlags.test(rsVSync) ? 1 : 0, 0); Очень странный вылет Данная проблема была в свое в ЛА еще в 2013 году, и я очень долго не мог найти причину вылета, так как вылет каждый раз ссылался на разные некорректные по его мнению объекты. Причем возникал не всегда и можно было его поймать только при выходе из игры. Спустя несколько месяцев чудом проблема была найдена. Оказывается, проблема была в лампочках, которые включались и выключались скриптово. Игра ловила крэш при 255 и более включении и выключении лампочки. Фиксится в HangingLamp.cpp в строках: Код if(!PPhysicsShell())//if we have physiccs_shell it will call processing deactivate when disable processing_deactivate (); Удаляем if(!PPhysicsShell()), теперь processing_deactivate(); будет срабатывать всегда, как и должен, и мы можем включать и выключать лампочки сколько угодно раз. Эффектор перезарядки срабатывает не каждый раз Эффектор перезарядки срабатывает не каждый раз [ЗП] Ну тут всё просто, просто перезапускаем активный эффектор. Заходим в player_hud.cpp, находим строки 380-381: Код if(NULL==ec) { Эти две строки с закрывающейся скобкой удаляем. Вместо этого вставляем: Код if(ec) current_actor->Cameras().RemoveCamEffector(eCEWeaponAction); Теперь эффектор работает при каждой перезарядке. Растянутое небо Код [b]dxEnvironmentRender.cpp:[/b] static Fvector3 hbox_verts[24] = { {-1.f, -1.f, -1.f}, {-1.f, -1.01f, -1.f}, // down { 1.f, -1.f, -1.f}, { 1.f, -1.01f, -1.f}, // down {-1.f, -1.f, 1.f}, {-1.f, -1.01f, 1.f}, // down { 1.f, -1.f, 1.f}, { 1.f, -1.01f, 1.f}, // down {-1.f, 1.f, -1.f}, {-1.f, 1.f, -1.f}, { 1.f, 1.f, -1.f}, { 1.f, 1.f, -1.f}, {-1.f, 1.f, 1.f}, {-1.f, 1.f, 1.f}, { 1.f, 1.f, 1.f}, { 1.f, 1.f, 1.f}, {-1.f, 0.f, -1.f}, {-1.f, -1.f, -1.f}, // half { 1.f, 0.f, -1.f}, { 1.f, -1.f, -1.f}, // half { 1.f, 0.f, 1.f}, { 1.f, -1.f, 1.f}, // half {-1.f, 0.f, 1.f}, {-1.f, -1.f, 1.f} // half }; Shredder: Воздействие аномалий на НПС В классе CSpaceRestrictor в методе net_Spawn убираем строчку Код spatial.type &= ~STYPE_VISIBLEFORAI Может, конечно, я тут Америку не открыл, но мне никто так и не подсказал. Правда после включения наблюдается интересная картина. Если сталкер после первого хита выжил, он чуть отходит назад и начинает кидать болты )) Правда не совсем туда, куда надо. Да и выглядит это кривовато, но думаю эту схему можно отключить и подключить скриптовую, например из amk для ТЧ Forser: Размытые шрифты на dx11 В dxFontRender.cpp ищем: Код #ifndef USE_DX10 //Make half pixel offset for 1 to 1 mapping tu +=( 0.5f / owner.vTS.x ); tv +=( 0.5f / owner.vTS.y ); #endif // USE_DX10 И модифицируем проверку: Код #if !defined(USE_DX10) && !defined(USE_DX11) KD & nikita_nz1986 & Forser: Тень от травы Так значит:Тень травы в файле DetailManager_VS.cpp(r2 only, совместимо с 1.0007) после Код RCache.stat.r.s_details.add (dwCNT_verts); } добавить: Код // KD: we must not clear vis on r2 since we want details shadows #if RENDER==R_R2 if ((ps_r2_ls_flags.test(R2FLAG_SUN_DETAILS) && (RImplementation.PHASE_SMAP == RImplementation.phase)) // phase smap with shadows || (ps_r2_ls_flags.test(R2FLAG_SUN_DETAILS) && (RImplementation.PHASE_NORMAL == RImplementation.phase) && (!RImplementation.is_sun())) // phase normal with shadows without sun || (!ps_r2_ls_flags.test(R2FLAG_SUN_DETAILS) && (RImplementation.PHASE_NORMAL == RImplementation.phase))) // phase normal without shadows #endif И аналогично в dx10DetailManager_VS.cpp в метод hw_Render_dump без проверки макроса RENDER Далее в r2.cpp, а также в r3.cpp и в r4.cpp добавить функцию Код bool CRender::is_sun() { if (o.sunstatic) return FALSE; Fcolor sun_color = ((light*)Lights.sun_adapted._get())->color; return (ps_r2_ls_flags.test(R2FLAG_SUN) && (u_diffuse2s(sun_color.r, sun_color.g, sun_color.B )>EPS)); } Затем в r2.h, а также в r3.h и в r4.h добавить идентификатор: Код bool is_sun(); Alundaio: Исправление недоступности вызова inherited::inherited::schedule_Update(dt) CustomMonster.h: Изменяем уровень доступа для inherited Код protected: typedef CEntityAlive inherited; entity_alive.h Добавляем protected перед определением inherited: Код protected: typedef CEntity inherited; private: Исправление недоступности вызова inherited::inherited::ProcessCam(info) ActorEffector.h:Добавляем protected перед определением inherited: Код protected: typedef CCameraManager inherited; private: Исправление Death callback для GameObject DestroyablePhysicsObject.cpp: Находим: Код callback(GameObject::eDeath)(lua_game_object(),who_object ? who_object : 0); И приводим к след.виду: Код callback(GameObject::eDeath)(lua_game_object(),who_object ? who_object->lua_game_object() : 0); Nanobot: Исправление explode() для гранат Находим файл script_game_object2.cpp и правим метод void CScriptGameObject::explode(u32 level_time) Заменяем это: Код explosive->SetInitiator(object().ID()); На это: Код explosive->SetInitiator(explosive->Initiator()); // устанавливаем инициатор только если он неизвестен. Не правильно работает гранатная прокрутка? Код bool CGrenade::Action(s32 cmd, u32 flags) { if(inherited::Action(cmd, flags)) return true; switch(cmd) { //переключение типа гранаты case kWPN_NEXT: { if(flags&CMD_START) { if(m_pCurrentInventory) { // (c) NanoBot xr_vector<shared_str> types_sect_grn; // текущий список секций гранат // Находим список секций гранат разных типов в активе // в m_belt или m_ruck нет гранаты которую актор держит в руках, т.е. this types_sect_grn.push_back(this->cNameSect()); int count_types = 1; // текущие количество типов гранат в активе //GRENADE_FROM_BELT TIItemContainer::iterator it, it_e; if(Belt()) { it = m_pCurrentInventory->m_belt.begin(); it_e = m_pCurrentInventory->m_belt.end(); } else { it = m_pCurrentInventory->m_ruck.begin(); it_e = m_pCurrentInventory->m_ruck.end(); } for(;it!=it_e;++it) { CGrenade *pGrenade = smart_cast<CGrenade*>(*it); if(pGrenade) { // составляем список типов гранат (с) НаноБот xr_vector<shared_str>::const_iterator I = types_sect_grn.begin(); xr_vector<shared_str>::const_iterator E = types_sect_grn.end(); bool new_type = true; for (; I != E; ++I) { if(!xr_strcmp(pGrenade->cNameSect(), *I)) // если совпадают new_type = false; } if(new_type) // новый тип гранаты?, добавляем { types_sect_grn.push_back(pGrenade->cNameSect()); count_types++; } } } // Если типов больше 1 то, сортируем список по алфавиту // и находим номер текущей гранаты в списке. if(count_types>1) { int curr_num = 0; // номер типа текущей гранаты std::sort(types_sect_grn.begin(), types_sect_grn.end()); xr_vector<shared_str>::const_iterator I = types_sect_grn.begin(); xr_vector<shared_str>::const_iterator E = types_sect_grn.end(); for (; I != E; ++I) { if(!xr_strcmp(this->cNameSect(), *I)) // если совпадают break; curr_num++; } int next_num = curr_num+1; // номер секции следующей гранаты if(next_num>=count_types) next_num = 0; shared_str sect_next_grn = types_sect_grn[next_num]; // секция следущей гранаты // Ищем в активе гранату с секцией следущего типа //GRENADE_FROM_BELT TIItemContainer::iterator it, it_e; if(Belt()) { it = m_pCurrentInventory->m_belt.begin(); it_e = m_pCurrentInventory->m_belt.end(); } else { it = m_pCurrentInventory->m_ruck.begin(); it_e = m_pCurrentInventory->m_ruck.end(); } for(;it!=it_e;++it) { CGrenade *pGrenade = smart_cast<CGrenade*>(*it); if(pGrenade && !xr_strcmp(pGrenade->cNameSect(), sect_next_grn)) { m_pCurrentInventory->Ruck(this); m_pCurrentInventory->SetActiveSlot(NO_ACTIVE_SLOT); m_pCurrentInventory->Slot(pGrenade); //GRENADE_FROM_BELT if(Belt()) m_pCurrentInventory->Belt(this); // текущую гранату, обратно в пояс. return true; } } } return true; } } return true; }; } return false; } Гранаты прокручиваются в алфавитном порядке, по имени секции. использование гранат из рюкзака, или из пояса, в зависимости от настройки конфига Код void CGrenade::PutNextToSlot() { if (OnClient()) return; VERIFY (!getDestroy()); //выкинуть гранату из инвентаря if (m_pCurrentInventory) { NET_Packet P; m_pCurrentInventory->Ruck (this); //GRENADE_FROM_BELT this->u_EventGen (P, (Belt() ? GEG_PLAYER_ITEM2BELT : GEG_PLAYER_ITEM2RUCK), this->H_Parent()->ID()); P.w_u16 (this->ID()); this->u_EventSend (P); //GRENADE_FROM_BELT CGrenade *pNext = smart_cast<CGrenade*>( m_pCurrentInventory->Same(this, !Belt()) ); if(!pNext) pNext = smart_cast<CGrenade*>( m_pCurrentInventory->SameSlot(GRENADE_SLOT, this, !Belt())); VERIFY (pNext != this); if(pNext && m_pCurrentInventory->Slot(pNext) ) { pNext->u_EventGen (P, GEG_PLAYER_ITEM2SLOT, pNext->H_Parent()->ID()); P.w_u16 (pNext->ID()); pNext->u_EventSend (P); m_pCurrentInventory->SetActiveSlot(pNext->GetSlot()); } ///// m_thrown = false; } } Модернизация GetCurrentFireMode для ухода от CWeaponCustomPistol Код virtual int GetCurrentFireMode() { return m_bHasDifferentFireModes ? m_aFireModes[m_iCurFireMode] : 1; }; Giperion, Forser: Утечка памяти Исходник: src/Layers/xrRenderDX10/dx10ResourceManager_Resources.cpp Код IReader* R = FS.r_open(cname); // TODO: DX10: HACK: Implement all shaders. Remove this for PS if (!R) { string1024 tmp; // TODO: HACK: Test failure //Memory.mem_compact(); xr_sprintf (tmp, "DX10: %s is missing. Replace with stub_default.ps", cname); Msg (tmp); strconcat (sizeof(cname), cname,GlobalEnv.Render->getShaderPath(),"stub_default",".ps"); FS.update_path (cname, "$game_shaders$", cname); R = FS.r_open(cname); } IReader* file = FS.r_open(cname); R_ASSERT2 ( file, cname ); u32 const size = file->length(); IReader* R - незакрытый объект файла. Который еще и не используется дальше, ведь его подменяет file, который потом успешно закрывается. Код IReader* file = FS.r_open(cname); // TODO: DX10: HACK: Implement all shaders. Remove this for PS if (!file) { string1024 tmp; //TODO: HACK: Test failure xr_sprintf(tmp, "DX10: %s is missing. Replace with stub_default.ps", cname); Msg(tmp); strconcat(sizeof(cname), cname,GlobalEnv.Render->getShaderPath(),"stub_default",".ps"); FS.update_path(cname, "$game_shaders$", cname); file = FS.r_open(cname); } R_ASSERT2 (file, cname); u32 const size = file->length(); Утечка обнаружена Giperion'ом. qweasdd136963: Глитч камеры при перезарядке Правка позиции ведения огня для актора Правка позиции ведения огня для актора, т.к. она идет от центра камеры Файл: Actor_Weapon.cpp Код void CActor::g_fireParams (const CHudItem* pHudItem, Fvector &fire_pos, Fvector &fire_dir) { CWeapon *weapon = smart_cast<CWeapon*>(inventory().ActiveItem()); if(weapon) { fire_pos = weapon->get_LastFP(); } else { const CMissile *pMissile = smart_cast <const CMissile*> (pHudItem); if (pMissile) { fire_pos = Actor()->Position(); fire_pos.y += 1.24f; } } fire_dir = Cameras().Direction(); } Переработка кода: ForserX P.S. Местами код правился, для сокращения объёма этого сообщения, мог подтереть что-то важное. При нахождении ошибок прошу сообщать. Сообщение отредактировал ForserX - 30.12.2017, 15:10 -------------------- В армии по 01.07.2020. |
 
|
|
|
|
19.11.2017, 18:21
Сообщение
#22
|
|
Опытный Игрок Репутация: 5 Группа: Участник Сообщений: 65 Награды: 2 Регистрация: 03.05.2012 |
Отключаем Проверку CD-Key сервером:
Файл: xrGameSpyServer.cpp Строка:81 m_bCheckCDKey = game->get_option_i (*session_name,"public",0) != 0; Удаляем данную проверку, сохраняем файл. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// Разрешаем клиенту юзать на сервере cam_1 cam_2 cam_3 Файл: actor_mp_client.cpp Строка:35 void CActorMP::cam_Set (EActorCameras style) { if (style != eacFirstEye) return; CCameraBase* old_cam = cam_Active(); cam_active = style; old_cam->OnDeactivate(); cam_Active()->OnActivate(old_cam); } Удаляем данную проверку, сохраняем файл. Файл: actor_mp_client.h Строка:32 protected: virtual void cam_Set (EActorCameras style); Удаляем, сохраняем файл. |
 
|
|
19.11.2017, 22:10
Сообщение
#23
|
|
Почти Игроман Репутация: 91 Куратор темы Сообщений: 516 Регистрация: 19.07.2015 |
v2v3v4, стоило по поводу мультиплеера вот это добавить:
-------------------- В армии по 01.07.2020. |
 
|
|
16.12.2017, 13:56
Сообщение
#24
|
|
Опытный Игрок Репутация: 5 Группа: Участник Сообщений: 65 Награды: 2 Регистрация: 03.05.2012 |
Подключаем возможность вести стрельбу из БТР:
Файл:Car.cpp void CCar::UpdateCL ( ) под строкой с указателями m_memory->set_camera(m_car_weapon->ViewCameraPos(), m_car_weapon->ViewCameraDir(),m_car_weapon->ViewCameraNorm()); Добавляем следующее: if (OwnerActor() && HasWeapon() && m_car_weapon->IsActive()) { collide::rq_result& rq = HUD().GetCurrentRayQuery(); CCameraBase* C = active_camera; m_car_weapon->SetParam(CCarWeapon::eWpnDesiredPos, C->vPosition.add(C->vDirection.mul(rq.range))); } Далее следующий войд void CCar::detach_Actor() Добавляем строку: if (HasWeapon()) m_car_weapon->Action(CCarWeapon::eWpnFire, 0); на пример на следующей строке после HandBreak(); Файл:CarInput.cpp Здесь добавляем синхронизацию с какой нибудь клавишей и непосредственно саму стрельбу на клавишу ведения огня void CCar::OnKeyboardPress(int cmd) находим кейс case kDETECTOR: SwitchEngine(); break; //в чн\зп case kENGINE: SwitchEngine(); break; //тч И добавляем синхрон чтобы можно было пользоваться оружием если мы завели двигатель case kDETECTOR: SwitchEngine(); if (HasWeapon()) m_car_weapon->Action(CCarWeapon::eWpnActivate, b_engine_on); break; //в чн\зп case kENGINE: SwitchEngine(); if (HasWeapon()) m_car_weapon->Action(CCarWeapon::eWpnActivate, b_engine_on); break; //тч И чуть ниже добавляем сам кейс который переводит огонь из бтра на клавишу ведения огня case kWPN_FIRE: if (HasWeapon()) m_car_weapon->Action(CCarWeapon::eWpnFire, 1); break; Сообщение отредактировал v2v3v4 - 16.12.2017, 14:19 |
 
|
|
16.12.2017, 15:28
Сообщение
#25
|
|
Почти Мастер Репутация: 111 Группа: Участник Сообщений: 1158 Награды: 3 Регистрация: 07.08.2015 |
Подключаем возможность вести стрельбу из БТР: Полезная тема. Я малость в Лост-Альфа подсмотрел, когда делал подобное. Тест в ЗП: Сообщение отредактировал andreyholkin - 16.12.2017, 15:33 |
 
|
|
28.12.2017, 22:19
Сообщение
#26
|
|
Опытный Игрок Репутация: 5 Группа: Участник Сообщений: 65 Награды: 2 Регистрация: 03.05.2012 |
Правка позиции ведения огня для актора, т.к. она идет от центра камеры
Файл: Actor_Weapon.cpp Код void CActor::g_fireParams (const CHudItem* pHudItem, Fvector &fire_pos, Fvector &fire_dir)
{ CWeapon *weapon = smart_cast<CWeapon*>(inventory().ActiveItem()); if(weapon) { fire_pos = weapon->get_LastFP(); } else { const CMissile *pMissile = smart_cast <const CMissile*> (pHudItem); if (pMissile) { fire_pos = Actor()->Position(); fire_pos.y += 1.24f; } } fire_dir = Cameras().Direction(); } Сообщение отредактировал ForserX - 29.12.2017, 11:41
Причина редактирования: Форматирование
|
 
|
|
10.01.2018, 19:43
Сообщение
#27
|
|
Опытный Игрок Репутация: 5 Группа: Участник Сообщений: 65 Награды: 2 Регистрация: 03.05.2012 |
ЗП. Правка скорее для тех кто сделал нормальный вид от 2го лица, для того чтобы радар не обновлял позицию по камере а обновлял её по управляемой сущности, чтобы когда мы крутим камерой он не сходил с ума.
UIZoneMap.cpp CODE void CUIZoneMap::Update()
{ CActor* pActor = smart_cast<CActor*>( Level().CurrentViewEntity() ); if ( !pActor ) return; if ( !( Device.dwFrame % 4 ) && !IsGameTypeSingle() ) { string16 text_str; xr_strcpy( text_str, sizeof(text_str), "" ); CPda* pda = pActor->GetPDA(); if ( pda ) { u32 cn = pda->ActiveContactsNum(); if ( cn > 0 ) { xr_sprintf( text_str, sizeof(text_str), "%d", cn ); } } m_Counter_text.SetText( text_str ); } UpdateRadar( Level().CurrentControlEntity()->Position() ); float h, p; Device.vCameraDirection.getHP( h, p ); SetHeading( -h ); m_clock_wnd->TextItemControl()->SetText( InventoryUtilities::GetGameTimeAsString( InventoryUtilities::etpTimeToMinutes ).c_str() ); } |
 
|
|
14.01.2018, 23:45
Сообщение
#28
|
|
Почти Игроман Репутация: 91 Куратор темы Сообщений: 516 Регистрация: 19.07.2015 |
v2v3v4, правка по позиции ведения огня некорректна. Теперь огонь идёт не по прицелу.
-------------------- В армии по 01.07.2020. |
 
|
|
15.01.2018, 02:00
Сообщение
#29
|
|
Продвинутый геймер Репутация: 16 Группа: Участник Сообщений: 222 Награды: 3 Регистрация: 28.06.2016 |
v2v3v4, правка по позиции ведения огня некорректна. Теперь огонь идёт не по прицелу. ну правильно, "прицел" потому что нафиг не нужен) А в режиме прицеливания как себя ведёт? Или не влияет? Осталось ещё доделать чтобы ствол за мышкой гулял как в Арма 3, и правочка будет збс. Есть идеи как такое реализовать? |
 
|
|
15.01.2018, 09:17
Сообщение
#30
|
|
Опытный Игрок Репутация: 5 Группа: Участник Сообщений: 65 Награды: 2 Регистрация: 03.05.2012 |
v2v3v4, правка по позиции ведения огня некорректна. Теперь огонь идёт не по прицелу. ну правильно, "прицел" потому что нафиг не нужен) А в режиме прицеливания как себя ведёт? Или не влияет? Осталось ещё доделать чтобы ствол за мышкой гулял как в Арма 3, и правочка будет збс. Есть идеи как такое реализовать? Всё там гуд с прицелом, вот только лучше бы не по дирекции камеры а по узнаванию предмета на который мы смотрим(GetCurrentRayQuery()) сделать Не играл в арму 3, не пойму о чём речь... v2v3v4, правка по позиции ведения огня некорректна. Теперь огонь идёт не по прицелу. Ну, всё правильно, теперь нужно следить за тем где наше оружие находится, и не упёрлось ли оно стволом во что-либо, иначе мы будем стрелять в это что-либо. А так все пули летят в перекрестие. но чтобы было все точнее нужно крутить firepoint по CurrentRayQuery, но я пока не придумал, чуть позже модернизирую правку Скрины стрельбы с правкой: Скрины |
 
|
|
16.01.2018, 10:31
Сообщение
#31
|
|
Опытный Игрок Репутация: 5 Группа: Участник Сообщений: 65 Награды: 2 Регистрация: 03.05.2012 |
Добавляем возможность выбрать материал попадания для ножа:
Файл: WeaponKnife.cpp Войд: void CWeaponKnife::Load (LPCSTR section) Параметр knife_material_idx удаляем всё что после '=' и вставляем туда: GMLib.GetMaterialIdx(pSettings->r_string(section,"material")); чтобы получилось вот так: knife_material_idx = GMLib.GetMaterialIdx(pSettings->r_string(section,"material")); Всё, теперь чтобы выбрать материал ножа нужно в его конфиге прописать: material = путь к материалу из .xr файла |
 
|
|
16.01.2018, 11:12
Сообщение
#32
|
|
Опытный Игрок Репутация: 5 Группа: Участник Сообщений: 65 Награды: 2 Регистрация: 03.05.2012 |
Аналогичная правка и для секций патронов, таким образом можно создать звуки, партиклы, воллмарки попадания разных видов патронов, как разрывных, так и футуристических, без использования флага explosive создать разрывной тип патронов, не только с партиклом, но и с соответствующим звуком и для всех видов материалов.
Файл: WeaponAmmo.cpp Войд: void CCartridge::Load(LPCSTR section, u8 LocalAmmoType) Параметр: bullet_material_idx После знака '=' удаляем весь текст в этой строке. Добавляем вместо него: GMLib.GetMaterialIdx(pSettings->r_string(section,"material")); Чтобы получилось: bullet_material_idx = GMLib.GetMaterialIdx(pSettings->r_string(section,"material")); Теперь в конфиге секций патронов прописываем: material = путь к материалу из .xr файла |
 
|
|
26.02.2018, 19:42
Сообщение
#33
|
|
Игрок Репутация: 2 Группа: Участник Сообщений: 38 Награды: 1 Регистрация: 24.05.2016 |
Привет всем, ребят я новичок в программировании, может кто нибудь скинуть инструкцию как добавить тени от ГГ заранее спасибо. Движок ЧН
Сообщение отредактировал ZveroBoy95rus - 26.02.2018, 19:43 |
 
|
|
26.02.2018, 21:05
Сообщение
#34
|
|
Почти Игроман Репутация: 91 Куратор темы Сообщений: 516 Регистрация: 19.07.2015 |
ZveroBoy95rus, отсюда возьми:
-------------------- В армии по 01.07.2020. |
 
|
|
22.06.2018, 14:46
Сообщение
#35
|
|
Почти Игроман Репутация: 91 Куратор темы Сообщений: 516 Регистрация: 19.07.2015 |
Исправление CUICellContainer::GetCellsInRange:
CODE
Diff: Сообщение отредактировал ForserX - 24.06.2018, 01:40 -------------------- В армии по 01.07.2020. |
 
|
|
18.08.2018, 01:33
Сообщение
#36
|
|
Игрок Репутация: 2 Группа: Участник Сообщений: 38 Награды: 1 Регистрация: 24.05.2016 |
И еще раз здравствуйте, интересуют вопросы касаемо ЧН, их несколько: во первых есть ли у кого нибудь исходники фикса на правильный ход солнца для ЧН и можно ли где нибудь посмотреть хотя бы пример того как можно добавить поддержку скриптов в мультиплеере?)
|
 
|
|
18.08.2018, 14:15
Сообщение
#37
|
|
Почти Игроман Репутация: 91 Куратор темы Сообщений: 516 Регистрация: 19.07.2015 |
Тут под PVS гонял и заметил такой косяк. во первых есть ли у кого нибудь исходники фикса на правильный ход солнца Окси, файл GamePersistent.cpp, ищи GAME_EXTRA_DYNAMIC_SUN -------------------- В армии по 01.07.2020. |
 
|
|
18.08.2018, 15:39
Сообщение
#38
|
|
Почти Мастер Репутация: 374 Группа: Участник Сообщений: 1073 Награды: 3 Регистрация: 26.09.2010 |
как можно добавить поддержку скриптов в мультиплеере?) Скрипты работают. Можешь включить биндер. script_binder.cpp:169 -------------------- |
 
|
|
13.11.2018, 04:18
Сообщение
#39
|
|
. Репутация: 750 Группа: Участник Сообщений: 7072 Награды: 4 Регистрация: 30.07.2010 |
Исходники правки мерцающих источников света на Р2:
Материнскую плату на socket A я так и не получил, увы. |
 
|
|
13.11.2018, 04:37
Сообщение
#40
|
|
Доктор Игровых Наук Репутация: 1084 Группа: Участник Сообщений: 3950 Награды: 6 Регистрация: 24.08.2010 |
Извини шадовс, но после лост альфы я уже не могу играть в эти кордоны, пойдешь на север через свалку 10 часов
Modera, могу скинуть на доширак премиум -------------------- |
 
|
|
13.11.2018, 15:42
Сообщение
#41
|
|
Pro gamer
Почти Игроман Репутация: 72 Группа: Участник Сообщений: 622 Регистрация: 05.11.2017 |
А в чём заключается правка?
|
 
|
|
Текстовая версия | Сейчас: 18.04.2024, 13:52 |