Guest Diegtiariow Posted March 3, 2023 Report Share Posted March 3, 2023 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. W 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: W 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/ Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.