Skocz do zawartości

Małe poprawki silnika [SoC]


Gość Diegtiariow

Rekomendowane odpowiedzi

Gość Diegtiariow

Na chwilę obecną temat jest skierowany do nowicjuszy. Tutaj będą zebrane gotowe rozwiązania dot. grzebania w kodach źródłowych silnika SoC. Właściwie zapraszam wszystkich do przyłączenia się.

 

TWORZENIE CALLBACK'ÓW DLA AKTORA NA PRZYKŁADZIE CALLBACK'A DŹGNIĘCIA NOŻEM:

Spoiler

Callback - to funkcja, która jest wywoływana przy określonej akcji, np. naciśnięcie klawisza, wystrzał z broni, śmierć aktora, itd.

Tworzenie takiego callback'a nie jest trudne. Rozważmy przykład tworzenia callback'ów na ciosy nożem na PPM i LPM. Żadne argumenty nie zostaną tu przekazane, tylko wywołanie funkcji przy ciosie. Więc.

1. W pliku WeaponKnife.cpp dodajemy na początek pliku po wszystkich include'ach jeszcze 4 include'y potrzebne dla callback'ów aktora:

#include "pch_script.h"
#include "script_callback_ex.h"
#include "script_game_object.h"
#include "alife_object_registry.h"

2. Dalej szukamy: void CWeaponKnife::switch2_Attacking (u32 state) i po:

m_pHUD->animPlay(random_anim(mhud_attack),        FALSE, this, state);

piszemy:

g_actor->callback(GameObject::eKnifeAttackOne)();

 

Analogicznie po:

m_pHUD->animPlay(random_anim(mhud_attack2),        FALSE, this, state);

piszemy:

g_actor->callback(GameObject::eKnifeAttackTwo)();

3. Nasze callback'i trzeba zarejestrować:

- w pliku: game_object_space.h dodajemy do listy callback'ów analogicznie na koniec:

eKnifeAttackOne,
eKnifeAttackTwo,

w script_game_object_script.cpp analogicznie jak u innych callback'ów dodajemy na koniec:

value("knife_attack_one", int(GameObject::eKnifeAttackOne) ),
value("knife_attack_two", int(GameObject::eKnifeAttackTwo) )

Warto tutaj trochę wyjaśnić: w cudzysłowie jest ten identyfikator, który rejestrujemy w bind_stalker.script. Rejestracja callback'a w bind_stalker.script.

 

Do funkcji:

function actor_binder:net_destroy()

dodajemy:

function actor_binder:reinit()

dodajemy też:

self.object:set_callback(callback.knife_attack_one, self.knife_attack_one, self)
self.object:set_callback(callback.knife_attack_two, self.knife_attack_two, self)

I dodajemy funkcje, które będą wywoływane po wykonaniu callback'a:

function actor_binder:knife_attack_one()
news_manager.send_tip(db.actor, "Cios LPM") --wiadomość dla testu
end
function actor_binder:knife_attack_two()
news_manager.send_tip(db.actor, "Cios PPM") --wiadomość dla testu
end

 

 

TWORZENIE FUNKCJI SORTUJĄCEJ PRZEDMIOTY NA PASIE:

Spoiler

Wiele ludzi spotkało się z funkcją iterate_inventory, która sortuje cały ekwipunek i dla każdego wywołuje funkcję. Jeśli potrzebujemy posortować wszystkie przedmioty na pasie, aby sprawdzić, czy jest tam jakiś przedmiot lub nie, można oczywiście, posortować cały ekwipunek i sprawdzać dla każdego przedmiotu na pasie czy on jest czy go nie ma. Ale można też stworzyć oddzielną funkcję, która będzie sortować tylko przedmioty na pasie.

 

1. W pliku: script_game_object_script3.cpp szukamy iterate_inventory i analogicznie robimy wariant dla pasa:

.def("iterate_inventory",        &CScriptGameObject::IterateInventory)
.def("iterate_belt",             &CScriptGameObject::IterateBelt)

 

Teraz w script_game_object.h rejestrujemy naszą funkcję:

void         IterateInventory    (luabind::functor<void> functor, luabind::object object);
void         IterateBelt     (luabind::functor<void> functor, luabind::object object);

 

I na koniec, w pliku script_game_object_inventory_owner.cpp dodajemy samą funkcję.

Znajdziecie funkcję dla inwentarza, zróbcie również.

void CScriptGameObject::IterateBelt    (luabind::functor<void> functor, luabind::object object)
{
    CInventoryOwner            *inventory_owner = smart_cast<CInventoryOwner*>(&this->object());
    if (!inventory_owner) {
        ai().script_engine().script_log        (ScriptStorage::eLuaMessageTypeError,"CScriptGameObject::IterateBelt non-CInventoryOwner object !!!");
        return;
    }

    TIItemContainer::iterator    I = inventory_owner->inventory().m_belt.begin();
    TIItemContainer::iterator    E = inventory_owner->inventory().m_belt.end();
    for ( ; I != E; ++I)
        functor                (object,(*I)->object().lua_game_object());
}

Jak widzicie, różnica tutaj jest tylko w tym, że przedmioty są sortowane nie wszystkie, a tylko te, które są na pasie: tak jak zamiast m_all, używamy m_belt.

Jak wykorzystać w skryptach:
Używa się tak samo, jak funkcji iterate_inventory.

 

POPRAWKA NA WYŚWIETLANIE ZIELONYM KOLOREM PRZECZYTANYCH NOTATEK W DZIALE PDA "DZIENNIK" BY LVG_BREST:

Spoiler

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())
{
if(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;
}
}
}
}
}
}

Pod koniec UIDiaryWnd2.cpp dopisać:

// Poprawka na wyświetlanie zielonym kolorem przeczytanych notatek w dzienniku PDA
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);
}

 

2) UIDiaryWnd.h:

void UnloadNewsTab ();
void LoadNewsTab ();
void Reload (EDiaryFilter new_filter);
// Poprawka na wyświetlanie zielonym kolorem przeczytanych notatek w dzienniku PDA
void AddDiaryArticle (shared_str, bool bReaded);

 

 

TWORZENIE NOWEGO SLOTU:

Spoiler

W tej części użyto rewizji z XP DEV, ponieważ zostały tam przeprowadzone prace nad slotami. Jeśli ktoś korzysta z innej wersji źródeł, mogą być różnice.

 

Tworzymy slot dla drugiego detektora:

W UIInventoryWnd.cpp po:

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);

dodajemy:

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);

 

Po:

m_slots_array[SLOT_QUICK_ACCESS_3]  = m_pUISlotQuickAccessList_3;

dodajemy:

m_slots_array[DET_ADV_SLOT]          = m_pUIDetAdvList;

 

W UIInventoryWnd.h po:

CUIDragDropListEx*   m_pUISlotQuickAccessList_3;

dodajemy:

CUIDragDropListEx* m_pUIDetAdvList;

 

W pliku uiinventorywnd2.cpp od razu po:

_itm            = m_pInv->m_slots[SLOT_QUICK_ACCESS_3].m_pIItem;
if(_itm)
{
    CUICellItem* itm    = create_cell_item(_itm);
    m_pUISlotQuickAccessList_3->SetItem  (itm);
}

dodajemy:

_itm               = m_pInv->m_slots[DET_ADV_SLOT].m_pIItem;
if(_itm)
{
    CUICellItem* itm    = create_cell_item(_itm);
    m_pUIDetAdvList->SetItem  (itm);
}

 

Po:

m_pUISlotQuickAccessList_3->ClearAll    (true);

dodajemy:

m_pUIDetAdvList->ClearAll    (true);

 

W pliku UIInventoryWnd3.cpp po:

case INVENTORY_TO_SLOT15_ACTION:
    CurrentIItem()->SetSlot(SLOT_QUICK_ACCESS_3);
    break;

dodajemy:

case INVENTORY_TO_SLOT16_ACTION:
    CurrentIItem()->SetSlot(DET_ADV_SLOT);
    break;

 

W pliku inventory_space.h po:

#define SLOT_QUICK_ACCESS_3 15

dodajemy:

#define DET_ADV_SLOT        16

 

Również wnosimy zmiany w slots_total. Numer musi być o jeden większy niż numer ostatniego slotu. W naszym przypadku będzie to wyglądało tak:

#define SLOTS_TOTAL     17

 

W pliku UIMessages.h po:

INVENTORY_TO_SLOT15_ACTION,

piszemy:

INVENTORY_TO_SLOT16_ACTION,

 

Teraz pozostało tylko zarejestrować nam, nowy slot w plikach konfiguracyjnych gry, analogicznie do pozostałych.

inventory_new.xml i w 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"/>

 

I w 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

 

 

NOWE PARAMETRY DLA PANCERZY:

Spoiler

W CoP niektóre modyfikacje pancerzy zwiększają szybkość regeneracji zdrowia, energii, itd. W oryginalnym SoC jest parę unikalnych pancerzy, w których jest parametr health_restore_speed, ale oczywiście on nie działa. Dodać te parametry można bardzo łatwo:

CustomOutfit.cpp po:

m_HitTypeProtection[ALife::eHitTypePhysicStrike]= READ_IF_EXISTS(pSettings, r_float, section, "physic_strike_protection", 0.0f);

dodajemy:

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 );

Od razu warto zwrócić uwagę, że jeżeli w pliku konfiguracyjnym będzie brakować jednego z nowych parametrów, to jego wartość będzie równa 0.0. Idziemy dalej.

 

W pliku CustomOutfit.h po:

public:
    float       m_additional_weight;
    float       m_additional_weight2;

dodajemy:

float             m_fHealthRestoreSpeed;
float              m_fRadiationRestoreSpeed;
float              m_fSatietyRestoreSpeed;
float             m_fPowerRestoreSpeed;
float             m_fBleedingRestoreSpeed;

Teraz te parametry są czytane, ale na razie nie są wykorzystywane.

 

Dla ich użycia w Actor.cpp po, np.:

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;
}

dodajemy:

#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
  }

}

 

Teraz po:

//dla właściwości artefaktów, znajdujących się na pasie
UpdateArtefactsOnBelt      ();

dodajemy:

UpdtateOutfitInSlot          ();

 

Teraz w Actor.h po:

//właściwości artefaktów
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;}

dodajemy:

//parametry pancerza
virtual void  UpdtateOutfitInSlot    ();

 

 

PRZYPISYWANIE SKRÓTÓW KLAWISZOWYCH DO SKRYPTÓW, KTÓRE MOŻNA ZMIENIAĆ W MENU GŁÓWNYM:

Spoiler

Stworzymy przycisk, który będzie można z łatwością zmieniać w opcjach, a po naciśnięciu będzie wywoływana funkcja ze skryptu.

W pliku: ActorInput.cpp po:

#include "../../build_config_defines.h"

dodajemy:

#include "pch_script.h"
#include "InventoryOwner.h"
#include "script_game_object.h"
#include "script_game_object_impl.h"

Nie wiadomo czy są potrzebne wszystkie 4 include'y, ale na wszelki wypadek lepiej napisać wszystkie 4.

 

Również np. po:

case kCROUCH_TOGGLE:
  {
   g_bAutoClearCrouch = !g_bAutoClearCrouch;
   if (!g_bAutoClearCrouch)
    mstate_wishful |= mcCrouch;

  }break;

dodajemy:

case kCLOCK:
  {
  luabind::functor<void>    clock_key;
  if (ai().script_engine().functor("gz_items_hud.clock_key",clock_key))
  clock_key();
    }break;

Jak widzicie, jest tutaj przycisk wyświetlenia godziny. "gz_items_hud.clock_key" to skrypt i funkcja, które zostały wywołane po naciśnięciu przycisku.

 

Teraz w pliku key_binding_registrator_script.cpp w:

class_<enum_exporter<EGameActions> >("key_bindings")
   .enum_("commands")
   [

analogicznie do pozostałych dodajemy:

value("kCLOCK",            int(kCLOCK)),

Jeśli będziecie dodawać na koniec, to nie zapomnijcie usunąć przecinka na końcu linijki.

 

Potem w pliku: xr_level_controller.cpp dodajemy analogicznie do pozostałych:

{ "clock",          kCLOCK          ,_sp},

Prawdopodobnie _sp odnosi się do trybu jednego gracza, _both do obydwu, a _mp do wieloosobowego. Nie wiadomo, trzeba to sprawdzić.

 

Teraz w xr_level_controller.h dodajemy:

kCLOCK,

do innych przycisków.

 

Nawiasem mówiąc takim sposobem, jeśli jest to potrzebne, można zamienić jakąś silnikową akcję na skryptową. Po prostu szukamy case kPOTRZEBNY_PRZYCISK: i zmieniamy "potrzebny" na swój.

I to wszystko, przycisk w silniku jest. Przechodzimy do konfiguracji.

 

Plik u\ui_keybinding.xml dodajemy do żądanej grupy przycisków:

<command id="kb_clock"            exe="clock"/>

Teraz w test\rus\ui_st_keybinding.xml:

<string id="kb_clock">
<text>Zegar</text>
</string>

 

Jeśli chcecie, aby domyślnie przycisk był już ustawiony, szukamy pliku default_controls.ltx w folderze config, skąd są brane dane o tym, jaki przycisk na jakie działanie ustawić przy tworzeniu przez grę pliku user.ltx.

Po prostu piszemy:

bind clock kC

Funkcja w skrypcie jest najzwyklejsza:

--//*** Zegar na ręce
function clock_key() -- wywołuje się z silnika po naciśnięciu przycisku zegar
--działanie po naciśnięciu przycisku
end

I to wszystko. Nie sprawdzano, co będzie jeśli skrypta lub funkcji nie ma.

 

PRZYWRÓCENIE FUNKCJI ODRADZANIA ARTEFAKTÓW PO ZADZIAŁANIU ANOMALII (AUTOR: BAK):

Spoiler

Źródło: https://disk.yandex.ru/d/LYCNOX-buFd7a

Dodano parametry dla anomalii:

; ustawienia online spawnu

spawn_blowout_artefacts = on ; główny przełącznik możliwości respawnu
artefact_spawn_probability = 0.05 ;prawdopodobieństwo, że podczas działania anomalii pojawi się artefakt

; dodane przez ?
birth_on_death_probability = 0.2 ; prawdopodobieństwo pojawienia się artefaktu po śmierci mutanta/NPC w anomalii
birth_on_torn_probability = 0.5 ; prawdopodobieństwo pojawienia się artefaktu po rozerwaniu ciała

birth_on_nonalive = true ; możliwość pojawienia się po działaniu na przedmiot
birth_on_alive = true ; możliwość pojawienia się po działaniu na żywą istotę
birth_on_dead = true ; możliwość pojawienia się po działaniu na trupa

 

 

 

 

ŹRÓDŁO:

https://ap-pro.ru/forums/topic/1572-soc-melkie-pravki-dvizhka/

Odnośnik do komentarza
Udostępnij na innych stronach

  • Gość zmienił(a) tytuł na Małe poprawki silnika [SoC]

Dołącz do dyskusji

Możesz dodać zawartość już teraz a zarejestrować się później. Jeśli posiadasz już konto, zaloguj się aby dodać zawartość za jego pomocą.
Uwaga: Twój wpis zanim będzie widoczny, będzie wymagał zatwierdzenia moderatora.

Gość
Dodaj odpowiedź do tematu...

×   Wklejono zawartość z formatowaniem.   Usuń formatowanie

  Dozwolonych jest tylko 75 emoji.

×   Odnośnik został automatycznie osadzony.   Przywróć wyświetlanie jako odnośnik

×   Przywrócono poprzednią zawartość.   Wyczyść edytor

×   Nie możesz bezpośrednio wkleić grafiki. Dodaj lub załącz grafiki z adresu URL.

×
×
  • Dodaj nową pozycję...

Powiadomienie o plikach cookie

Korzystając z tej strony, zgadzasz się na nasze Warunki użytkowania.