Doctor_Oz 29 Опубликовано 26 апреля, 2022 (изменено) Так как я человек лени, мне было лень искать по всяким форумам людей кто будет редактировать движок. В связи с этим я решил взяться за OpenXRay (честь и хвала его создателям), так как он собирается и редактируется без проблем. Я хочу оставить тут записи тем людям что хотят, хоть как-то отредактировать движок(новые слоты, новые характеристики и т.д.). Спойлер Исходный Код OpenXRayКак собрать OpenXRay (обязательно к прочтению) Спойлер Scarlet Sunset Engine Спойлер NGEngine Если у вас так же, как и у меня есть подходящие уроки, то поделитесь с людьми, ведь даже нам иногда могут помочь:) WARNING!!! Все правки производятся в xrGame.dll. Если же они делаются не там, то будет сделан отдельный спойлер для правок других библиотек!!! Пожалуй первыми моими уроками будет вот это: Спойлер Первое что мы будем редактировать файл UIActorMenuInitialize.cpp. Ищем вот эту строку: constexpr std::tuple<eActorMenuListType, cpcstr, cpcstr, cpcstr, cpcstr, bool> inventory_lists[] = Как вы наверно заметили(если хотя бы немного знаете инглишь),то это таблица с некоторыми ссылками, а именно на такие параметры как: иконка, степень повреждённости(прогресс бар), подсветка и иконка блокировки(как у шлема в экзоскелете или артефактов). Добавляем туда вот такие строки: { eInventoryKnifeList, "dragdrop_knife", "progess_bar_knife", "knife_slot_highlight", nullptr, true }, // Нож { eInventoryBinocularList, "dragdrop_binocular", nullptr, "binocular_slot_highlight",nullptr, true }, // Бинокль Если хотим в бинокле сделать прогресс-бар, то можно добавить во второй строке на место первой nullptr вот это "progess_bar_binocular". (главное не забыть добавить это в actor_menu). Теперь ищем вот эту строку: std::tuple<eActorMenuListType, cpcstr, CUIWindow*> inventory_lists[] = Это также таблица в которую нужно добавить вот эти строки: { eInventoryKnifeList, "dragdrop_knife", m_pInventoryWnd }, // Нож { eInventoryBinocularList, "dragdrop_binocular", m_pInventoryWnd }, // Бинокль Также ищем вот эту строку: BindDragDropListEvents(m_pLists[eInventoryAutomaticList]); И буквально после нее добавляем вот это: BindDragDropListEvents(m_pLists[eInventoryKnifeList]); BindDragDropListEvents(m_pLists[eInventoryBinocularList]); С первым файлом пожалуй закончили. Приступаем ко второму, а именно UIActorMenuInventory.cpp В нём нам нужна строка void CUIActorMenu::InitInventoryMode() Это опять таблица, в нее (желательно в середину) нужно добавить вот это: m_pLists[eInventoryKnifeList]->Show(true); m_pLists[eInventoryBinocularList]->Show(true); Теперь в таблице CUIDragDropListEx* all_lists[] = Добавляем через запятую следующее(желательно как изначально сделано) то есть вот это: m_pLists[eInventoryKnifeList], m_pLists[eInventoryBinocularList], Добавить так, чтобы всё выглядело так(хотя это необязательно): 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] С еще одной таблицей мы покончили. Не беспокойтесь, их будет еще очень немножко много:) И как я и обещал, нам нужно изменить еще одну таблицу. Ищем строку if (onlyBagList) Сразу после нее идёт список слотов: INV_SLOT2 INV_SLOT3 И т.д. Так сразу после них, нужно удалить следующие строки: if (!m_pActorInvOwner->inventory().SlotIsPersistent(KNIFE_SLOT)) if (!m_pActorInvOwner->inventory().SlotIsPersistent(BINOCULAR_SLOT)) Теперь меняем следующую таблицу, ее можно найти по такой строке: CUIDragDropListEx* CUIActorMenu::GetSlotList(u16 slot_idx) В ней нужно поменять: case KNIFE_SLOT: case BINOCULAR_SLOT: На следующее: case KNIFE_SLOT: return m_pLists[eInventoryKnifeList]; break; case BINOCULAR_SLOT: return m_pLists[eInventoryBinocularList]; break; Со вторым файлом покончили. Теперь следующий, а именно UIActorMenu.cpp В начале мы добавим к инклудам следующие два файла: #include "WeaponKnife.h" #include "WeaponBinocular.h" В таблицу EDDListType CUIActorMenu::GetListType(CUIDragDropListEx* l) Добавляем следующее: if (l == m_pLists[eInventoryKnifeList]) return iActorSlot; if (l == m_pLists[eInventoryBinocularList]) return iActorSlot; В таблицу void CUIActorMenu::clear_highlight_lists() m_pLists[eInventoryBinocularList]->Highlight(false); m_pLists[eInventoryKnifeList]->Highlight(false); В таблицу void CUIActorMenu::highlight_item_slot(CUICellItem* cell_item) Добавляем после CWeapon* weapon = smart_cast<CWeapon*>(item); Вот это: CWeaponKnife* knife = smart_cast<CWeaponKnife*>(item); CWeaponBinoculars* binoculars = smart_cast<CWeaponBinoculars*>(item); Также после if (weapon && (slot_id == INV_SLOT_2 || slot_id == INV_SLOT_3)) { m_pLists[eInventoryPistolList]->Highlight(true); m_pLists[eInventoryAutomaticList]->Highlight(true); return; } Добавляем вот это: if (knife && slot_id == KNIFE_SLOT) { m_pLists[eInventoryKnifeList]->Highlight(true); return; } if (binoculars && slot_id == BINOCULAR_SLOT) { m_pLists[eInventoryBinocularList]->Highlight(true); return; } В таблицу void CUIActorMenu::ClearAllLists() m_pLists[eInventoryKnifeList]->ClearAll(true); m_pLists[eInventoryBinocularList]->ClearAll(true); Теперь в файле UIActorMenu.h добавим ссылки: В таблицу enum eActorMenuListType Вот это: eInventoryKnifeList, eInventoryBinocularList, Всё, можно собирать движок(если вы закончили). И когда вы его соберете мы приступим к самому UI. Сразу предупреждаю, я не учу вас рисовать, так что рисовать будете сами, я покажу только примерно, все UI вам нужно будет подгонять самим, под свой инвентарь. Для редактирования возьмём actor_menu.xml этот файл отвечает за разрешение 1024x768 вроде, а actor_menu_16.xml отвечает за широкоформат, в нём делаете практически точно так же как и в первом, в них будут различаться только координаты и на пару пикселей размер(если знакомы с UI то сами знаете). Так, побазарили и хватит, приступим к редактированию: После <detector_slot_highlight x="463" y="330" width="96" height="48" stretch="1"> <texture>ui_inGame2_detector_highlighter</texture> </detector_slot_highlight> Добавляем следующее(сделана на примере детектора, но работает просто чудесно) <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> Теперь после <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> Добавляем <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> Также добавляем после <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"/> Вот это вот <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"/> Теперь в system.ltx исправим следующие строки: slot_persistent_1 = true ;knife slot_active_1 = true На вот это: slot_persistent_1 = false ;knife slot_active_1 = true Также это: slot_persistent_5 = true ;binocular slot_active_5 = true На это: slot_persistent_5 = false ;binocular slot_active_5 = true Вот пожалуй и всё. Но если у вас вдруг случился вылет, сразу же бежим кидать в меня тапком, чтобы я нашёл ошибку, а то я уже говорил, что пишу в два часа ночи, а это значит что я несу всякий бред. После того как сообщите свою ошибку(желательно с логом, а он ОБЯЗАТЕЛЬНО будет(если его нет, то вы накосячили где-то, где я не давал корректировку.)) Автор данного урока: Doctor_Oz(Даниил Озол) Спойлер Первым делом изменим кол-во артефактов в самом рюкзаке. (смысла не ищите, его нет XD) Откроем файл Inventory.cpp и найдём строчку m_iMaxBelt = pSettings->read_if_exists<s32>("inventory", "max_belt", 5); Нам нужно изменить цифру(большую не ставьте, не рекомендую). Лично я уже изменил на 8(сначала была 5). m_iMaxBelt = pSettings->read_if_exists<s32>("inventory", "max_belt", 5); Так как мы изменили системное кол-во артефактов, нам надо изменить макс. кол-во ячеек которые могут быть открыты с помощью костюма. Откроем файл CustomOutfit.cpp и найдём функцию: void CCustomOutfit::Load(LPCSTR section) В этой функции найдём строчку: clamp(m_artefact_count, (u32)0, (u32)5); И изменим на: clamp(m_artefact_count, (u32)0, (u32)8); Так же в файле найдём функцию(да я знаю что переменная, но всё же): bool CCustomOutfit::install_upgrade_impl(LPCSTR section, bool test) А в ней найдём точно такую же строку и изменяем ее также: clamp(m_artefact_count, (u32)0, (u32)5); На: clamp(m_artefact_count, (u32)0, (u32)8); Вот пожалуй и всё. Теперь вы можете просто изменить кол-во артефактов в outfit.ltx, UI и System.ltx также, как делали(если делали конечно, если нет то google в помощь). Автор данного урока: Doctor_Oz(Даниил Озол) Автор правки: Doctor_Oz(Даниил Озол) Спойлер Под редакцию попадает два файла: Torch.cpp и Torch.h Ну пожалуй приступим. Откроем файл Torch.cpp и если вы ничего там не редактировали ищем функцию на 76 строке 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"); } Меняем её на: 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"); } Теперь ищем функцию void CTorch::Switch(bool light_on) и дабы вам не заморачиваться(если вы конечно НЕ редактировали файл до этого) просто изменим её на это: 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); } } Также меняем функцию bool CTorch::net_Spawn(CSE_Abstract* DC) на это: 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")); //включить/выключить фонарик 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); } Последнее было добавлено не для звука, а потому что мы изменили TORCH_DEFINITION на m_light_section и теперь нам надо зарегистрировать этот самый m_light_section Откроем файл Torch.h и сразу после Fvector m_focus; добавим вот это: shared_str m_light_section; Чтобы получилось вот это: 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; Так же torch.zip в папку sounds закиньте звуки включения и выключения(изначально они одинаковые, но вы можете поменять на свои) Так же в файле где у вас хранится device_torch (изначально он находится в misc\items.ltx), в сам device_torch нужно добавить строки: snd_turn_on = torch\ваше_название_звука_включения ;(тут писать без расширения .ogg) snd_turn_off = torch\ваше_название_звука_выключения ;(тут писать без расширения .ogg) Автор данного урока: Doctor_Oz(Даниил Озол) Автор правки: На данный момент неизвестен, кроме ника на GitHub (revolucas), код был взят из открытого репозитория Call of Chernobyl (ссылка на коммит) Спойлер Под редакторство попадает только один файл в движке и один в gamedat'e. Сначала начнём с движка, откроем файл: UIActorMenuInventory.cpp И если он у вас уже отредактирован ищем функцию: void CUIActorMenu::PropertiesBoxForUsing(PIItem item, bool& b_show) А в ней вот эти строки: // 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"; И заменяем их полностью на: act_str = READ_IF_EXISTS(pSettings, r_string, section_name, "use_caption", "st_use"); Теперь при использовании ЛЮБОГО предмета, будет высвечиваться надпись "Использовать" Дабы её изменить, достаточно в секции нужно предмета указать: use_caption = st_ваш_id_текста Главное не забудьте локализировать эту надпись, иначе вы будете видеть надпись "st_ваш_id_текста" Автор данного урока: Doctor_Oz(Даниил Озол) Автор правки: Suhar_ (Lex_Addon) Спойлер Итак, долгожданный урок по добавлению рюкзака. Распинаться не будем, сразу приступим. В xrGame создайте фильтр (нажмите на какую нибудь папку, я выбрал xrGame/core/client/objects/item&weapons/) и назовите его Backpack. В нём создайте новый элемент. При создании высветиться список и в нём нужно выбрать .cpp . Снизу надо ввести название ActorBackpack.cpp. Точно таким же образом создаём файл .h название отличается тем что вместо .cpp нужно вписать .h. После того как мы их создали начнём редактирование их. Сначала откроем ActorBackpack.h, выделим всё в нём комбинацией клавиш ctrl + a и в него впишем это: #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); }; Теперь открывает ActorBackpack.cpp и туда вписываем: #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; } Всё, эти файлы можно закрывать. Их трогать будем в случае если вам понадобится добавить какую то функцию в рюкзак по типу ЗСД(замкнутой системы дыхания, то есть попросту сделать кислородный баллон). Теперь займёмся функцией добавление переносимого веса. Откроем Actor_Movement.cpp и ищем функцию: 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; } Сначала перед ней есть #include "Artefact.h" После неё добавим, но не в функции #include "ActorBackpack.h" Теперь меняем саму функцию на это: 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; } Всё с этим файлом закончили. Теперь идём в следующий CustomOutfit.cpp. Мы его редактируем чтобы можно было сделать возможность закрыть слот, например в том же экзоскелете. Сразу после #include "ActorHelmet.h" Добавим #include "ActorBackpack.h" Теперь после bIsHelmetAvaliable = !!READ_IF_EXISTS(pSettings, r_bool, section, "helmet_avaliable", true); Добавим: bIsBackpackAvaliable = !!READ_IF_EXISTS(pSettings, r_bool, section, "backpack_avaliable", true); Теперь ищем функцию 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); } } } И меняем на это: 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); } } } Дальше идём в CustomOutfit.h и после bool bIsHelmetAvaliable; Добавить bool bIsBackpackAvaliable; Теперь идём в Inventory.cpp и вместо false // helmet Ставим false, // helmet false // backpack Теперь в функции bool CInventory::CanPutInSlot(PIItem pIItem, u16 slot_id) const Сразу после if (slot_id == HELMET_SLOT) { CCustomOutfit* pOutfit = m_pOwner->GetOutfit(); if (pOutfit && !pOutfit->bIsHelmetAvaliable) return false; } Добавим if (slot_id == BACKPACK_SLOT) { CCustomOutfit* pOutfit = m_pOwner->GetOutfit(); if (pOutfit && !pOutfit->bIsBackpackAvaliable) return false; } Всё. Теперь идём в EntityConditions.cpp. Сразу после #include "ActorHelmet.h" Добавим #include "ActorBackpack.h" Теперь ищем функцию 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)); } С очередным файлом закончили. Теперь открываем файл InventoryOwner.cpp и ПЕРЕД этим float CInventoryOwner::MaxCarryWeight() const Добавляем #include "ActorBackpack.h" И теперь меняем всю функцию float CInventoryOwner::MaxCarryWeight() const На 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; } Теперь переходим в script_game_object_inventory_owner.cpp И после #include "PhysicObject.h" Добавляем #include "ActorBackpack.h" Теперь займёмся заменой функций(если что функцией считается не только строка но и всё что в таких скобках {...} после неё): Заменим это float CScriptGameObject::GetAdditionalMaxWeight() const На это 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); } Теперь это float CScriptGameObject::GetAdditionalMaxWalkWeight() const На это 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); } Дальше это void CScriptGameObject::SetAdditionalMaxWeight(float add_max_weight) На это 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; } Теперь это void CScriptGameObject::SetAdditionalMaxWalkWeight(float add_max_walk_weight) На это 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; } Всё, теперь займёмся UI составляющей Откроем UIActorMenu.h и после eInventoryHelmetList, Добавить: eInventoryBackpackList, Открываем UIActorMenu.cpp и сразу после #include "ActorHelmet.h" Добавим #include "ActorBackpack.h" Теперь в функцию EDDListType CUIActorMenu::GetListType(CUIDragDropListEx* l) Сразу после if (l == m_pLists[eInventoryHelmetList] && m_pLists[eInventoryHelmetList] != nullptr) return iActorSlot; Добавим if (l == m_pLists[eInventoryBackpackList] && m_pLists[eInventoryBackpackList] != nullptr) return iActorSlot; Теперь в функции void CUIActorMenu::clear_highlight_lists() Сразу после if (m_pLists[eInventoryHelmetList]) m_pLists[eInventoryHelmetList]->Highlight(false); Добавим if (m_pLists[eInventoryBackpackList]) m_pLists[eInventoryBackpackList]->Highlight(false); В функции void CUIActorMenu::highlight_item_slot(CUICellItem* cell_item) Сразу после CHelmet* helmet = smart_cast<CHelmet*>(item); Добавим CBackpack* backpack = smart_cast<CBackpack*>(item); Дальше после if (helmet && slot_id == HELMET_SLOT) { if (m_pLists[eInventoryHelmetList]) m_pLists[eInventoryHelmetList]->Highlight(true); return; } Добавим if (backpack && slot_id == BACKPACK_SLOT) { if (m_pLists[eInventoryBackpackList]) m_pLists[eInventoryBackpackList]->Highlight(true); return; } Дальше в функции void CUIActorMenu::ClearAllLists() После if (m_pLists[eInventoryHelmetList]) m_pLists[eInventoryHelmetList]->ClearAll(true); Добавим if (m_pLists[eInventoryBackpackList]) m_pLists[eInventoryBackpackList]->ClearAll(true); Теперь идём в UIActorMenuInventory.cpp #include "actor_defs.h" Пишем #include "ActorBackpack.h" В функции void CUIActorMenu::InitInventoryMode() После ShowIfExist(m_pLists[eInventoryHelmetList], true); Добавляем ShowIfExist(m_pLists[eInventoryBackpackList], true); Дальше в функции void CUIActorMenu::OnInventoryAction(PIItem pItem, u16 action_type) Сразу после m_pLists[eInventoryHelmetList], Добавляем m_pLists[eInventoryBackpackList], Теперь ищем строку InitCellForSlot(HELMET_SLOT); И сразу после неё InitCellForSlot(BACKPACK_SLOT); Теперь функцию bool CUIActorMenu::ToSlot(CUICellItem* itm, bool force_place, u16 slot_id) Меняем на 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; } } Дальше в функции CUIDragDropListEx* CUIActorMenu::GetSlotList(u16 slot_idx) Сразу после case HELMET_SLOT: return m_pLists[eInventoryHelmetList]; break; Добавляем case BACKPACK_SLOT: return m_pLists[eInventoryBackpackList]; break; Теперь функцию void CUIActorMenu::PropertiesBoxForSlots(PIItem item, bool& b_show) Меняем на 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(); // Флаг-признак для невлючения пункта контекстного меню: Dreess Outfit, если костюм уже надет 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; } } Теперь в функции void CUIActorMenu::UpdateOutfit() Сразу после if (m_pLists[eInventoryHelmetList]) { if (outfit && !outfit->bIsHelmetAvaliable) m_pLists[eInventoryHelmetList]->SetCellsCapacity({ 0, 0 }); else m_pLists[eInventoryHelmetList]->SetCellsCapacity(m_pLists[eInventoryHelmetList]->MaxCellsCapacity()); } Добавляем if (m_pLists[eInventoryBackpackList]) { if (outfit && !outfit->bIsBackpackAvaliable) m_pLists[eInventoryBackpackList]->SetCellsCapacity({ 0, 0 }); else m_pLists[eInventoryBackpackList]->SetCellsCapacity(m_pLists[eInventoryBackpackList]->MaxCellsCapacity()); } Теперь откроем файл UIActorMenuInitialize.cpp Найдём данную строку { eInventoryHelmetList, "dragdrop_helmet", "progess_bar_helmet", "helmet_slot_highlight", "helmet_over", false }, И после добавим { eInventoryBackpackList, "dragdrop_backpack", nullptr, "backpack_slot_highlight", "backpack_over", false }, Теперь ищем строки if (m_pLists[eInventoryHelmetList]) m_pLists[eInventoryHelmetList]->SetMaxCellsCapacity(m_pLists[eInventoryHelmetList]->CellsCapacity()); Добавим после них if (m_pLists[eInventoryBackpackList]) m_pLists[eInventoryBackpackList]->SetMaxCellsCapacity(m_pLists[eInventoryBackpackList]->CellsCapacity()); Теперь ищем строку BindDragDropListEvents(m_pLists[eInventoryHelmetList]); И после неё добавим BindDragDropListEvents(m_pLists[eInventoryBackpackList]); Теперь идём в файл UIInventoryUpgradeWnd.cpp И там также как и везде добавляем #include "ActorBackpack.h" Дальше в функции void CUIInventoryUpgradeWnd::InitInventory(CUICellItem* cellItem, bool can_upgrade) Меняем это else if (smart_cast<CCustomOutfit*>(m_inv_item) || smart_cast<CHelmet*>(m_inv_item)) { is_shader = true; m_item->SetShader(InventoryUtilities::GetOutfitUpgradeIconsShader()); } На это 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()); } Теперь идём в xrServerEntities Ищем там файл object_factory_register.cpp И в нём сразу после #include "ActorHelmet.h" Добавляем #include "ActorBackpack.h" Теперь ищем строку ADD(CHelmet, CSE_ALifeItem, CLSID_EQUIPMENT_HELMET, "helmet"); И сразу после неё добавляем ADD(CBackpack, CSE_ALifeItemBackpack, CLSID_EQUIPMENT_BACKPACK, "equ_backpack"); Теперь идём в файл clsid_game.h И там после #define CLSID_EQUIPMENT_HELMET MK_CLSID('E', 'Q', '_', 'H', 'L', 'M', 'E', 'T') Добавляем #define CLSID_EQUIPMENT_BACKPACK MK_CLSID('E','Q','_','B','A','K','P','K') Теперь идём в файл inventory_space.h И после HELMET_SLOT, // helmet Добавляем BACKPACK_SLOT, // backpack Теперь идём в файл xrServer_Objects_ALife_Items.cpp И сразу после //////////////////////////////////////////////////////////////////////////// // 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); } Добавляем //////////////////////////////////////////////////////////////////////////// // 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); } Дальше идём в xrServer_Objects_ALife_Items.h И сразу после 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 }; Добавляем 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 }; Теперь идём в файл xrServer_Objects_ALife_Items_script2.cpp И после SCRIPT_EXPORT(CSE_ALifeItemHelmet, (CSE_ALifeItem), { module(luaState)[luabind_class_item1(CSE_ALifeItemHelmet, "cse_alife_item_helmet", CSE_ALifeItem)]; }); Добавляем SCRIPT_EXPORT(CSE_ALifeItemBackpack, (CSE_ALifeItem), { module(luaState)[luabind_class_item1(CSE_ALifeItemBackpack, "cse_alife_item_backpack", CSE_ALifeItem)]; }); Всё. С движком закончили. Дальше дело за малым. Отредактировать xml, сделать файл рюкзака и зарегистрировать его в System.ltx Так же в том же самом System.ltx меняем slots_count вместо 12 на 13 Также после slot_persistent_12 = false ;helmet slot_active_12 = false Добавим slot_persistent_13 = false ;backpack slot_active_13 = false Всё, теперь точно закончили. Если что, тестовый файл рюкзака я прикреплю, поэтому достаточно будет зарегистрировать его в System.ltx и добавить в папку misc для удобства. Урок Doctor_Oz (Даниил Озол) Код взят из Call of Chernobyl(нужна будет ссылка попросите, отправлю отдельным сообщением в теме) Так же если вы в костюм добавите isBackpackAvaiable = false то у вас будет закрыт слот рюкзака(по умолчанию он открыт) Всем благ! Будут проблемы обращайтесь! Спойлер Редактировать надо только один файл, ActorAnimation.cpp Ищем функцию void CActor::g_SetAnimation(u32 mstate_rl) В ней ищем строки 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]; После этих строк идут такие скобки } и после 5 пишем данный текст: 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 } Всё, теперь можно собирать. Скриншоты прилагаются: Урок от Doctor_Oz (Даниил Озол) Код был дан разработчиком M.F.S. Team backpack.ltx Изменено 10 июня, 2022 пользователем Doctor_Oz 3 1 4 Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты
Doctor_Oz 29 Опубликовано 25 мая, 2022 Добавил новый урок. Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты
Mad Hikki 332 Опубликовано 25 мая, 2022 Я не разбиоаюсь в кодах движков, и хотел бы спросить 2 вопроса. 1. Инструкцию "Как добавить щелчок при включения фонарика" можно провернуть например на OGSR Engine, как я знаю, там код ЗПшного движка. 2. В какой dll. Файл, Torch.h и Torch.cpp будут компилироваться при компиляции движка в dll. Файлы? Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты
Misery 431 Опубликовано 25 мая, 2022 Hikki 1. ЗП 2. xrGame, в нём же Torch. 1 Clear Sky: Gunslinger Addon Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты
Doctor_Oz 29 Опубликовано 25 мая, 2022 1 минуту назад, Hikki сказал: Я не разбиоаюсь в кодах движков, и хотел бы спросить 2 вопроса. 1. Инструкцию "Как добавить щелчок при включения фонарика" можно провернуть например на OGSR Engine, как я знаю, там код ЗПшного движка. 2. В какой dll. Файл, Torch.h и Torch.cpp будут компилироваться при компиляции движка в dll. Файлы? Хм, забыл сказать что ВСЕ уроки чисто по xrGame Да, это возможно, но вроде в OGSR же есть уже звук щелчка, не? Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты
Misery 431 Опубликовано 25 мая, 2022 Только что, Hikki сказал: OGSR Engine Если ничего не переименовали, то можно ctrl c ctrl v Дополнено 0 минут спустя Только что, Doctor_Oz сказал: Да, это возможно, но вроде в OGSR же есть уже звук щелчка, не? Ща гляну Clear Sky: Gunslinger Addon Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты
Doctor_Oz 29 Опубликовано 25 мая, 2022 Только что, Misery сказал: Если ничего не переименовали, то можно ctrl c ctrl v Не факт, код я брал с СоС'а так что навряд-ли... Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты
Misery 431 Опубликовано 25 мая, 2022 Только что, Doctor_Oz сказал: Да, это возможно, но вроде в OGSR же есть уже звук щелчка, не? Нема Дополнено 0 минут спустя Из весомых отличий могу отметить только, что в OGSR по другому написана загрузка звука Clear Sky: Gunslinger Addon Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты
Doctor_Oz 29 Опубликовано 25 мая, 2022 Только что, Misery сказал: Нема Значит можно добавить, но по OGSR я не помогу, ибо я оттуда ток правки умею тыбзить)) Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты
Misery 431 Опубликовано 25 мая, 2022 (изменено) HUD_SOUND::LoadSound HUD_SOUND::PlaySound HUD_SOUND::StopSound HUD_SOUND::DestroySound Изменено 25 мая, 2022 пользователем Misery Clear Sky: Gunslinger Addon Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты
Misery 431 Опубликовано 25 мая, 2022 Только что, Doctor_Oz сказал: ибо я оттуда ток правки умею тыбзить)) Жиза) Clear Sky: Gunslinger Addon Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты
Doctor_Oz 29 Опубликовано 25 мая, 2022 Добавил новый урок. 1 Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты
Doctor_Oz 29 Опубликовано 27 мая, 2022 Ожидайте в течение недели добавление урока по добавлению рюкзака в двиг!!! P. S. Если у вас возникла та или иная проблема, то напишите мне пожалуйста, дабы я мог исправить ситуацию. Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты
Arkada 428 Опубликовано 27 мая, 2022 Doctor_Oz а не с моих ли это сурсов было взято, из мода "Суждено быть новичком"? Просто возникли подозрения, потому что у меня всё это уже было сделано в исходниках: звук включения фонарика из ОП, 10 слотов под артефакты (в уроке 8), новые слоты за авторством Suhar_ и мой перенос на движок OpenXray, нужная надпись в мини-окне, которая выводит возможные действия с предметом. Если всё это так, то укажите моё авторство + добавьте других авторов, и ещё не забудьте добавить мою систему ремонта на деталях вдобавок к разряжаемым экзоскелетам) А иначе как получается: другие люди написали этот код, ты его сюда выложил, зарабатываешь репутацию на этой теме а создателей не указываешь... Нельзя так. Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты
Doctor_Oz 29 Опубликовано 27 мая, 2022 Только что, liner сказал: Doctor_Oz а не с моих ли это сурсов было взято, из мода "Суждено быть новичком"? Просто возникли подозрения, потому что у меня всё это уже было сделано в исходниках: звук включения фонарика из ОП, 10 слотов под артефакты (в уроке 8), новые слоты за авторством Suhar_ и мой перенос на движок OpenXray, нужная надпись в мини-окне, которая выводит возможные действия с предметом. Если всё это так, то укажите моё авторство + добавьте других авторов, и ещё не забудьте добавить мою систему ремонта на деталях вдобавок к разряжаемым экзоскелетам) А иначе как получается: другие люди написали этот код, ты его сюда выложил, зарабатываешь репутацию на этой теме а создателей не указываешь... Нельзя так. Не-не Авторы данных правок: Новые слоты (сам догадался) Кол-во слотов под артефакты так-же пришлось самому искать. Звук включения фонарика был взят из СоС (Автор мне лично неизвестен) use_caption за авторством Suhar_ был взят из Lex_Addon. 1 Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты
Arkada 428 Опубликовано 27 мая, 2022 Если вы используете наработки из других модов, то пожалуйста, не удаляйте копирайты и оставляйте благодарность автору(ам), ведь это элементарная этика модостроения! Ведь это делается за бесплатно! Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты
Doctor_Oz 29 Опубликовано 27 мая, 2022 Только что, liner сказал: Если вы используете наработки из других модов, то пожалуйста, не удаляйте копирайты и оставляйте благодарность автору(ам), ведь это элементарная этика модостроения! Ведь это делается за бесплатно! Этим я собирался заняться в течение недели, поэтому всех авторов я отмечу, ибо сам понимаю что обидно когда твои труды выдают за свои, а я между прочим не говорил что автор всех этих правок Я. Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты
Arkada 428 Опубликовано 27 мая, 2022 Только что, Doctor_Oz сказал: Кол-во слотов под артефакты так-же пришлось самому искать. Правки у Suhar_ делались на оригинальном двигле, некоторые вещи пришлось переводить самому под рельсы OpenXray. Советую глянуть, что у меня реализовано в двигле. Помню точно, что адаптировал такие моды, как: деградация артефактов из CoC (Автор: Alundaio) расширенные свойства брони из Lex Addon (Автор: Suhar_) ну и то что выше перечислил. Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты
Doctor_Oz 29 Опубликовано 27 мая, 2022 Только что, liner сказал: Правки у Suhar_ делались на оригинальном двигле, некоторые вещи пришлось переводить самому под рельсы OpenXray. Советую глянуть, что у меня реализовано в двигле. Помню точно, что адаптировал такие моды, как: деградация артефактов из CoC (Автор: Alundaio) расширенные свойства брони из Lex Addon (Автор: Suhar_) ну и то что выше перечислил. Но я не говорил что я брал что-то у вас, я всё брал чисто у Lex, про ваш мод слышу впервые... Так что не надо гнать на меня что я у вас что-то украл. А если не верите мне, то я просто могу скинуть все ссылки на те сайты откуда бралось что-либо. Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты
Arkada 428 Опубликовано 27 мая, 2022 (изменено) 8 минут назад, Doctor_Oz сказал: а я между прочим не говорил что автор всех этих правок Я. Есть такие люди. Одного такого помню. Короче, раньше был проект StalkerDVA (именно так он и назывался!!!). Мультиплеер на ЗП, кооператив, все дела... Но только вот автор оказался ещё той крысой... Адаптировал броню из сткопа, ещё из других модов понемножку, и кстати, за основу проекта взял Soproject, который раньше (в годах так 2010-2013) был популярен как мод, где есть кооператив. Я играл и в то, и в другое. Мануэль снимал видео на этот мультиплеерный мод, его популярность возросла. И так вот, разработчик этого "второго сталкера", Вано как он себя называл, сказал, что релизнет новую версию, как только на его кошельке соберётся 5000 рублей. Это уже полный зашквар. Думаю, ты понял, к чему я всё это. Мод потом через полгода окончательно закрылся. Дополнено 1 минуту спустя 3 минуты назад, Doctor_Oz сказал: Так что не надо гнать на меня что я у вас что-то украл. А если не верите мне, то я просто могу скинуть все ссылки на те сайты откуда бралось что-либо. Я и не утверждал, что это мои правки. Без негатива. Изменено 27 мая, 2022 пользователем liner Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты
Doctor_Oz 29 Опубликовано 27 мая, 2022 Только что, liner сказал: Есть такие люди. Одного такого помню. Короче, раньше был проект STALKER 2 (именно так он и назывался!!!). Мультиплеер на ЗП, кооператив, все дела... Но только вот автор оказался ещё той крысой... Адаптировал броню из сткопа, ещё из других модов понемножку, и кстати, за основу проекта взял Soproject, который раньше (в годах так 2010-2013) был популярен как мод, где есть кооператив. Я играл и в то, и в другое. Мануэль снимал видео на этот мультиплеерный мод, его популярность возросла. И так вот, разработчик этого "второго сталкера", Вано как он себя называл, сказал, что релизнет новую версию, как только на его кошельке соберётся 5000 рублей. Это уже полный зашквар. Думаю, ты понял, к чему я всё это. Но я ничего не прошу взамен... Зачем на меня то гнать? Я этого понять не могу. Я во-первых не утверждал что автор правок Я, во-вторых Я не делаю это взамен на что-то. Это делается для таких же людей как Я, ведь даже самая небольшая правка движка занимает уйму времени у новичков. Я конечно тоже мод делаю, но как Я и говорил, Я не собираюсь присваивать чужие правки себе, спрашивается, зачем мне лишние проблемы? 1 Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты
Arkada 428 Опубликовано 27 мая, 2022 К дополнению про StalkerDVA: потом блогер Неважно, кто выложил видео на всю эту суету. У него похожее мнение, что и у меня. Но то видео по-моему, он уже удалил, ибо я его на его канале уже давно не нахожу. Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты
Doctor_Oz 29 Опубликовано 28 мая, 2022 Добрый день. Если у вас после моего урока по добавлению звука щелчка в фонарик нет звука, Я изменил урок, точнее добавил то что нужно в сам фонарик секцию включения и выключения. Вылетать не будет, но и работать звук. P. S. сам только-только разобрался ? Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты
Doctor_Oz 29 Опубликовано 1 июня, 2022 Сделан урок по добавлению рюкзака. Оформление не очень, поэтому прошу оформить модераторов как будет покрасивше. Если у вас будут проблемы касательно этого урока, говорите, поможем. Дополнено 15 минуты спустя Добавил урок по изгнанию Наруто из ГГ. Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты
Doctor_Oz 29 Опубликовано 2 июня, 2022 Добрый день, если у вас есть предложения по урокам, то если возможно я добавлю в шапку темы. Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты