Исходники правок, Различные исходники правок, собранные с форумов |
Здравствуйте, гость ( Авторизация | Регистрация )
Сайт S.T.A.L.K.E.R. Inside / [ЗП] Параметры командной строки / Распаковщик ресурсов
Исходники правок, Различные исходники правок, собранные с форумов |
02.02.2017, 20:44
Сообщение
#1
|
|
Почти Игроман Репутация: 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. |
 
|
|
|
|
03.02.2017, 00:48
Сообщение
#2
|
|
Опытный Геймер Репутация: 17 Группа: Участник Сообщений: 161 Награды: 3 Регистрация: 08.03.2015 |
Клац 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 я поставил средние значения В зп тоже работает я тогда не упомянул об этом к стати r2_sun_depth_near_scale = 1.f и r2_sun_depth_near_bias = 0.f а так все нормально выглядит попробовал на нескольких ПК пропало как и не бывало FPS от этого не проседает. Сообщение отредактировал Stalker_Monolit - 03.02.2017, 00:50 -------------------- |
 
|
|
03.02.2017, 03:00
Сообщение
#3
|
|
Кандидат Игровых Наук Репутация: 2153 Группа: Участник Сообщений: 3488 Награды: 4 Регистрация: 27.07.2009 |
Цитата В файле xrGame\Level_network.cpp в начале функции void CLevel::ClientSend() Перед проверкой GameID() == eGameIDSingle нужно поставить отрицание: Код if (GameID() != eGameIDSingle || OnClient()) Тогда при сохранении игры для всех клиентских объектов будет вызываться net_Export (клиентские объекты будут синхронизироваться с серверным чётко при сохранении) Лучше использовать: if (GameID() != eGameIDSingle && OnClient()) Иначе получается что мы включаем эту проверку ещё и для сервера в МП. Вообще в идеале эту правку стоит доработать. Сделать что то вроде: Код bool bSkipBandwithCheck = (GameID() == eGameIDSingle && "мы_сейчас_сохраняем_игру") if (bSkipBandwithCheck == false || OnClient()) ... Это более правильно с точки зрения оптимизации, правда думаю там максимум 1-2 FPS разницы будет (нужно сравнить FPS игры до правки и после правки), ну и есть шанс что описанная "проблема" вернётся в момент перехода объектов в оффлайн, но словить такое в игре будет трудно. -------------------- Мне просто нравятся синие буквы под сообщением.
|
 
|
|
04.02.2017, 21:04
Сообщение
#4
|
|
Ветеран Репутация: 5 Группа: Участник Сообщений: 82 Награды: 2 Регистрация: 11.07.2014 |
SHoC. Функция перемотки времени из CoP, используется, к примеру, для сна. xrGame: level_script.cpp: В начала файла, перед: Код 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); }; -------------------- |
 
|
|
07.02.2017, 03:17
Сообщение
#5
|
|
Новичок Репутация: 5 Группа: Участник Сообщений: 8 Регистрация: 07.02.2017 |
Hello friends, forgive me for I do not speak Russian. I have just discovered this thread and would like to thank all contributors for these fixes, it's wonderful.
I have some fixes I can contribute as well (1.6.02 maybe others), ------------------------ Fix 1: Fix inaccessible call in ai_stalker.cpp for inherited::inherited::schedule_Update(dt) ------------------------ In CustomMonster.h private needs renamed to protected: protected: typedef CEntityAlive inherited; In entity_alive.h protected needs added: protected: typedef CEntity inherited; private: Why are these changes necessary? Look at ai_stalker.cpp: inherited::inherited::shedule_Update(DT); inherited is inaccessible, compiler does not give error and instead calls CCustomMonster::schedule_Update(dt) which is BAD! Stalkers are essentially updating twice! --------------------- Fix 2: Fix inaccessible call in ActorEffector.cpp for inherited::inherited::ProcessCam(info). It is the cause of glitchy *.anm --------------------- In ActorEffector.h: protected: typedef CCameraManager inherited; private: CAnimatorCamEffector::ProcessCam() being incorrectly called because 2nd inherited inaccessible in ActorEffector.cpp. It should call CEffectorCam::ProcessCam(info). ---------------------------------------------------------------- Shout out to Shoker whose question I saw about this today on GitHUB and made me realize this problem. Here are some other 1.6.02 corrections: Сообщение отредактировал alundaio - 07.02.2017, 03:57 |
 
|
|
07.02.2017, 15:15
Сообщение
#6
|
|
Ветеран Репутация: 5 Группа: Участник Сообщений: 82 Награды: 2 Регистрация: 11.07.2014 |
По поводу фикса полосы загрузки, в ТЧ надо еще добавить:
Код typedef IGame_Persistent::params params; params &p = g_pGamePersistent->m_game_params; Т.е вот так будет как-то: Код typedef IGame_Persistent::params params; params &p = g_pGamePersistent->m_game_params; if (g_pGamePersistent->GameType()==1 && !xr_strcmp(p.m_alife,"alife")) max_load_stage = 17; else max_load_stage = 14; 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. Создание нового слота Я использую ревизию с 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 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 На этом всё. Правда я не проверял, что будет, если скрипта или функции не существует. Сообщение отредактировал Vampir35 - 07.02.2017, 15:11 -------------------- |
 
|
|
07.02.2017, 15:47
Сообщение
#7
|
|
Ветеран Репутация: 5 Группа: Участник Сообщений: 82 Награды: 2 Регистрация: 11.07.2014 |
Да там по хорошему достаточно: Код if (g_pGamePersistent->GameType()==1) Имхо Не спорю. Это я добавил, чтобы работало: !xr_strcmp(p.m_alife,"alife")) Функции, возвращающие текущий год и месяц. Небольшое расширение пространства level для SHoC. тык Совсем мелочь, но мне понадобилось, мб ещё кому-то будет надо. В SHoC существует три функции, для возврата игрового времени, в пространстве level: Код get_time_days() -- день get_time_hours() -- час get_time_minutes() -- минута Собственно, для своих целей я добавил аналогичные функции, которые возвращают текущий месяц и год. level_script.cpp: Перед: Код u32 get_time_days() { 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 day; } добавим: Код u32 get_time_year() { 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 year; } u32 get_time_month() { 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 month; } и перед: Код def("get_time_days", get_time_days), добавим: Код def("get_time_year", get_time_year), def("get_time_month", get_time_month), На этом - всё, использовать в своих скриптах, вот так: Код local year = level.get_time_year() local month = level.get_time_month() -------------------- |
 
|
|
07.02.2017, 18:44
Сообщение
#8
|
|
Грандмастер Репутация: 118 Группа: Участник Сообщений: 1788 Награды: 4 Регистрация: 04.04.2013 |
Интересно. Нужная тема однако.
Ещё бы найти актуальные инструкции по сборке движков. Я вот знаю такие: http://stalkerin.gameru.net/wiki/index.php...ка_движка_X-Ray Но не в курсе насколько они актуальны. Сообщение отредактировал aka_sektor - 07.02.2017, 18:53 -------------------- |
 
|
|
07.02.2017, 20:41
Сообщение
#9
|
|
Ветеран Репутация: 5 Группа: Участник Сообщений: 82 Награды: 2 Регистрация: 11.07.2014 |
Сборка исходников SHoC Это сложно назвать какой-то инструкцией, скорее описание того как это делаю я, на правильность не претендую, но у меня работает. Итак, для сборки исходников, нам нужно, для начала, их скачать. Я лично работаю на репозитории xp-dev, собственно альтернативы, которые в открытом доступе довольны печальны. Я лично "форкнулся" с r-180 потому что дальше там пошли какие то баги и непонятности, а так выбирать можно ревизию, собственно, любую, какую душе угодно. Дальнейшая статья будет относится именно к этому репо. Итак, скачать исходники можно: Для скачивания нам понадобится TorotoiseSVN. Найти можно на официальном сайте. Ссылка, которую нужно будет вставлять: Как скачать исходники с помощью TorotoiseSVN Создаём папку, в которую будем скачивать репозитории (для удобства лучше хранить все репозитории в одной папке, например, C:\SVN). Заходим в неё в проводнике Windows, нажимаем правой кнопкой мыши по свободному месту и выбираем «SVN Checkout…«. В поле «URL of repository» пишем полный URL до репозитория SVN, который нам нужно скачать, а в поле «Checkout directory» корректируем путь, в которой будет помещена локальная копия. Внимание! Вам нужно делать checkout только каталога /trunk/ svn-репозитория, либо корневого, если /trunk/ не существует (очень редко, т.к. в 99% репозиториев trunk существует и содержит всегда самую последнюю версию файлов). В списке «Checkout Depth» укажите «Fully recursive«, что означает, что будет скачан весь репозиторий от указанного пути. Если установить флажок «Omit externals«, то внешние файлы, на которые есть ссылки в репозитории (например, из других репозиториев, либо репозиториев третьих лиц), скачаны не будут, поэтому ставить флажок здесь не рекомендуется. В блоке «Revision» Вы можете запросить выдать Вам последнюю версию репозитория: «HEAD revision» (рекомендуется именно этот вариант), либо указанную Вам в поле ревизию: «Revision ###» (не рекомендуется). Кнопка «Show log» покажет Вам список изменений в репозитории с информацией об авторах каждого изменения, описании изменений (если авторы их вводили при коммите изменений), а также списке добавленных, изменённых и удалённых файлов. Здесь же можно просмотреть чем файл одной ревизии (версии) отличается от файла другой, а также запросить показать унифицированный diff-файл изменений либо нескольких файлов, либо нескольких ревизий (отображается только для текстовых файлов). Более подробную информацию о Log Viewer читайте ниже. Нажимаем кнопку «OK» и ждём скачивания репозитория с Subversion-сервера (зависит от скорости Вашего Интернет-соединения, а также от загруженности svn-сервера). Внимание! Некоторые svn-серверы могут запросить пароль. Если Вы не знаете пароля, то вводите anonsvn как логин и пароль. Это стандартный логин/пароль для анонимного доступа. Если Вы хотите в дальнейшем публиковать свои изменения в этот репозиторий и у Вас есть на это право, то введите здесь свой логин и пароль. Готово. В каталоге, который Вы указали на третьем шаге в поле «Checkout directory» теперь находится локальная версия репозитория (рабочая копия). Полная версия инструкции - Итак, теперь мы имеем на руках исходники. Для сборки нам понадобится установить на ПК: 1. Visual Studio 2010 (НЕ Express Version, у меня, по моему pro) 2. Visual Studio 2010 Service Pack 1 3. DirectX SDK June 2010. Я не уверен в необходимости его установки, но в изначальной инструкции он был. 4. DirectX SDK June 2007. Если ставили 2010, то 2007 ОБЯЗАТЕЛЬНО нужно ставить после 10. 5. Windows SDK 6. Скорее всего, понадобятся также некоторые dll из 6 патча: wrap_oal.dll, eax.dll, OpenAl32.dll (или же установить его). Для вашей звуковой карты, возможно придётся подобрать оптимальную комбинацию. У меня даже xrSound.dll какое-то время была от 1.0006. Как только мы установили всё это, открываем студию, ставим Solution Configurations - Release (насколько помню, дебаговая версия с репо не собирается) Все, дальше идет сборка, делать build\build solution я не советую, для этого проект, скорее всего придется отдельно настраивать. Я лично собираю библиотеки по очереди в таком порядке: 1. libogg_static 2. libtheora_static 3. libvorbis_static 4. libvorbisfile 5. nvtt 6. ode 7. xrD3D9-Null 8. LuaJIT 9. xrCore 10. Luabind 11. xrCDB 12. xrGameSpy 13. xrParticles 14. xrSound 15. xrXMLParser 16. xrNetServer 17. XR_3DA 18. xrCPU_Pipe 19. xrRender_R1 20. xrRender_R2 21. xrGame Скорее всего, можно и по другому, этот порядок у меня сложился эмперически и вникать в настройки проекта мне пока банально лень: собирается и ладно. Собственно на этом всё. -------------------- |
 
|
|
08.02.2017, 05:52
Сообщение
#10
|
|
Опытный Геймер Репутация: 17 Группа: Участник Сообщений: 161 Награды: 3 Регистрация: 08.03.2015 |
ЧН Фикс количества группировок в ПДА с 9 на 18
Клац В файл UIRankingWnd.h надо CODE max_factions = 9 поменять на: CODE max_factions = 18 Посмотрел в X-Ray of Hope -------------------- |
 
|
|
09.02.2017, 20:23
Сообщение
#11
|
|
Игровой Бог Репутация: 1690 Группа: Участник Сообщений: 7021 Награды: 11 Регистрация: 22.02.2006 |
Наткнулся на статью
|
 
|
|
16.02.2017, 21:19
Сообщение
#12
|
|
Ветеран Репутация: 5 Группа: Участник Сообщений: 82 Награды: 2 Регистрация: 11.07.2014 |
Фикс сохранения клиентских объектов от Шокера, вариант для ТЧ:
Код if (GameID() != GAME_SINGLE && OnClient()) Догадаться не сложно, но всё же отличие в названии переменной имеется, пусть будет). ---***---***--- Карлан упоминал, вспомнил вот. Ошибка-опечатка в оригинальном репозитории xp-dev в колбеке на before save (вызывается перед созданием сейва, насколько я понял), точно есть с r180 и до финальной так и осталось. script_game_object_script.cpp: находим: Код value("on_before_save", int(GameObject::ePostSave)), и заменяем на: Код value("on_before_save", int(GameObject::eBeforeSave)),
Сообщение отредактировал Vampir35 - 16.02.2017, 22:18 -------------------- |
 
|
|
16.04.2017, 14:00
Сообщение
#13
|
|
Почти Мастер Репутация: 75 Группа: Участник Сообщений: 1168 Награды: 4 Регистрация: 10.11.2015 |
virtual int GetCurrentFireMode() { return m_bHasDifferentFireModes ? m_aFireModes[m_iCurFireMode] : 1; }; Стой, моя правка решается более сложно, так не заработает как надо. Так же были проблемы когда НПС стреляли из двухстволки дуплетом, и ещё некоторые другие проблемы. Пришлось вот решать, метод SetQueueSize блокирует не правильные размеры очереди, для пистолетов, например, можно задать только 0 и 1, всё остальное блокируется. Скриптовый метод так же на этот метод должен ссылаться. Метод OnH_A_Chield вызывается когда кто-то подбирает оружие, а так же при переходе в онлайн и создании объекта. И ещё тут есть код регулируемая скорострельность, сделано для Абакана. highfire_queue - размер очереди когда включён высокий темп стрельбы, для Абакана = 2, для "забыл как называется" = 3. rpm_high - высокий темп стрельбы, для Абакана = 1800, для "забыл как называется" = 900. rpm - нормальный режим стрельбы, для Абакана = 600, для "забыл как называется" = 600. код CODE void CWeaponMagazined::Load (LPCSTR section) ... else { m_bHasDifferentFireModes = false; // [7/21/2005] m_iQueueSize = 1; // размер очереди } // © NanoBot m_bAutoReload = READ_IF_EXISTS(pSettings, r_bool, section, "auto_reload", true); //Регулирумая скорострельность.(Абакан) © NanoBot m_bHighFire = false; if(pSettings->line_exist(section, "highfire_queue")) { m_bHighFire = true; m_iHighfireQueue = pSettings->r_s32(section, "highfire_queue"); if(m_iHighfireQueue<WEAPON_ININITE_QUEUE) m_iHighfireQueue=WEAPON_ININITE_QUEUE; m_fTimeToFireHigh = 60.f/pSettings->r_float(section, "rpm_high"); m_fTimeToFireNormal = fTimeToFire; } } код CODE void CWeaponMagazined::OnH_A_Chield() { int queue_size = 1; if (m_bHasDifferentFireModes) { if (smart_cast<CActor*>(H_Parent())) queue_size = GetCurrentFireMode(); else // НПС всегда переключает на автоматический режим, если он есть, или на максимальную очередь. queue_size = (smart_cast<CWeaponBM16*>(this)) ? 1 : WEAPON_ININITE_QUEUE; // НПС из двухстволки дуплетом не стреляет } SetQueueSize(queue_size); inherited::OnH_A_Chield(); } void CWeaponMagazined::SetQueueSize(int size) { if(size<WEAPON_ININITE_QUEUE) size=WEAPON_ININITE_QUEUE; m_iCurFireMode = 0; int size_queue = 1; if(m_bHasDifferentFireModes) { for(u32 i = 0; i<m_aFireModes.size(); ++i) { m_iCurFireMode = i; size_queue = m_aFireModes[i]; if((size<=size_queue && size>=0) || size_queue==WEAPON_ININITE_QUEUE) { size_queue = size; // размер очереди может быть меньше или равным указаным в fire_modes break; } } } m_iQueueSize = size_queue; if(size==0 && size_queue) return; // вероятно блокировка оружия if (m_iQueueSize == WEAPON_ININITE_QUEUE) strcpy_s(m_sCurFireMode, " (A)"); else sprintf_s(m_sCurFireMode, " (%d)", m_iQueueSize); //Регулирумая скорострельность.(Абакан) © NanoBot if(m_bHighFire) if(m_iHighfireQueue==m_iQueueSize) fTimeToFire = m_fTimeToFireHigh; else fTimeToFire = m_fTimeToFireNormal; } Это для блокировки автоперезарядки, надо для некоторого однозарядного оружия. Блокировка перезарядки CODE void CWeaponMagazined::FireEnd() { inherited::FireEnd(); CActor *actor = smart_cast<CActor*>(H_Parent()); if (!iAmmoElapsed && actor && GetState() != eReload && m_bAutoReload) Reload(); } CODE void CWeaponMagazined::switch2_Empty() { if(m_bAutoReload) { OnZoomOut(); if (!TryReload()) OnEmptyClick(); else inherited::FireEnd(); } else inherited::FireEnd(); } Так же не забудьте зарегистрировать: код CODE //переменная блокирует использование //только разных типов патронов bool m_bLockType; <-- это оригинал, метка куда вставлять, файл WeaponMagazined.h bool m_bAutoReload; // блокировка автоперезарядки bool m_bHighFire; int m_iHighfireQueue; float m_fTimeToFireHigh; float m_fTimeToFireNormal; Сообщение отредактировал NanoBot-AMK - 16.04.2017, 14:29 -------------------- СТАЛКЕР только для ПК!
|
 
|
|
27.04.2017, 21:28
Сообщение
#14
|
|
Почти Мастер Репутация: 75 Группа: Участник Сообщений: 1168 Награды: 4 Регистрация: 10.11.2015 |
Ещё небольшая правка. В игре если попытаться взорвать методом explode() гранату то теряется инициатор, в результате в ТЧ в некоторых случаях вылетает, из-за того что у НПСа грохается логика, XRayExtensions не вылетает, но НПС зависает.
Находим файл script_game_object2.cpp и правим метод void CScriptGameObject::explode(u32 level_time) Заменяем это: код CODE explosive->SetInitiator(object().ID()); На это: код CODE explosive->SetInitiator(explosive->Initiator()); // устанавливаем инициатор только если он неизвестен. Теперь проблем с гранатами не будет. Править можно все сталкеры. Я использую это в скрипте "Гранаты с ударным запалом." ЗЫ Аналогичная правка для ТЧ в проекте XRayExtensions. Файл xrgame_stubs.asm код CODE ; explosive->SetInitiator(explosive->Initiator()); // устанавливаем инициатор только если он неизвестен. ;;;org 10250F40h - shift ;;;CExplosive__Initiator: Virtual_CExplosive__Initiator = dword ptr 4 ; виртуальный адрес ; ebx - explosive CExplosive* org 10141716h - shift ; 10 bytes mov edx, [ebx] ; virtual_CExplosive mov ecx, ebx call [edx+Virtual_CExplosive__Initiator] ; explosive->Initiator() movzx eax, ax Включаем в corrections_list.txt, другую мою правку надо удалить. ; возможность назначать инициатор функции explode. Пример: bomb:explode(initiator). Требуется адаптация скриптов, наличие параметра initiator обязательно!!! ;;;0x10141719 7 ;;;0x1014B311 5 0x10141716 10 ; в взрывном объекте устанавливаем инициатор только если он неизвестен (у гранат не изменяется). Сообщение отредактировал NanoBot-AMK - 27.04.2017, 21:44 -------------------- СТАЛКЕР только для ПК!
|
 
|
|
18.06.2017, 20:03
Сообщение
#15
|
|
Почти Мастер Репутация: 75 Группа: Участник Сообщений: 1168 Награды: 4 Регистрация: 10.11.2015 |
Не правильно работает гранатная прокрутка?
Решение. Grenade.cpp Код 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; } Заменить метод CGrenade::Action. Гранаты прокручиваются в алфавитном порядке, по имени секции. Правка для проекта Маландринуса и Ко. Я там, так же правил, использование гранат из рюкзака, или из пояса, в зависимости от настройки конфига, в оригинале не которые комитёры сделали это через через дефайн. Так что вот ещё правка в том же файле. Grenade.cpp Код 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; } } Что гораздо разумней. Сообщение отредактировал NanoBot-AMK - 18.06.2017, 20:19 -------------------- СТАЛКЕР только для ПК!
|
 
|
|
25.06.2017, 23:36
Сообщение
#16
|
|
Грандмастер Репутация: 118 Группа: Участник Сообщений: 1788 Награды: 4 Регистрация: 04.04.2013 |
Forser, думаю стоит добавить про восстановление меню перехода между уровнями в ЗП:
-------------------- |
 
|
|
27.06.2017, 00:03
Сообщение
#17
|
|
Ветеран Репутация: 5 Группа: Участник Сообщений: 82 Награды: 2 Регистрация: 11.07.2014 |
Исправление пулестойкости костюмов SHoC Кто-то слышал, кто-то нет, как разработчики некоторых глобальных модов упоминали (ну по крайней мере я что-то подобное помню), что в движок закралась какая-то чудовищная ошибка и на самом деле бронежилеты от пуль не защищают и чуть ли не чем больше показатель, тем хуже. Однако, в принципе, не так все страшно. На самом деле в этом плане никакой ошибки нет. Просто в Сталкере (речь идет о ТЧ, насчет других частей серии - не уверен, хотя суть та же скорее всего) расчет хита от пули происходит иначе, чем от любого другого воздействия. А конкретно, берутся настройки костей, что позволяет более гибко эту самую пулестойкость настроить. Подробнее можно почитать здесь. Пулестойкость ГГ рассчитывается также, как у НПС. На самом деле, это легко исправить. Возможно ,кому-то не понравится такой способ, ибо если выставить у костюма 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 Вот и всё, если есть какие-то вопросы - пишите, возможно, я забыл что-то указать. Сообщение отредактировал Vampir35 - 27.06.2017, 00:05 -------------------- |
 
|
|
01.08.2017, 16:05
Сообщение
#18
|
|
Почти Игроман Репутация: 91 Куратор темы Сообщений: 516 Регистрация: 19.07.2015 |
-------------------- В армии по 01.07.2020. |
 
|
|
06.08.2017, 14:52
Сообщение
#19
|
|
Почти Игроман Репутация: 153 Группа: Участник Сообщений: 614 Награды: 4 Регистрация: 03.05.2012 |
Исправление чтения векторов из user.ltx:
В xr_ioc_cmd.h в функции CCC_Vector3::Execute(LPCSTR args) Код if (3 != sscanf(args, "%f,%f,%f", &v.x, &v.y, &v.z)) { InvalidSyntax(); return; } Изменить так Код if ((3 != sscanf(args, "%f,%f,%f", &v.x, &v.y, &v.z)) && (3 != sscanf(args, "(%f, %f, %f)", &v.x, &v.y, &v.z)) ) { InvalidSyntax(); return; } Если в движке есть CCC_Vector4, то добавить аналогично и для него. |
 
|
|
19.11.2017, 15:38
Сообщение
#20
|
|
Почти Игроман Репутация: 91 Куратор темы Сообщений: 516 Регистрация: 19.07.2015 |
Такой момент весёлый нашёл.
Просто правильно настраивайте class в item.ltx -------------------- В армии по 01.07.2020. |
 
|
|
Текстовая версия | Сейчас: 29.03.2024, 17:28 |