IPB

Помощь по разделу

Сайт S.T.A.L.K.E.R. Inside / [ЗП] Параметры командной строки / Распаковщик ресурсов

>

Исходники правок

, Различные исходники правок, собранные с форумов

 
 ForserX
сообщение 02.02.2017, 20:44
Сообщение #21


Продвинутый геймер
********

Куратор темы
Сообщений: 249
Регистрация: 19.07.2015
Из: Москва
Пользователь №: 22151



Ковыряясь на форумах находил много интересных постов, касательно готовых исходников правок. Сейчас появилось свободное время, в связи с чем решил собрать их в этой теме. Конечно же, тут собрано не всё, в ближайшее время(возможно) будет дополнено. Большая часть правок портируется под другие версии, так что, если я не написал вариант для используемой вами платформы, вы можете попробовать сделать порт сами. Особенно это относится к 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;
}

Здесь я оставил только добавление статика, на самом деле в ЗП с помощью этого инструмента можно все что угодно добавлять. Переносите себе по мере необходимости (IMG:style_emoticons/default/smile.gif) , идем дальше.
Нам нужен файл 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"

На этом всё (IMG:style_emoticons/default/smile.gif) . Собственно у меня по такой схеме сделаны все подобные иконки, потому что система ТЧ показалась мне неоправданно сложной и громоздкой. Ну, быть может, это на мой дилетантский взгляд. (IMG:style_emoticons/default/smile.gif)
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 и пускай себе стоит (IMG:style_emoticons/default/smile.gif) .
Теперь в 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:
Глитч камеры при перезарядке
v2v3v4:
Правка позиции ведения огня для актора
Правка позиции ведения огня для актора, т.к. она идет от центра камеры
Файл: 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
Перейти в начало страницы
 
 
 
Ответов
 v2v3v4
сообщение 19.11.2017, 18:21
Сообщение #22


Опытный Игрок
****

Группа: Участник
Сообщений: 55
Регистрация: 03.05.2012
Пользователь №: 14741



Отключаем Проверку 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);
Удаляем, сохраняем файл.
Перейти в начало страницы
 
 
 ForserX
сообщение 19.11.2017, 22:10
Сообщение #23


Продвинутый геймер
********

Куратор темы
Сообщений: 249
Регистрация: 19.07.2015
Из: Москва
Пользователь №: 22151



v2v3v4, стоило по поводу мультиплеера вот это добавить: https://github.com/OpenXRay/xray-16/commit/...d96d38d4ebe264b
Перейти в начало страницы
 
 
 v2v3v4
сообщение 16.12.2017, 13:56
Сообщение #24


Опытный Игрок
****

Группа: Участник
Сообщений: 55
Регистрация: 03.05.2012
Пользователь №: 14741



Подключаем возможность вести стрельбу из БТР:
Файл: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
Перейти в начало страницы
 
 
 Expropriator
сообщение 16.12.2017, 15:28
Сообщение #25


Опытный Геймер
*******

Группа: Участник
Сообщений: 187
Регистрация: 07.08.2015
Пользователь №: 22230



Цитата(v2v3v4 @ 16.12.2017, 15:56) *
Подключаем возможность вести стрельбу из БТР:

Полезная тема. Я малость в Лост-Альфа подсмотрел, когда делал подобное.
https://www.youtube.com/watch?v=osyTSDq-F1g&t=8s
Тест в ЗП:
https://yadi.sk/d/RWQuI76ysb2nY

Сообщение отредактировал andreyholkin - 16.12.2017, 15:33
Перейти в начало страницы
 
 
 v2v3v4
сообщение 28.12.2017, 22:19
Сообщение #26


Опытный Игрок
****

Группа: Участник
Сообщений: 55
Регистрация: 03.05.2012
Пользователь №: 14741



Правка позиции ведения огня для актора, т.к. она идет от центра камеры
Файл: 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
Причина редактирования: Форматирование
Перейти в начало страницы
 
 
 v2v3v4
сообщение 10.01.2018, 19:43
Сообщение #27


Опытный Игрок
****

Группа: Участник
Сообщений: 55
Регистрация: 03.05.2012
Пользователь №: 14741



ЗП. Правка скорее для тех кто сделал нормальный вид от 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() );
}
Перейти в начало страницы
 
 
 ForserX
сообщение 14.01.2018, 23:45
Сообщение #28


Продвинутый геймер
********

Куратор темы
Сообщений: 249
Регистрация: 19.07.2015
Из: Москва
Пользователь №: 22151



v2v3v4, правка по позиции ведения огня некорректна. Теперь огонь идёт не по прицелу.
Перейти в начало страницы
 
 
 mortan
сообщение 15.01.2018, 02:00
Сообщение #29


Геймер
******

Группа: Участник
Сообщений: 111
Регистрация: 28.06.2016
Из: Воронеж
Пользователь №: 24726



Цитата(ForserX @ 14.01.2018, 23:45) *
v2v3v4, правка по позиции ведения огня некорректна. Теперь огонь идёт не по прицелу.

ну правильно, "прицел" потому что нафиг не нужен)
А в режиме прицеливания как себя ведёт? Или не влияет?
Осталось ещё доделать чтобы ствол за мышкой гулял как в Арма 3, и правочка будет збс. Есть идеи как такое реализовать?
Перейти в начало страницы
 
 
 v2v3v4
сообщение 15.01.2018, 09:17
Сообщение #30


Опытный Игрок
****

Группа: Участник
Сообщений: 55
Регистрация: 03.05.2012
Пользователь №: 14741



Цитата(mortan @ 15.01.2018, 04:00) *
Цитата(ForserX @ 14.01.2018, 23:45) *
v2v3v4, правка по позиции ведения огня некорректна. Теперь огонь идёт не по прицелу.

ну правильно, "прицел" потому что нафиг не нужен)
А в режиме прицеливания как себя ведёт? Или не влияет?
Осталось ещё доделать чтобы ствол за мышкой гулял как в Арма 3, и правочка будет збс. Есть идеи как такое реализовать?

Всё там гуд с прицелом, вот только лучше бы не по дирекции камеры а по узнаванию предмета на который мы смотрим(GetCurrentRayQuery()) сделать
Не играл в арму 3, не пойму о чём речь...

Цитата(ForserX @ 15.01.2018, 01:45) *
v2v3v4, правка по позиции ведения огня некорректна. Теперь огонь идёт не по прицелу.

Ну, всё правильно, теперь нужно следить за тем где наше оружие находится, и не упёрлось ли оно стволом во что-либо, иначе мы будем стрелять в это что-либо.
А так все пули летят в перекрестие. но чтобы было все точнее нужно крутить firepoint по CurrentRayQuery, но я пока не придумал, чуть позже модернизирую правку

Скрины стрельбы с правкой:
Перейти в начало страницы
 
 
 v2v3v4
сообщение 16.01.2018, 10:31
Сообщение #31


Опытный Игрок
****

Группа: Участник
Сообщений: 55
Регистрация: 03.05.2012
Пользователь №: 14741



Добавляем возможность выбрать материал попадания для ножа:
Файл: 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 файла
Перейти в начало страницы
 
 
 v2v3v4
сообщение 16.01.2018, 11:12
Сообщение #32


Опытный Игрок
****

Группа: Участник
Сообщений: 55
Регистрация: 03.05.2012
Пользователь №: 14741



Аналогичная правка и для секций патронов, таким образом можно создать звуки, партиклы, воллмарки попадания разных видов патронов, как разрывных, так и футуристических, без использования флага 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 файла
Перейти в начало страницы
 
 
 ZveroBoy95rus
сообщение 26.02.2018, 19:42
Сообщение #33


Новичок
*

Группа: Участник
Сообщений: 6
Регистрация: 24.05.2016
Пользователь №: 24533



Привет всем, ребят я новичок в программировании, может кто нибудь скинуть инструкцию как добавить тени от ГГ заранее спасибо. Движок ЧН

Сообщение отредактировал ZveroBoy95rus - 26.02.2018, 19:43
Перейти в начало страницы
 
 
 ForserX
сообщение 26.02.2018, 21:05
Сообщение #34


Продвинутый геймер
********

Куратор темы
Сообщений: 249
Регистрация: 19.07.2015
Из: Москва
Пользователь №: 22151



ZveroBoy95rus, отсюда возьми: https://github.com/xrOxygen/xray-oxygen/com...572fc1741d24e85
Перейти в начало страницы
 
 
 ForserX
сообщение 22.06.2018, 14:46
Сообщение #35


Продвинутый геймер
********

Куратор темы
Сообщений: 249
Регистрация: 19.07.2015
Из: Москва
Пользователь №: 22151



Исправление CUICellContainer::GetCellsInRange:
CODE
u32 CUICellContainer::GetCellsInRange(const Irect& rect, UI_CELLS_VEC& res)
{
res.clear();
for (int x = rect.x1; x <= rect.x2; ++x)
for (int y = rect.y1; y <= rect.y2; ++y)
res.push_back(GetCellAt(Ivector2().set(x, y)));
// ForserX: Fixed std::unique using.
xr_vector<CUICell>::iterator last = std::unique(res.begin(), res.end());
res.erase(last, res.end());

return (u32)res.size();
}


Diff: https://github.com/xrOxygen/xray-oxygen/com...930890b11563bb1

Сообщение отредактировал ForserX - 24.06.2018, 01:40
Перейти в начало страницы
 
 
 
 

 
2 чел. читают эту тему (гостей: 2, скрытых пользователей: 0)
Пользователей: 0

 

Текстовая версия Сейчас: 23.07.2018, 20:43