Gość Diegtiariow Opublikowano 18 Lutego 2023 Zgłoś Udostępnij Opublikowano 18 Lutego 2023 OPENXRAY: Spoiler Kod źródłowy OpenXRay (po rosyjsku): https://github.com/OpenXRay/xray-16/wiki/[RU]-Как-собрать-движок-на-Windows Jak zainstalować/zebrać OpenXRay (obowiązkowe do przeczytania): https://github.com/OpenXRay/xray-16/wiki/[RU]-Как-собрать-движок-на-Windows REPOZYTORIUM ZWYKŁEGO SILNIKA: Spoiler NGEngine: https://gitlab.com/DaniilOzol181/ng-engine UWAGA!!! Wszystkie poprawki dokonywane są w pliku xrGame.dll. Jeśli nie zostaną tam utworzone, będzie utworzony osobny spoiler do edycji innych bibliotek !!! LEKCJE OD DOCTOR_OZ: Spoiler JAK DODAĆ NOWE SLOTY DO INWENTARZA (NÓŻ, LORNETKĘ, itd.): Spoiler Autor tej lekcji: Doctor_Oz (Даниил Озол) Będziemy edytować plik UIActorMenuInitialize.cpp. Szukamy tej linijki: constexpr std::tuple<eActorMenuListType, cpcstr, cpcstr, cpcstr, cpcstr, bool> inventory_lists[] = Jak zapewne zauważyliście (jeśli chociaż trochę znacie język angielski), to jest to tablica z kilkoma odnośnikami, a dokładnie na takie parametry jak: ikonka, stopień uszkodzenia (pasek stanu), podświetlenie i ikonka blokady (jak w hełmie w egzoszkielecie lub artefaktów). Dodajemy tutaj takie linijki: { eInventoryKnifeList, "dragdrop_knife", "progess_bar_knife", "knife_slot_highlight", nullptr, true }, // Nóż { eInventoryBinocularList, "dragdrop_binocular", nullptr, "binocular_slot_highlight",nullptr, true }, // Lornetka Jeśli chcemy w lornetce zrobić pasek stanu, to można dodać w drugiej linijce na miejsce pierwszej z wartością "nullptr" - wartość "progess_bar_binocular" (najważniejsze, aby nie zapomnieć dodać tego do actor_menu). Teraz szukamy tej linijki: std::tuple<eActorMenuListType, cpcstr, CUIWindow*> inventory_lists[] = Jest to także tablica, do której trzeba dodać te linijki: { eInventoryKnifeList, "dragdrop_knife", m_pInventoryWnd }, // Nóż { eInventoryBinocularList, "dragdrop_binocular", m_pInventoryWnd }, // Lornetka Szukamy tej linijki: BindDragDropListEvents(m_pLists[eInventoryAutomaticList]); I dokładnie po niej dodajemy to: BindDragDropListEvents(m_pLists[eInventoryKnifeList]); BindDragDropListEvents(m_pLists[eInventoryBinocularList]); Z pierwszym plikiem już skończyliśmy pracę. Przechodzimy do drugiego, a mianowicie UIActorMenuInventory.cpp. W nim potrzebna jest nam linijka: void CUIActorMenu::InitInventoryMode() To znowu tablica, a w niej (najlepiej na środku) musisz dodać to: m_pLists[eInventoryKnifeList]->Show(true); m_pLists[eInventoryBinocularList]->Show(true); Teraz w tablicy: CUIDragDropListEx* all_lists[] = Dodajemy następujące elementy, oddzielając je przecinkami (najlepiej tak, jak pierwotnie zrobiono), czyli to: m_pLists[eInventoryKnifeList], m_pLists[eInventoryBinocularList], Trzeba dodać tak, aby wszystko wyglądało tak (chociaż jest to nieobowiązkowe): m_pLists[eInventoryBeltList], m_pLists[eInventoryPistolList], m_pLists[eInventoryAutomaticList], m_pLists[eInventoryKnifeList], m_pLists[eInventoryBinocularList], m_pLists[eInventoryOutfitList], m_pLists[eInventoryHelmetList], m_pLists[eInventoryDetectorList], m_pLists[eInventoryBagList], m_pLists[eTradeActorBagList], m_pLists[eTradeActorList] Z jeszcze jedną tablicą skończyliśmy pracę. Nie martw się, będzie ich jeszcze trochę więcej:) Trzeba zmienić jeszcze jedną tablicę. Szukamy linijki: if (onlyBagList) Od razu po niej jest lista slotów: INV_SLOT2 INV_SLOT3 itd. Od razu po nich, trzeba usunąć następujące linijki: if (!m_pActorInvOwner->inventory().SlotIsPersistent(KNIFE_SLOT)) if (!m_pActorInvOwner->inventory().SlotIsPersistent(BINOCULAR_SLOT)) Następnie zmieniamy kolejną tablicę, można ją znaleźć po takiej linijce: CUIDragDropListEx* CUIActorMenu::GetSlotList(u16 slot_idx) W niej trzeba zmienić: case KNIFE_SLOT: case BINOCULAR_SLOT: na: case KNIFE_SLOT: return m_pLists[eInventoryKnifeList]; break; case BINOCULAR_SLOT: return m_pLists[eInventoryBinocularList]; break; Z drugim plikiem skończyliśmy pracę. Teraz następny, a dokładnie UIActorMenu.cpp. Na początku dodamy do include dwa pliki: #include "WeaponKnife.h" #include "WeaponBinocular.h" Do tablicy: EDDListType CUIActorMenu::GetListType(CUIDragDropListEx* l) dodajemy: if (l == m_pLists[eInventoryKnifeList]) return iActorSlot; if (l == m_pLists[eInventoryBinocularList]) return iActorSlot; Do tablicy: void CUIActorMenu::clear_highlight_lists() m_pLists[eInventoryBinocularList]->Highlight(false); m_pLists[eInventoryKnifeList]->Highlight(false); Do tablicy: void CUIActorMenu::highlight_item_slot(CUICellItem* cell_item) dodajemy po tym: CWeapon* weapon = smart_cast<CWeapon*>(item); takie coś: CWeaponKnife* knife = smart_cast<CWeaponKnife*>(item); CWeaponBinoculars* binoculars = smart_cast<CWeaponBinoculars*>(item); Również po: if (weapon && (slot_id == INV_SLOT_2 || slot_id == INV_SLOT_3)) { m_pLists[eInventoryPistolList]->Highlight(true); m_pLists[eInventoryAutomaticList]->Highlight(true); return; } dodajemy: if (knife && slot_id == KNIFE_SLOT) { m_pLists[eInventoryKnifeList]->Highlight(true); return; } if (binoculars && slot_id == BINOCULAR_SLOT) { m_pLists[eInventoryBinocularList]->Highlight(true); return; } Do tablicy: void CUIActorMenu::ClearAllLists() dodajemy: m_pLists[eInventoryKnifeList]->ClearAll(true); m_pLists[eInventoryBinocularList]->ClearAll(true); Teraz w pliku: UIActorMenu.h dodajemy odnośniki: Do tablicy: enum eActorMenuListType to: eInventoryKnifeList, eInventoryBinocularList, I to wszystko, można kompilować silnik (jeśli zakończyliście). I kiedy go skompilujecie, przystąpimy do samego UI. Uwaga od twórcy lekcji - rysować będziecie sami, autor pokaże przykładowo, całe UI będziecie musieli samodzielnie dostosowywać, dla swojego inwentarza. Dla edycji bierzemy actor_menu.xml - ten plik odpowiada za rozdzielczość 1024x768, a actor_menu_16.xml odpowiada za panoramiczny rozmiar, w nim robicie praktycznie to samo, co w pierwszym. Będą się jedynie różnić współrzędnymi i rozmiarem kilku pikseli (jeśli jesteście zaznajomieni z UI to sami wiecie). Przystępujemy do edytowania: Po fragmencie: <detector_slot_highlight x="463" y="330" width="96" height="48" stretch="1"> <texture>ui_inGame2_detector_highlighter</texture> </detector_slot_highlight> dodajemy następujące rzeczy (zrobione na przykładzie detektora, ale działa wyśmienicie): <knife_slot_highlight x="463" y="350" width="96" height="48" stretch="1"> <texture>ui_inGame2_detector_highlighter</texture> </knife_slot_highlight> <binocular_slot_highlight x="463" y="370" width="96" height="48" stretch="1"> <texture>ui_inGame2_detector_highlighter</texture> </binocular_slot_highlight> Teraz po: <progess_bar_outfit x="484" y="309" width="58" height="5" horz="1" min="0" max="1" pos="0"> <progress> <texture r="142" g="149" b="149">ui_inGame2_inventory_status_bar</texture> </progress> <min_color r="196" g="18" b="18"/> <middle_color r="255" g="255" b="118"/> <max_color r="107" g="207" b="119"/> </progess_bar_outfit> Dodajemy: <progess_bar_knife x="484" y="324" width="58" height="5" horz="1" min="0" max="1" pos="0"> <progress> <texture r="142" g="149" b="149">ui_inGame2_inventory_status_bar</texture> </progress> <min_color r="196" g="18" b="18"/> <middle_color r="255" g="255" b="118"/> <max_color r="107" g="207" b="119"/> </progess_bar_knife> Również dodajemy po: <dragdrop_detector x="458" y="328" width="106" height="55" cell_width="41" cell_height="41" rows_num="1" cols_num="2" custom_placement="0" a="0" virtual_cells="1" vc_vert_align="c" vc_horiz_align="c"/> takie coś: <dragdrop_knife x="458" y="348" width="106" height="55" cell_width="41" cell_height="41" rows_num="1" cols_num="2" custom_placement="0" a="0" virtual_cells="1" vc_vert_align="c" vc_horiz_align="c"/> <dragdrop_binocular x="458" y="368" width="106" height="55" cell_width="41" cell_height="41" rows_num="1" cols_num="2" custom_placement="0" a="0" virtual_cells="1" vc_vert_align="c" vc_horiz_align="c"/> W system.ltx poprawiamy następujące linijki: slot_persistent_1 = true ;knife slot_active_1 = true na takie coś: slot_persistent_1 = false ;knife slot_active_1 = true Również: slot_persistent_5 = true ;binocular slot_active_5 = true na: slot_persistent_5 = false ;binocular slot_active_5 = true To chyba wszystko. Jeśli wystąpi wylot bez logu, to znaczy, że gdzieś jest błąd w kodzie. DODANIE DODATKOWYCH SLOTÓW NA ARTEFAKTY: Spoiler Autor lekcji: Doctor_Oz(Даниил Озол) Autor poprawki: Doctor_Oz(Даниил Озол) Najpierw zmienimy ilość artefaktów w samym plecaku (nie szukaj sensu, nie ma go XD). Otwieramy plik Inventory.cpp i znajdujemy linijkę: m_iMaxBelt = pSettings->read_if_exists<s32>("inventory", "max_belt", 5); Trzeba zmienić cyfrę (odradza się zmiany na większą). Autor lekcji zmienił na 8 (na początku było 5). m_iMaxBelt = pSettings->read_if_exists<s32>("inventory", "max_belt", 5); Ponieważ zmieniliśmy systemową ilość artefaktów, musimy zmienić max. liczbę slotów, które mogą zostać otwarte przez pancerz. Otwieramy plik CustomOutfit.cpp i znajdujemy funkcję: void CCustomOutfit::Load(LPCSTR section) W tej funkcji szukamy linijki: clamp(m_artefact_count, (u32)0, (u32)5); i zmieniamy na: clamp(m_artefact_count, (u32)0, (u32)8); Również w pliku znajdujemy funkcję (wiadomo, że zmienna, jednakże): bool CCustomOutfit::install_upgrade_impl(LPCSTR section, bool test) a w niej szukamy dokładnie takiej linijki i zmieniamy ją: clamp(m_artefact_count, (u32)0, (u32)5); na: clamp(m_artefact_count, (u32)0, (u32)8); I to chyba wszystko. Możecie teraz zmienić ilość slotów na artefakty w outfit.ltx, UI i System.ltx, tak jak było robione (jeśli nie robiliście to Google na pomoc). JAK DODAĆ PRZYCIŚNIĘCIE PRZY WŁĄCZENIU LATARKI: Spoiler Autor lekcji: Doctor_Oz(Даниил Озол) Autor poprawki: nieznany, na GitHub jest revolucas, kod wzięto z otwartego repozytorium Call of Chernobyl (link na commit) Do edycji będą potrzebne dwa pliki: Torch.cpp i Torch.h. Otwieramy plik Torch.cpp i jeśli niczego nie edytowaliśmy, to szukamy funkcji w 76 linijce: void CTorch::Load(LPCSTR section) { inherited::Load(section); light_trace_bone = pSettings->r_string(section, "light_trace_bone"); m_bNightVisionEnabled = !!pSettings->r_bool(section, "night_vision"); } Zmieniamy ją na: void CTorch::Load(LPCSTR section) { inherited::Load(section); light_trace_bone = pSettings->r_string(section, "light_trace_bone"); m_light_section = READ_IF_EXISTS(pSettings, r_string, section, "light_section", "torch_definition"); if (pSettings->line_exist(section, "snd_turn_on")) m_sounds.LoadSound(section, "snd_turn_on", "sndTurnOn", false, SOUND_TYPE_ITEM_USING); if (pSettings->line_exist(section, "snd_turn_off")) m_sounds.LoadSound(section, "snd_turn_off", "sndTurnOff", false, SOUND_TYPE_ITEM_USING); m_bNightVisionEnabled = !!pSettings->r_bool(section, "night_vision"); } Szukamy teraz funkcji void CTorch::Switch(bool light_on) i żebyś nie zawracał sobie głowy (jeśli oczywiście NIE edytowałeś wcześniej pliku), po prostu zmień na taką: void CTorch::Switch(bool light_on) { CActor* pActor = smart_cast<CActor*>(H_Parent()); if (pActor) { if (light_on && !m_switched_on) { if (m_sounds.FindSoundItem("SndTurnOn", false)) m_sounds.PlaySound("SndTurnOn", pActor->Position(), NULL, !!pActor->HUDview()); } else if (!light_on && m_switched_on) { if (m_sounds.FindSoundItem("SndTurnOff", false)) m_sounds.PlaySound("SndTurnOff", pActor->Position(), NULL, !!pActor->HUDview()); } } m_switched_on = light_on; if (can_use_dynamic_lights()) { light_render->set_active(light_on); // CActor *pA = smart_cast<CActor *>(H_Parent()); // if(!pA) light_omni->set_active(light_on); } glow_render->set_active(light_on); if (*light_trace_bone) { IKinematics* pVisual = smart_cast<IKinematics*>(Visual()); VERIFY(pVisual); u16 bi = pVisual->LL_BoneID(light_trace_bone); pVisual->LL_SetBoneVisible(bi, light_on, TRUE); pVisual->CalculateBones(TRUE); } } Również zmieniamy funkcję bool CTorch::net_Spawn(CSE_Abstract* DC) na taką: bool CTorch::net_Spawn(CSE_Abstract* DC) { CSE_Abstract* e = (CSE_Abstract*)(DC); CSE_ALifeItemTorch* torch = smart_cast<CSE_ALifeItemTorch*>(e); R_ASSERT(torch); cNameVisual_set(torch->get_visual()); R_ASSERT(!GetCForm()); R_ASSERT(smart_cast<IKinematics*>(Visual())); CForm = xr_new<CCF_Skeleton>(this); if (!inherited::net_Spawn(DC)) return (FALSE); bool b_r2 = GEnv.Render->GenerationIsR2OrHigher(); IKinematics* K = smart_cast<IKinematics*>(Visual()); CInifile* pUserData = K->LL_UserData(); R_ASSERT3(pUserData, "Empty Torch user data!", torch->get_visual()); R_ASSERT2(pUserData->section_exist(m_light_section), "Section not found in torch user data! Check 'light_section' field in config"); lanim = LALib.FindItem(pUserData->r_string(m_light_section, "color_animator")); guid_bone = K->LL_BoneID(pUserData->r_string(m_light_section, "guide_bone")); VERIFY(guid_bone != BI_NONE); Fcolor clr = pUserData->r_fcolor(m_light_section, (b_r2) ? "color_r2" : "color"); fBrightness = clr.intensity(); float range = pUserData->r_float(m_light_section, (b_r2) ? "range_r2" : "range"); light_render->set_color(clr); light_render->set_range(range); if (b_r2) { bool useVolumetric = pUserData->read_if_exists<bool>(m_light_section, "volumetric_enabled", false); light_render->set_volumetric(useVolumetric); if (useVolumetric) { float volQuality = pUserData->read_if_exists<float>(m_light_section, "volumetric_quality", 1.f); clamp(volQuality, 0.f, 1.f); light_render->set_volumetric_quality(volQuality); float volIntensity = pUserData->read_if_exists<float>(m_light_section, "volumetric_intensity", 1.f); clamp(volIntensity, 0.f, 10.f); light_render->set_volumetric_intensity(volIntensity); float volDistance = pUserData->read_if_exists<float>(m_light_section, "volumetric_distance", 1.f); clamp(volDistance, 0.f, 1.f); light_render->set_volumetric_distance(volDistance); } } Fcolor clr_o = pUserData->r_fcolor(m_light_section, (b_r2) ? "omni_color_r2" : "omni_color"); float range_o = pUserData->r_float(m_light_section, (b_r2) ? "omni_range_r2" : "omni_range"); light_omni->set_color(clr_o); light_omni->set_range(range_o); light_render->set_cone(deg2rad(pUserData->r_float(m_light_section, "spot_angle"))); light_render->set_texture(READ_IF_EXISTS(pUserData,r_string,m_light_section, "spot_texture",(0))); glow_render->set_texture(pUserData->r_string(m_light_section, "glow_texture")); glow_render->set_color(clr); glow_render->set_radius(pUserData->r_float(m_light_section, "glow_radius")); //włączyć/wyłączyć latarkę Switch(torch->m_active); VERIFY(!torch->m_active || (torch->ID_Parent != 0xffff)); if (torch->ID_Parent == 0) SwitchNightVision(torch->m_nightvision_active, false); // else // SwitchNightVision (false, false); m_delta_h = PI_DIV_2 - atan((range * 0.5f) / _abs(TORCH_OFFSET.x)); return (TRUE); } To ostatnie zostało dodane nie dla dźwięka, a dlatego że zmienialiśmy TORCH_DEFINITION na m_light_section i teraz trzeba zarejestrować ten sam m_light_section. Otwieramy plik Torch.h i od razu po Fvector m_focus; dodajemy to: shared_str m_light_section; Aby wyszło tak: float m_delta_h; Fvector2 m_prev_hp; bool m_switched_on; ref_light light_render; ref_light light_omni; ref_glow glow_render; Fvector m_focus; shared_str m_light_section; Również torch.zip do folderu sounds, wrzucamy dźwięki włączenia i wyłączenia (początkowo są one jednakowe, ale możecie zmienić na swoje). W pliku, gdzie są przechowywane device_torch (początkowo znajduje się on w misc\items.ltx), w samym device_torch trzeba dodać linijki: snd_turn_on = torch\nazwa_dźwięku_włączania ;(pisać bez rozszerzenia .ogg) snd_turn_off = torch\nazwa_dźwięku_wyłączania ;(pisać bez rozszerzenia .ogg) ZMIANA NAPISU, PO NACIŚNIĘCIU PRAWEGO PRZYCISKU MYSZY NA UŻYWANY PRZEDMIOT (TYPU "ZJEŚĆ", "WYPIĆ", ITD.) DLA DOWOLNEGO NAPISU: Spoiler Autor lekcji: Doctor_Oz(Даниил Озол) Autor poprawki: Suhar_ (Lex_Addon) Do edycji będzie tylko jeden plik w silniku i jeden w gamedata. Na początku zaczniemy od silnika i otworzymy plik: UIActorMenuInventory.cpp I jeśli już go edytowałeś to szukamy funkcji: void CUIActorMenu::PropertiesBoxForUsing(PIItem item, bool& b_show) A w niej te linijki: // XXX: Xottab_DUTY: remove this.. if (!xr_strcmp(section_name, "vodka") || !xr_strcmp(section_name, "energy_drink")) act_str = "st_drink"; else if (!xr_strcmp(section_name, "bread") || !xr_strcmp(section_name, "kolbasa") || !xr_strcmp( section_name, "conserva")) act_str = "st_eat"; else act_str = "st_use"; I zamieniamy je na: act_str = READ_IF_EXISTS(pSettings, r_string, section_name, "use_caption", "st_use"); Teraz przy korzystaniu z DOWOLNEGO przedmiotu, będzie wyświetlany napis "Użyć". Aby to zmienić wystarczy podać w sekcji: use_caption = st_wasz_id_tekstu Najważniejsze, aby ulokować ten napis - w przeciwnym wypadku, będzie widzieli napis "st_wasz_id_tekstu". LEKCJA NT. DODAWANIA PLECAKA: Spoiler W xrGame tworzymy filtr (naciskamy na jakiś folder, twórca lekcji wybrał xrGame/core/client/objects/item&weapons/) i nazwijmy go Backpack. W nim tworzymy nowy element. Podczas tworzenia wyświetli się lista i w niej trzeba wybrać ".cpp". Na dole trzeba wpisać nazwę ActorBackpack.cpp. I takim sposobem tworzymy plik ".h" . Nazwa wyróżni się tym, że zamiast .cpp trzeba wpisać .h. Po tym jak je stworzyliśmy, zaczynamy ich edytowanie. Na początku otwieramy ActorBackpack.h, wydzielamy wszystko i umieszczamy w nim to: #pragma once #include "inventory_item_object.h" class CBackpack : public CInventoryItemObject { private: typedef CInventoryItemObject inherited; public: CBackpack(); virtual ~CBackpack(); virtual void Load(LPCSTR section); virtual void Hit(float P, ALife::EHitType hit_type); virtual void OnMoveToSlot(const SInvItemPlace& prev); virtual void OnMoveToRuck(const SInvItemPlace& previous_place); virtual void OnH_A_Chield(); public: float m_additional_weight; float m_additional_weight2; float m_fPowerRestoreSpeed; float m_fPowerLoss; virtual bool net_Spawn(CSE_Abstract* DC); virtual void net_Export(NET_Packet& P); virtual void net_Import(NET_Packet& P); protected: virtual bool install_upgrade_impl(LPCSTR section, bool test); }; Teraz otwieramy ActorBackpack.cpp i wpisujemy: #include "stdafx.h" #include "ActorBackpack.h" #include "Actor.h" #include "Inventory.h" CBackpack::CBackpack() { m_flags.set(FUsingCondition, FALSE); } CBackpack::~CBackpack() { } void CBackpack::Load(LPCSTR section) { inherited::Load(section); m_additional_weight = pSettings->r_float(section, "additional_inventory_weight"); m_additional_weight2 = pSettings->r_float(section, "additional_inventory_weight2"); m_fPowerRestoreSpeed = READ_IF_EXISTS(pSettings, r_float, section, "power_restore_speed", 0.0f); m_fPowerLoss = READ_IF_EXISTS(pSettings, r_float, section, "power_loss", 1.0f); clamp(m_fPowerLoss, EPS, 1.0f); m_flags.set(FUsingCondition, READ_IF_EXISTS(pSettings, r_bool, section, "use_condition", TRUE)); } bool CBackpack::net_Spawn(CSE_Abstract* DC) { return inherited::net_Spawn(DC); } void CBackpack::net_Export(NET_Packet& P) { inherited::net_Export(P); P.w_float_q8(GetCondition(), 0.0f, 1.0f); } void CBackpack::net_Import(NET_Packet& P) { inherited::net_Import(P); float _cond; P.r_float_q8(_cond, 0.0f, 1.0f); SetCondition(_cond); } void CBackpack::OnH_A_Chield() { inherited::OnH_A_Chield(); } void CBackpack::OnMoveToSlot(const SInvItemPlace& previous_place) { inherited::OnMoveToSlot(previous_place); } void CBackpack::OnMoveToRuck(const SInvItemPlace& previous_place) { inherited::OnMoveToRuck(previous_place); } void CBackpack::Hit(float hit_power, ALife::EHitType hit_type) { if (IsUsingCondition() == false) return; hit_power *= GetHitImmunity(hit_type); ChangeCondition(-hit_power); } bool CBackpack::install_upgrade_impl(LPCSTR section, bool test) { bool result = inherited::install_upgrade_impl(section, test); result |= process_if_exists(section, "power_restore_speed", &CInifile::r_float, m_fPowerRestoreSpeed, test); result |= process_if_exists(section, "power_loss", &CInifile::r_float, m_fPowerLoss, test); clamp(m_fPowerLoss, 0.0f, 1.0f); result |= process_if_exists(section, "additional_inventory_weight", &CInifile::r_float, m_additional_weight, test); result |= process_if_exists(section, "additional_inventory_weight2", &CInifile::r_float, m_additional_weight2, test); return result; } I to wszystko. Pliki można zamknąć. Będziemy je ruszać, jeśli będziemy potrzebowali dodać jakąś funkcję taką jak ZSO (Zamknięty system oddychania - tzn. dodać butlę z tlenem). Teraz zajmiemy się funkcją dodania udźwigu. Otwieramy Actor_Movement.cpp i szukamy funkcji: float CActor::get_additional_weight() const { float res = 0.0f; CCustomOutfit* outfit = GetOutfit(); if (outfit) { res += outfit->m_additional_weight; } for (TIItemContainer::const_iterator it = inventory().m_belt.begin(); inventory().m_belt.end() != it; ++it) { CArtefact* artefact = smart_cast<CArtefact*>(*it); if (artefact) res += artefact->AdditionalInventoryWeight(); } return res; } Na początku przed tą linijką: #include "Artefact.h" Po niej dodajemy, ale nie w funkcji: #include "ActorBackpack.h" Teraz zmieniamy samą funkcję na taką: float CActor::get_additional_weight() const { float res = 0.0f; CCustomOutfit* outfit = GetOutfit(); if (outfit) { res += outfit->m_additional_weight; } CBackpack* pBackpack = smart_cast<CBackpack*>(inventory().ItemFromSlot(BACKPACK_SLOT)); if (pBackpack) res += pBackpack->m_additional_weight; for (TIItemContainer::const_iterator it = inventory().m_belt.begin(); inventory().m_belt.end() != it; ++it) { CArtefact* artefact = smart_cast<CArtefact*>(*it); if (artefact) res += artefact->AdditionalInventoryWeight(); } return res; } Zakończyliśmy pracę z tym plikiem. Idziemy do następnego CustomOutfit.cpp. Edytujemy go po to, aby można było zrobić możliwość zamknięcia slotu, np. w tym egzoszkielecie. Od razu po: #include "ActorHelmet.h" dodajemy: #include "ActorBackpack.h" Teraz po: bIsHelmetAvaliable = !!READ_IF_EXISTS(pSettings, r_bool, section, "helmet_avaliable", true); dodajemy: bIsBackpackAvaliable = !!READ_IF_EXISTS(pSettings, r_bool, section, "backpack_avaliable", true); Teraz szukamy funkcji: void CCustomOutfit::OnMoveToSlot(const SInvItemPlace& prev) { if (m_pInventory) { CActor* pActor = smart_cast<CActor*>(H_Parent()); if (pActor) { ApplySkinModel(pActor, true, false); if (prev.type == eItemPlaceSlot && !bIsHelmetAvaliable) { CTorch* pTorch = smart_cast<CTorch*>(pActor->inventory().ItemFromSlot(TORCH_SLOT)); if (pTorch && pTorch->GetNightVisionStatus()) pTorch->SwitchNightVision(true, false); } PIItem pHelmet = pActor->inventory().ItemFromSlot(HELMET_SLOT); if (pHelmet && !bIsHelmetAvaliable) pActor->inventory().Ruck(pHelmet, false); } } } i zmieniamy na taką: void CCustomOutfit::OnMoveToSlot(const SInvItemPlace& prev) { if (m_pInventory) { CActor* pActor = smart_cast<CActor*>(H_Parent()); if (pActor) { ApplySkinModel(pActor, true, false); if (prev.type == eItemPlaceSlot && !bIsHelmetAvaliable) { CTorch* pTorch = smart_cast<CTorch*>(pActor->inventory().ItemFromSlot(TORCH_SLOT)); if (pTorch && pTorch->GetNightVisionStatus()) pTorch->SwitchNightVision(true, false); } PIItem pHelmet = pActor->inventory().ItemFromSlot(HELMET_SLOT); if (pHelmet && !bIsHelmetAvaliable) pActor->inventory().Ruck(pHelmet, false); PIItem pBackpack = pActor->inventory().ItemFromSlot(BACKPACK_SLOT); if (pBackpack && !bIsBackpackAvaliable) pActor->inventory().Ruck(pBackpack, false); } } } Dalej wchodzimy w CustomOutfit.h i po: bool bIsHelmetAvaliable; dodajemy: bool bIsBackpackAvaliable; Teraz wchodzimy w Inventory.cpp i zamiast: false // helmet stawiamy: false, // helmet false // backpack Teraz w funkcji: bool CInventory::CanPutInSlot(PIItem pIItem, u16 slot_id) const Od razu po: if (slot_id == HELMET_SLOT) { CCustomOutfit* pOutfit = m_pOwner->GetOutfit(); if (pOutfit && !pOutfit->bIsHelmetAvaliable) return false; } dodajemy: if (slot_id == BACKPACK_SLOT) { CCustomOutfit* pOutfit = m_pOwner->GetOutfit(); if (pOutfit && !pOutfit->bIsBackpackAvaliable) return false; } I to wszystko. Wchodzimy teraz do EntityConditions.cpp. Po: #include "ActorHelmet.h" dodajemy: #include "ActorBackpack.h" Szukamy funkcji: float CEntityCondition::HitPowerEffect(float power_loss) float CEntityCondition::HitPowerEffect(float power_loss) { CInventoryOwner* pInvOwner = smart_cast<CInventoryOwner*>(m_object); if (!pInvOwner) return power_loss; CCustomOutfit* pOutfit = pInvOwner->GetOutfit(); CHelmet* pHelmet = (CHelmet*)pInvOwner->inventory().ItemFromSlot(HELMET_SLOT); CBackpack* pBackpack = (CBackpack*)pInvOwner->inventory().ItemFromSlot(BACKPACK_SLOT); return power_loss * (0.5f +(pOutfit?pOutfit->m_fPowerLoss:EPS) + (pHelmet?pHelmet->m_fPowerLoss:EPS) + (pBackpack?pBackpack->m_fPowerLoss:EPS)); } Zakończyliśmy pracę z kolejnym plikiem. Otwieramy plik InventoryOwner.cpp i PRZED tym: float CInventoryOwner::MaxCarryWeight() const dodajemy: #include "ActorBackpack.h" I zmieniamy całą funkcję: float CInventoryOwner::MaxCarryWeight() const na: float CInventoryOwner::MaxCarryWeight() const { float ret = inventory().GetMaxWeight(); const CCustomOutfit* outfit = GetOutfit(); if (outfit) ret += outfit->m_additional_weight2; CBackpack* pBackpack = smart_cast<CBackpack*>(inventory().ItemFromSlot(BACKPACK_SLOT)); if (pBackpack) ret += pBackpack->m_additional_weight2; return ret; } Przechodzimy do script_game_object_inventory_owner.cpp. I po: #include "PhysicObject.h" dodajemy: #include "ActorBackpack.h" Teraz zajmujemy się zamianą funkcji (funkcja to nie tylko linijka, ale wszystko w nawiasach klamrowych{...} po niej): Zamieniamy to: float CScriptGameObject::GetAdditionalMaxWeight() const na: float CScriptGameObject::GetAdditionalMaxWeight() const { CCustomOutfit* outfit = smart_cast<CCustomOutfit*>(&object()); CBackpack* pBackpack = smart_cast<CBackpack*>(&object()); if(!outfit && !pBackpack) { GEnv.ScriptEngine->script_log(LuaMessageType::Error, "CCustomOutfit : cannot access class member GetAdditionalMaxWeight!"); return false; } if (outfit) return (outfit->m_additional_weight2); return (pBackpack->m_additional_weight2); } Teraz to: float CScriptGameObject::GetAdditionalMaxWalkWeight() const na: float CScriptGameObject::GetAdditionalMaxWalkWeight() const { CCustomOutfit* outfit = smart_cast<CCustomOutfit*>(&object()); CBackpack* pBackpack = smart_cast<CBackpack*>(&object()); if(!outfit && !pBackpack) { GEnv.ScriptEngine->script_log(LuaMessageType::Error, "CCustomOutfit : cannot access class member GetAdditionalMaxWalkWeight!"); return false; } if (outfit) return (outfit->m_additional_weight); return (pBackpack->m_additional_weight); } Później to: void CScriptGameObject::SetAdditionalMaxWeight(float add_max_weight) na: void CScriptGameObject::SetAdditionalMaxWeight(float add_max_weight) { CCustomOutfit* outfit = smart_cast<CCustomOutfit*>(&object()); CBackpack* pBackpack = smart_cast<CBackpack*>(&object()); if(!outfit && !pBackpack) { GEnv.ScriptEngine->script_log(LuaMessageType::Error, "CCustomOutfit : cannot access class member SetAdditionalMaxWeight!"); return; } if (outfit) outfit->m_additional_weight2 = add_max_weight; if (pBackpack) pBackpack->m_additional_weight2 = add_max_weight; } Teraz to: void CScriptGameObject::SetAdditionalMaxWalkWeight(float add_max_walk_weight) na: void CScriptGameObject::SetAdditionalMaxWalkWeight(float add_max_walk_weight) { CCustomOutfit* outfit = smart_cast<CCustomOutfit*>(&object()); CBackpack* pBackpack = smart_cast<CBackpack*>(&object()); if(!outfit && !pBackpack) { GEnv.ScriptEngine->script_log(LuaMessageType::Error, "CCustomOutfit : cannot access class member SetAdditionalMaxWalkWeight!"); return; } if (outfit) outfit->m_additional_weight = add_max_walk_weight; if (pBackpack) pBackpack->m_additional_weight = add_max_walk_weight; } I to wszystko. Zajmiemy się teraz częścią związaną z UI. Otwieramy UIActorMenu.h i po: eInventoryHelmetList, dodajemy: eInventoryBackpackList, Otwieramy UIActorMenu.cpp i od razu po: #include "ActorHelmet.h" dodajemy: #include "ActorBackpack.h" Teraz do funkcji: EDDListType CUIActorMenu::GetListType(CUIDragDropListEx* l) po: if (l == m_pLists[eInventoryHelmetList] && m_pLists[eInventoryHelmetList] != nullptr) return iActorSlot; dodajemy: if (l == m_pLists[eInventoryBackpackList] && m_pLists[eInventoryBackpackList] != nullptr) return iActorSlot; W funkcji: void CUIActorMenu::clear_highlight_lists() po: if (m_pLists[eInventoryHelmetList]) m_pLists[eInventoryHelmetList]->Highlight(false); dodajemy: if (m_pLists[eInventoryBackpackList]) m_pLists[eInventoryBackpackList]->Highlight(false); W funkcji: void CUIActorMenu::highlight_item_slot(CUICellItem* cell_item) po: CHelmet* helmet = smart_cast<CHelmet*>(item); dodajemy: CBackpack* backpack = smart_cast<CBackpack*>(item); Dalej po: if (helmet && slot_id == HELMET_SLOT) { if (m_pLists[eInventoryHelmetList]) m_pLists[eInventoryHelmetList]->Highlight(true); return; } dodajemy: if (backpack && slot_id == BACKPACK_SLOT) { if (m_pLists[eInventoryBackpackList]) m_pLists[eInventoryBackpackList]->Highlight(true); return; } W funkcji: void CUIActorMenu::ClearAllLists() po: if (m_pLists[eInventoryHelmetList]) m_pLists[eInventoryHelmetList]->ClearAll(true); dodajemy: if (m_pLists[eInventoryBackpackList]) m_pLists[eInventoryBackpackList]->ClearAll(true); Wchodzimy do UIActorMenuInventory.cpp #include "actor_defs.h" piszemy: #include "ActorBackpack.h" W funkcji: void CUIActorMenu::InitInventoryMode() po: ShowIfExist(m_pLists[eInventoryHelmetList], true); dodajemy: ShowIfExist(m_pLists[eInventoryBackpackList], true); Później w funkcji: void CUIActorMenu::OnInventoryAction(PIItem pItem, u16 action_type) po: m_pLists[eInventoryHelmetList], dodajemy: m_pLists[eInventoryBackpackList], Szukamy linijki: InitCellForSlot(HELMET_SLOT); i po niej: InitCellForSlot(BACKPACK_SLOT); Funkcję: bool CUIActorMenu::ToSlot(CUICellItem* itm, bool force_place, u16 slot_id) zmieniamy na: bool CUIActorMenu::ToSlot(CUICellItem* itm, bool force_place, u16 slot_id) { CUIDragDropListEx* old_owner = itm->OwnerList(); PIItem iitem = (PIItem)itm->m_pData; bool b_own_item = (iitem->parent_id() == m_pActorInvOwner->object_id()); if (slot_id == HELMET_SLOT) { CCustomOutfit* pOutfit = m_pActorInvOwner->GetOutfit(); if (pOutfit && !pOutfit->bIsHelmetAvaliable) return false; } if (slot_id == BACKPACK_SLOT) { CCustomOutfit* pOutfit = m_pActorInvOwner->GetOutfit(); if (pOutfit && !pOutfit->bIsBackpackAvaliable) return false; } if (m_pActorInvOwner->inventory().CanPutInSlot(iitem, slot_id)) { CUIDragDropListEx* new_owner = GetSlotList(slot_id); //Alundaio if (!new_owner) return true; /*if (slot_id == GRENADE_SLOT || !new_owner) { return true; // fake, sorry ((( } else*/ if (slot_id == OUTFIT_SLOT) { CCustomOutfit* pOutfit = smart_cast<CCustomOutfit*>(iitem); CBackpack* pBackpack = smart_cast<CBackpack*>(iitem); if (pOutfit && !pOutfit->bIsHelmetAvaliable) { CUIDragDropListEx* helmet_list = GetSlotList(HELMET_SLOT); if (helmet_list && helmet_list->ItemsCount() == 1) { CUICellItem* helmet_cell = helmet_list->GetItemIdx(0); ToBag(helmet_cell, false); } } if (pOutfit && !pOutfit->bIsBackpackAvaliable) { CUIDragDropListEx* backpack_list = GetSlotList(BACKPACK_SLOT); if (backpack_list && backpack_list->ItemsCount() == 1) { CUICellItem* backpack_cell = backpack_list->GetItemIdx(0); ToBag(backpack_cell, false); } } } bool result = (!b_own_item) || m_pActorInvOwner->inventory().Slot(slot_id, iitem); VERIFY(result); CUICellItem* i = old_owner->RemoveItem(itm, (old_owner == new_owner)); while (i->ChildsCount()) { CUICellItem* child = i->PopChild(nullptr); old_owner->SetItem(child); } new_owner->SetItem(i); SendEvent_Item2Slot(iitem, m_pActorInvOwner->object_id(), slot_id); SendEvent_ActivateSlot(slot_id, m_pActorInvOwner->object_id()); // ColorizeItem ( itm, false ); if (slot_id == OUTFIT_SLOT) { MoveArtefactsToBag(); } return true; } else { // in case slot is busy if (!force_place || slot_id == NO_ACTIVE_SLOT) return false; if (m_pActorInvOwner->inventory().SlotIsPersistent(slot_id) && slot_id != DETECTOR_SLOT) return false; if (slot_id == INV_SLOT_2 && m_pActorInvOwner->inventory().CanPutInSlot(iitem, INV_SLOT_3)) return ToSlot(itm, force_place, INV_SLOT_3); if (slot_id == INV_SLOT_3 && m_pActorInvOwner->inventory().CanPutInSlot(iitem, INV_SLOT_2)) return ToSlot(itm, force_place, INV_SLOT_2); CUIDragDropListEx* slot_list = GetSlotList(slot_id); if (!slot_list) return false; const PIItem _iitem = m_pActorInvOwner->inventory().ItemFromSlot(slot_id); CUIDragDropListEx* invlist = GetListByType(iActorBag); if (invlist != slot_list) { if (!slot_list->ItemsCount() == 1) return false; CUICellItem* slot_cell = slot_list->GetItemIdx(0); if (!(slot_cell && static_cast<PIItem>(slot_cell->m_pData) == _iitem)) return false; if (ToBag(slot_cell, false) == false) return false; } else { //Alundaio: Since the player's inventory is being used as a slot we need to search for cell with matching m_pData auto container = slot_list->GetContainer(); auto child_list = container->GetChildWndList(); for (auto& it : child_list) { CUICellItem* i = static_cast<CUICellItem*>(it); const PIItem pitm = static_cast<PIItem>(i->m_pData); if (pitm == _iitem) { if (ToBag(i, false)) break; return false; } } return ToSlot(itm, false, slot_id); } bool result = ToSlot(itm, false, slot_id); if (b_own_item && result && slot_id == DETECTOR_SLOT) { CCustomDetector* det = smart_cast<CCustomDetector*>(iitem); det->ToggleDetector(g_player_hud->attached_item(0) != NULL); } return result; } } W funkcji: CUIDragDropListEx* CUIActorMenu::GetSlotList(u16 slot_idx) po: case HELMET_SLOT: return m_pLists[eInventoryHelmetList]; break; dodajemy: case BACKPACK_SLOT: return m_pLists[eInventoryBackpackList]; break; Funkcję: void CUIActorMenu::PropertiesBoxForSlots(PIItem item, bool& b_show) zmieniamy na: void CUIActorMenu::PropertiesBoxForSlots(PIItem item, bool& b_show) { CCustomOutfit* pOutfit = smart_cast<CCustomOutfit*>(item); CHelmet* pHelmet = smart_cast<CHelmet*>(item); CBackpack* pBackpack = smart_cast<CBackpack*>(item); CInventory& inv = m_pActorInvOwner->inventory(); // Flaga dla wyłączenia punktu kontekstowego menu: Dress Outfit, jeśli pancerz jest już założony bool bAlreadyDressed = false; u16 cur_slot = item->BaseSlot(); if (!pOutfit && !pHelmet && cur_slot != NO_ACTIVE_SLOT && !inv.SlotIsPersistent(cur_slot) && m_pActorInvOwner-> inventory().ItemFromSlot(cur_slot) != item /*&& inv.CanPutInSlot(item, cur_slot)*/) { m_UIPropertiesBox->AddItem("st_move_to_slot", NULL, INVENTORY_TO_SLOT_ACTION); b_show = true; } if (item->Belt() && inv.CanPutInBelt(item)) { m_UIPropertiesBox->AddItem("st_move_on_belt", NULL, INVENTORY_TO_BELT_ACTION); b_show = true; } if (item->Ruck() && inv.CanPutInRuck(item) && (cur_slot == NO_ACTIVE_SLOT || !inv.SlotIsPersistent(cur_slot))) { if (!pOutfit) { if (!pHelmet) { if (!pBackpack) { if (m_currMenuMode == mmDeadBodySearch) m_UIPropertiesBox->AddItem("st_move_to_bag", nullptr, INVENTORY_TO_BAG_ACTION); else m_UIPropertiesBox->AddItem("st_unequip", nullptr, INVENTORY_TO_BAG_ACTION); } else m_UIPropertiesBox->AddItem("st_undress_backpack", NULL, INVENTORY_TO_BAG_ACTION); } else m_UIPropertiesBox->AddItem("st_undress_helmet", NULL, INVENTORY_TO_BAG_ACTION); } else m_UIPropertiesBox->AddItem("st_undress_outfit", NULL, INVENTORY_TO_BAG_ACTION); bAlreadyDressed = true; b_show = true; } if (pOutfit && !bAlreadyDressed) { m_UIPropertiesBox->AddItem("st_dress_outfit", NULL, INVENTORY_TO_SLOT_ACTION); b_show = true; } CCustomOutfit* outfit_in_slot = m_pActorInvOwner->GetOutfit(); if (pHelmet && !bAlreadyDressed && (!outfit_in_slot || outfit_in_slot->bIsHelmetAvaliable)) { m_UIPropertiesBox->AddItem("st_dress_helmet", NULL, INVENTORY_TO_SLOT_ACTION); b_show = true; } if (pBackpack && !bAlreadyDressed && (!outfit_in_slot || outfit_in_slot->bIsBackpackAvaliable)) { m_UIPropertiesBox->AddItem("st_dress_backpack", NULL, INVENTORY_TO_SLOT_ACTION); b_show = true; } } W funkcji: void CUIActorMenu::UpdateOutfit() po: if (m_pLists[eInventoryHelmetList]) { if (outfit && !outfit->bIsHelmetAvaliable) m_pLists[eInventoryHelmetList]->SetCellsCapacity({ 0, 0 }); else m_pLists[eInventoryHelmetList]->SetCellsCapacity(m_pLists[eInventoryHelmetList]->MaxCellsCapacity()); } dodajemy: if (m_pLists[eInventoryBackpackList]) { if (outfit && !outfit->bIsBackpackAvaliable) m_pLists[eInventoryBackpackList]->SetCellsCapacity({ 0, 0 }); else m_pLists[eInventoryBackpackList]->SetCellsCapacity(m_pLists[eInventoryBackpackList]->MaxCellsCapacity()); } Otwieramy plik UIActorMenuInitialize.cpp Szukamy tej linijki: { eInventoryHelmetList, "dragdrop_helmet", "progess_bar_helmet", "helmet_slot_highlight", "helmet_over", false }, i po niej dodajemy: { eInventoryBackpackList, "dragdrop_backpack", nullptr, "backpack_slot_highlight", "backpack_over", false }, Szukamy linijek: if (m_pLists[eInventoryHelmetList]) m_pLists[eInventoryHelmetList]->SetMaxCellsCapacity(m_pLists[eInventoryHelmetList]->CellsCapacity()); dodajemy po nich: if (m_pLists[eInventoryBackpackList]) m_pLists[eInventoryBackpackList]->SetMaxCellsCapacity(m_pLists[eInventoryBackpackList]->CellsCapacity()); Szukamy linijki: BindDragDropListEvents(m_pLists[eInventoryHelmetList]); i po niej dodajemy: BindDragDropListEvents(m_pLists[eInventoryBackpackList]); Wchodzimy do pliku UIInventoryUpgradeWnd.cpp I tam, jak wszędzie, dodajemy: #include "ActorBackpack.h" Później w funkcji: void CUIInventoryUpgradeWnd::InitInventory(CUICellItem* cellItem, bool can_upgrade) zmieniamy to: else if (smart_cast<CCustomOutfit*>(m_inv_item) || smart_cast<CHelmet*>(m_inv_item)) { is_shader = true; m_item->SetShader(InventoryUtilities::GetOutfitUpgradeIconsShader()); } na to: else if (smart_cast<CCustomOutfit*>(m_inv_item) || smart_cast<CHelmet*>(m_inv_item) || smart_cast<CBackpack*>(m_inv_item)) { is_shader = true; m_item->SetShader(InventoryUtilities::GetOutfitUpgradeIconsShader()); } Wchodzimy do xrServerEntities Szukamy tam pliku object_factory_register.cpp I w nim po: #include "ActorHelmet.h" dodajemy: #include "ActorBackpack.h" Szukamy linijki: ADD(CHelmet, CSE_ALifeItem, CLSID_EQUIPMENT_HELMET, "helmet"); i po niej dodajemy: ADD(CBackpack, CSE_ALifeItemBackpack, CLSID_EQUIPMENT_BACKPACK, "equ_backpack"); Wchodzimy do pliku clsid_game.h I po: #define CLSID_EQUIPMENT_HELMET MK_CLSID('E', 'Q', '_', 'H', 'L', 'M', 'E', 'T') dodajemy: #define CLSID_EQUIPMENT_BACKPACK MK_CLSID('E','Q','_','B','A','K','P','K') Wchodzimy do pliku inventory_space.h I po: HELMET_SLOT, // helmet dodajemy: BACKPACK_SLOT, // backpack Wchodzimy do pliku xrServer_Objects_ALife_Items.cpp I po: //////////////////////////////////////////////////////////////////////////// // CSE_ALifeItemHelmet //////////////////////////////////////////////////////////////////////////// CSE_ALifeItemHelmet::CSE_ALifeItemHelmet(LPCSTR caSection) : CSE_ALifeItem(caSection) {} CSE_ALifeItemHelmet::~CSE_ALifeItemHelmet() {} void CSE_ALifeItemHelmet::STATE_Read(NET_Packet& tNetPacket, u16 size) { inherited::STATE_Read(tNetPacket, size); } void CSE_ALifeItemHelmet::STATE_Write(NET_Packet& tNetPacket) { inherited::STATE_Write(tNetPacket); } void CSE_ALifeItemHelmet::UPDATE_Read(NET_Packet& tNetPacket) { inherited::UPDATE_Read(tNetPacket); tNetPacket.r_float_q8(m_fCondition, 0.0f, 1.0f); } void CSE_ALifeItemHelmet::UPDATE_Write(NET_Packet& tNetPacket) { inherited::UPDATE_Write(tNetPacket); tNetPacket.w_float_q8(m_fCondition, 0.0f, 1.0f); } #ifndef XRGAME_EXPORTS void CSE_ALifeItemHelmet::FillProps(LPCSTR pref, PropItemVec& items) { inherited::FillProps(pref, items); } #endif // #ifndef XRGAME_EXPORTS BOOL CSE_ALifeItemHelmet::Net_Relevant() { return (true); } dodajemy: //////////////////////////////////////////////////////////////////////////// // CSE_ALifeItemBackpack //////////////////////////////////////////////////////////////////////////// CSE_ALifeItemBackpack::CSE_ALifeItemBackpack(LPCSTR caSection) : CSE_ALifeItem(caSection) {} CSE_ALifeItemBackpack::~CSE_ALifeItemBackpack() {} void CSE_ALifeItemBackpack::STATE_Read(NET_Packet& tNetPacket, u16 size) { inherited::STATE_Read(tNetPacket, size); } void CSE_ALifeItemBackpack::STATE_Write(NET_Packet& tNetPacket) { inherited::STATE_Write(tNetPacket); } void CSE_ALifeItemBackpack::UPDATE_Read(NET_Packet& tNetPacket) { inherited::UPDATE_Read(tNetPacket); tNetPacket.r_float_q8(m_fCondition, 0.0f, 1.0f); } void CSE_ALifeItemBackpack::UPDATE_Write(NET_Packet& tNetPacket) { inherited::UPDATE_Write(tNetPacket); tNetPacket.w_float_q8(m_fCondition, 0.0f, 1.0f); } #ifndef XRGAME_EXPORTS void CSE_ALifeItemBackpack::FillProps(LPCSTR pref, PropItemVec& items) { inherited::FillProps(pref, items); } #endif // #ifndef XRGAME_EXPORTS BOOL CSE_ALifeItemBackpack::Net_Relevant() { return (true); } Później wchodzimy do xrServer_Objects_ALife_Items.h I po: class CSE_ALifeItemHelmet : public CSE_ALifeItem { using inherited = CSE_ALifeItem; public: CSE_ALifeItemHelmet(LPCSTR caSection); virtual ~CSE_ALifeItemHelmet(); virtual BOOL Net_Relevant(); virtual void UPDATE_Read(NET_Packet& P); virtual void UPDATE_Write(NET_Packet& P); virtual void STATE_Read(NET_Packet& P, u16 size); virtual void STATE_Write(NET_Packet& P); SERVER_ENTITY_EDITOR_METHODS }; dodajemy: class CSE_ALifeItemBackpack : public CSE_ALifeItem { using inherited = CSE_ALifeItem; public: CSE_ALifeItemBackpack(LPCSTR caSection); virtual ~CSE_ALifeItemBackpack(); virtual BOOL Net_Relevant(); virtual void UPDATE_Read(NET_Packet& P); virtual void UPDATE_Write(NET_Packet& P); virtual void STATE_Read(NET_Packet& P, u16 size); virtual void STATE_Write(NET_Packet& P); SERVER_ENTITY_EDITOR_METHODS }; Wchodzimy do pliku xrServer_Objects_ALife_Items_script2.cpp I po: SCRIPT_EXPORT(CSE_ALifeItemHelmet, (CSE_ALifeItem), { module(luaState)[luabind_class_item1(CSE_ALifeItemHelmet, "cse_alife_item_helmet", CSE_ALifeItem)]; }); dodajemy: SCRIPT_EXPORT(CSE_ALifeItemBackpack, (CSE_ALifeItem), { module(luaState)[luabind_class_item1(CSE_ALifeItemBackpack, "cse_alife_item_backpack", CSE_ALifeItem)]; }); I to wszystko. Zakończyliśmy pracę z silnikiem. Mało już zostało pracy. Edytować .xml, zrobić plik plecaka i zarejestrować go w System.ltx W tym samym System.ltx zmieniami slots_count zamiast 12 na 13 Po: slot_persistent_12 = false ;helmet slot_active_12 = false dodajemy: slot_persistent_13 = false ;backpack slot_active_13 = false Jest to już koniec prac. Testowy plik plecaka: backpack.ltx , teraz wystarczy go zarejestrować w System.ltx i dodać do folderu misc dla wygody. LEKCJA "WYGANIAMY NARUTO Z GG": Spoiler Autor lekcji: Doctor_Oz (Даниил Озол) Kod został dostarczony od twórcy M.F.S. Team Edytować trzeba jeden plik - ActorAnimation.cpp. Szukamy funkcji: void CActor::g_SetAnimation(u32 mstate_rl) W niej szukamy linijki: case CArtefact::eIdle: M_torso = TW->moving[moving_idx]; break; case CArtefact::eShowing: M_torso = TW->draw; break; case CArtefact::eHiding: M_torso = TW->holster; break; case CArtefact::eActivating: M_torso = TW->zoom; break; default: M_torso = TW->moving[moving_idx]; Po tych linijkach są takie nawiasy klamrowe "}" i po piątej piszemy dany kod: else if (!m_bAnimTorsoPlayed) { if (moving_idx == STorsoWpn::eSprint) M_torso = ST->m_torso[0].moving[moving_idx]; else M_torso = ST->m_torso[4].moving[moving_idx]; //Alundaio: Fix torso anim no wpn } I to wszystko. Screeny po zmianie: ŹRÓDŁO: https://ap-pro.ru/forums/topic/3457-redaktirovanie-openxray/ Cytuj Odnośnik do komentarza Udostępnij na innych stronach Więcej opcji udostępniania...
Rekomendowane odpowiedzi
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.