Перейти в начало страницы

Здравствуйте, гость ( Авторизация | Регистрация )

Gameru.net останавливает работу в связи с вторжением армии РФ в Украину. Следите за дальнейшими анонсами.
Support Gameru!

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

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

> Исходники правок, Различные исходники правок, собранные с форумов
ForserX
сообщение 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;
}

Здесь я оставил только добавление статика, на самом деле в ЗП с помощью этого инструмента можно все что угодно добавлять. Переносите себе по мере необходимости 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"

На этом всё smile.gif . Собственно у меня по такой схеме сделаны все подобные иконки, потому что система ТЧ показалась мне неоправданно сложной и громоздкой. Ну, быть может, это на мой дилетантский взгляд. 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 и пускай себе стоит 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


--------------------

В армии по 01.07.2020.
Перейти в начало страницы
 
3 страниц V   1 2 3 >  
Начать новую тему
Ответов
Stalker_Monolit
сообщение 03.02.2017, 00:48
Сообщение #2


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

Репутация:   17  
Группа: Участник
Сообщений: 161
Награды: 3
Регистрация: 08.03.2015




Вставить ник Цитировать выделенное в форуму быстрого ответа


Клац
Цитата(Forser @ 02.02.2017, 20:42) *
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 я поставил средние значения


В зп тоже работает я тогда не упомянул об этом biggrin1.gif
к стати r2_sun_depth_near_scale = 1.f и r2_sun_depth_near_bias = 0.f
а так все нормально выглядит попробовал на нескольких ПК пропало как и не бывало FPS от этого не проседает.

Сообщение отредактировал Stalker_Monolit - 03.02.2017, 00:50


--------------------

Перейти в начало страницы
 
Shoкer
сообщение 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 игры до правки и после правки), ну и есть шанс что описанная "проблема" вернётся в момент перехода объектов в оффлайн, но словить такое в игре будет трудно.


--------------------
Мне просто нравятся синие буквы под сообщением.
Перейти в начало страницы
 
Vampir35
сообщение 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);
};



--------------------
Перейти в начало страницы
 
alundaio
сообщение 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:
https://github.com/revolucas/xray-16/commit...71c6ff5a119e041
https://github.com/revolucas/xray-16/commit...05de2b2a35c4c90
https://github.com/revolucas/xray-16/commit...1f995b57572ca06
https://github.com/revolucas/xray-16/commit...dc93749d114e8a7

Сообщение отредактировал alundaio - 07.02.2017, 03:57
Перейти в начало страницы
 
Vampir35
сообщение 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;
}

Здесь я оставил только добавление статика, на самом деле в ЗП с помощью этого инструмента можно все что угодно добавлять. Переносите себе по мере необходимости 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"

На этом всё smile.gif . Собственно у меня по такой схеме сделаны все подобные иконки, потому что система ТЧ показалась мне неоправданно сложной и громоздкой. Ну, быть может, это на мой дилетантский взгляд. 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 и пускай себе стоит 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

На этом всё. Правда я не проверял, что будет, если скрипта или функции не существует.


Сообщение отредактировал Vampir35 - 07.02.2017, 15:11


--------------------
Перейти в начало страницы
 
Vampir35
сообщение 07.02.2017, 15:47
Сообщение #7


Ветеран
*****

Репутация:   5  
Группа: Участник
Сообщений: 82
Награды: 2
Регистрация: 11.07.2014




Вставить ник Цитировать выделенное в форуму быстрого ответа


Цитата(Forser @ 07.02.2017, 16:16) *
Да там по хорошему достаточно:
Код
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()



--------------------
Перейти в начало страницы
 
aka_sektor
сообщение 07.02.2017, 18:44
Сообщение #8


Грандмастер
**************

Репутация:   118  
Группа: Участник
Сообщений: 1788
Награды: 4
Регистрация: 04.04.2013




Вставить ник Цитировать выделенное в форуму быстрого ответа


Интересно. Нужная тема однако.
Ещё бы найти актуальные инструкции по сборке движков.

Я вот знаю такие:
http://chernobyl-soul.com/load/1/x_ray_src..._e_r/8-1-0-8288
http://stalkerin.gameru.net/wiki/index.php...ка_движка_X-Ray

Но не в курсе насколько они актуальны.

Сообщение отредактировал aka_sektor - 07.02.2017, 18:53


--------------------


Те кто играют уже не забудут ​​​​​​​© Алексей Сытянов
Перейти в начало страницы
 
Vampir35
сообщение 07.02.2017, 20:41
Сообщение #9


Ветеран
*****

Репутация:   5  
Группа: Участник
Сообщений: 82
Награды: 2
Регистрация: 11.07.2014




Вставить ник Цитировать выделенное в форуму быстрого ответа


Сборка исходников SHoC

Это сложно назвать какой-то инструкцией, скорее описание того как это делаю я, на правильность не претендую, но у меня работает. smile.gif
Итак, для сборки исходников, нам нужно, для начала, их скачать. Я лично работаю на репозитории xp-dev, собственно альтернативы, которые в открытом доступе довольны печальны. Я лично "форкнулся" с r-180 потому что дальше там пошли какие то баги и непонятности, а так выбирать можно ревизию, собственно, любую, какую душе угодно.
Дальнейшая статья будет относится именно к этому репо.
Итак, скачать исходники можно: https://xp-dev.com/sc/204486/HEAD/
Для скачивания нам понадобится TorotoiseSVN. Найти можно на официальном сайте.
Ссылка, которую нужно будет вставлять:
https://xp-dev.com/svn/xray
Как скачать исходники с помощью 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» теперь находится локальная версия репозитория (рабочая копия).
Полная версия инструкции - https://www.easycoding.org/2010/02/27/rabot...ortoisesvn.html

Итак, теперь мы имеем на руках исходники. Для сборки нам понадобится установить на ПК:
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
Скорее всего, можно и по другому, этот порядок у меня сложился эмперически и вникать в настройки проекта мне пока банально лень: собирается и ладно.
Собственно на этом всё. smile.gif


--------------------
Перейти в начало страницы
 
Stalker_Monolit
сообщение 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


--------------------

Перейти в начало страницы
 
macron
сообщение 09.02.2017, 20:23
Сообщение #11


Игровой Бог
**********************

Репутация:   1690  
Группа: Участник
Сообщений: 7021
Награды: 11
Регистрация: 22.02.2006




Вставить ник Цитировать выделенное в форуму быстрого ответа


Наткнулся на статью Ищем аномалии в X-Ray Engine
Перейти в начало страницы
 
Vampir35
сообщение 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


--------------------
Перейти в начало страницы
 
NanoBot-AMK
сообщение 16.04.2017, 14:00
Сообщение #13


Почти Мастер
***********

Репутация:   75  
Группа: Участник
Сообщений: 1168
Награды: 4
Регистрация: 10.11.2015




Вставить ник Цитировать выделенное в форуму быстрого ответа


Цитата(Forser @ 02.02.2017, 20:48) *
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


--------------------
СТАЛКЕР только для ПК!
Перейти в начало страницы
 
NanoBot-AMK
сообщение 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


--------------------
СТАЛКЕР только для ПК!
Перейти в начало страницы
 
NanoBot-AMK
сообщение 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


--------------------
СТАЛКЕР только для ПК!
Перейти в начало страницы
 
aka_sektor
сообщение 25.06.2017, 23:36
Сообщение #16


Грандмастер
**************

Репутация:   118  
Группа: Участник
Сообщений: 1788
Награды: 4
Регистрация: 04.04.2013




Вставить ник Цитировать выделенное в форуму быстрого ответа


Forser, думаю стоит добавить про восстановление меню перехода между уровнями в ЗП: http://ap-pro.ru/forum/21-11239-1050643-16-1498399073


--------------------


Те кто играют уже не забудут ​​​​​​​© Алексей Сытянов
Перейти в начало страницы
 
Vampir35
сообщение 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


--------------------
Перейти в начало страницы
 
ForserX
сообщение 01.08.2017, 16:05
Сообщение #18


Почти Игроман
*********

Репутация:   91  
Куратор темы
Сообщений: 516
Регистрация: 19.07.2015




Вставить ник Цитировать выделенное в форуму быстрого ответа


[COP]
Глитч камеры при перезарядке (автор qweasdd136963)


--------------------

В армии по 01.07.2020.
Перейти в начало страницы
 
SkyLoader
сообщение 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, то добавить аналогично и для него.
Перейти в начало страницы
 
ForserX
сообщение 19.11.2017, 15:38
Сообщение #20


Почти Игроман
*********

Репутация:   91  
Куратор темы
Сообщений: 516
Регистрация: 19.07.2015




Вставить ник Цитировать выделенное в форуму быстрого ответа


Такой момент весёлый нашёл.
https://github.com/ForserX/xray-oxygen/comm...7001aa1d02f0b12

Просто правильно настраивайте class в item.ltx


--------------------

В армии по 01.07.2020.
Перейти в начало страницы
 

3 страниц V   1 2 3 >
Ответить в данную темуНачать новую тему
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 



Текстовая версия Сейчас: 28.03.2024, 19:55