Hardtmuth 5 504 Опубликовано 27 июля, 2020 [SOC] Мелкие правки движка Ковыряемся в исходниках SoC. На данный момент тема ориентирована в большей степени на новичков. Здесь будут собираться готовые решения по мелкому ковырянию исходников движка SoC. Собственно приглашаю всех желающих присоединиться. P.S. обсуждение также приветствуется. Спойлер Колбек - это функция, которая вызывается при определенном событии, например нажатие клавиши, выстрел из оружия, смерть актора и т.д. Создать такой колбек не сложно. Рассмотрим на примере создания колбеков на удары ножом на ЛКМ и ПКМ. Никаких аргументов здесь передаваться не будет, просто вызов функции при ударе. Итак. 1. В файле WeaponKnife.cpp добавим в начало файла после всех инклудов ещё четыре, необходимые для колбеков актора: #include "pch_script.h" #include "script_callback_ex.h" #include "script_game_object.h" #include "alife_object_registry.h" 2. Далее ищем: void CWeaponKnife::switch2_Attacking (u32 state) и после: m_pHUD->animPlay(random_anim(mhud_attack), FALSE, this, state); пишем: g_actor->callback(GameObject::eKnifeAttackOne)(); Аналогично после: m_pHUD->animPlay(random_anim(mhud_attack2), FALSE, this, state); пишем: g_actor->callback(GameObject::eKnifeAttackTwo)(); 3. Далее наши колбеки нужно зарегистрировать: - в файле: game_object_space.h в список колбеков по аналогии в конец добавить: eKnifeAttackOne, eKnifeAttackTwo, И наконец, в: script_game_object_script.cpp по аналогии с другими колбеками добавляем опять же в конец: value("knife_attack_one", int(GameObject::eKnifeAttackOne) ), value("knife_attack_two", int(GameObject::eKnifeAttackTwo) ) Тут стоит немного пояснить: в кавычках тот идентефикатор, который мы зарегистрируем в bind_stalker.script регистрация колбека в bind_stalker.script В функцию: function actor_binder:net_destroy() добавляем: function actor_binder:reinit() добавить: self.object:set_callback(callback.knife_attack_one, self.knife_attack_one, self) self.object:set_callback(callback.knife_attack_two, self.knife_attack_two, self) И добавить функции, которые и будут вызываться при срабатывании колбека: function actor_binder:knife_attack_one() news_manager.send_tip(db.actor, "Удар ЛКМ") --сообщение для теста end function actor_binder:knife_attack_two() news_manager.send_tip(db.actor, "Удар ПКМ") --сообщение для теста end Спойлер Я думаю, многие сталкивались с функцией iterate_inventory, которая перебирает весь инвентарь и для каждого вызывает функцию. Если нам нужно перебрать все предметы на поясе, чтобы проверить, есть там какой-либо предмет или нет, можно, конечно, перебрать весь инвентарь и проверять для каждого предмета на поясе ли он или нет. Но можно создать отдельную функцию, которая будет перебирать предметы только на поясе.1. В файле: script_game_object_script3.cpp ищем iterate_inventory и по аналогии делаем вариант для пояса: .def("iterate_inventory", &CScriptGameObject::IterateInventory) .def("iterate_belt", &CScriptGameObject::IterateBelt) Теперь в script_game_object.h зарегистрируем нашу функцию: void IterateInventory (luabind::functor<void> functor, luabind::object object); void IterateBelt (luabind::functor<void> functor, luabind::object object); И, наконец, в файле: script_game_object_inventory_owner.cpp добавляем саму функцию. Найдите функцию для инвентаря, сделайте также. void CScriptGameObject::IterateBelt (luabind::functor<void> functor, luabind::object object) { CInventoryOwner *inventory_owner = smart_cast<CInventoryOwner*>(&this->object()); if (!inventory_owner) { ai().script_engine().script_log (ScriptStorage::eLuaMessageTypeError,"CScriptGameObject::IterateBelt non-CInventoryOwner object !!!"); return; } TIItemContainer::iterator I = inventory_owner->inventory().m_belt.begin(); TIItemContainer::iterator E = inventory_owner->inventory().m_belt.end(); for ( ; I != E; ++I) functor (object,(*I)->object().lua_game_object()); } Как видите, разница тут лишь в том, что предметы перебираются не все, а только те, которые на поясе: так как вместо m_all мы используем m_belt. Как использовать в скриптах: Используется как и функция iterate_inventory Спойлер 1) UIDiaryWnd2.cpp: void CUIDiaryWnd::LoadJournalTab (ARTICLE_DATA::EArticleType _type) { delete_data (m_ArticlesDB); m_UILeftWnd->AttachChild (m_SrcListWnd); m_SrcListWnd->Show (true); m_UIRightWnd->AttachChild (m_DescrView); m_DescrView->Show (true); if(Actor()->encyclopedia_registry->registry().objects_ptr()) { ARTICLE_VECTOR::const_iterator it = Actor()->encyclopedia_registry->registry().objects_ptr()->begin(); for(; it != Actor()->encyclopedia_registry->registry().objects_ptr()->end(); it++) { if (_type == it->article_type) { // Исправление отображения зеленым цветом прочитанных записей в дневнике КПК AddDiaryArticle(it->article_id, it->readed); } } } g_pda_info_state &= !pda_section::journal; } void CUIDiaryWnd::OnSrcListItemClicked (CUIWindow* w,void* p) { CUITreeViewItem* pSelItem = (CUITreeViewItem*)p; m_DescrView->Clear (); if (!pSelItem->IsRoot()) { CUIEncyclopediaArticleWnd* article_info = xr_new<CUIEncyclopediaArticleWnd>(); article_info->Init ("encyclopedia_item.xml","encyclopedia_wnd:objective_item"); article_info->SetArticle (m_ArticlesDB[pSelItem->GetValue()]); m_DescrView->AddWindow (article_info, true); // Исправление отображения зеленым цветом прочитанных записей в дневнике КПК if (!pSelItem->IsArticleReaded()) { if(Actor()->encyclopedia_registry->registry().objects_ptr()) { for(ARTICLE_VECTOR::iterator it = Actor()->encyclopedia_registry->registry().objects().begin(); it != Actor()->encyclopedia_registry->registry().objects().end(); it++) { if (ARTICLE_DATA::eJournalArticle == it->article_type && m_ArticlesDB[pSelItem->GetValue()]->Id() == it->article_id) { it->readed = true; break; } } } } } } В конце UIDiaryWnd2.cpp дописать: // Исправление отображения зеленым цветом прочитанных записей в дневнике КПК void CUIDiaryWnd::AddDiaryArticle(shared_str article_id, bool bReaded) { m_ArticlesDB.resize(m_ArticlesDB.size() + 1); CEncyclopediaArticle*& a = m_ArticlesDB.back(); a = xr_new<CEncyclopediaArticle>(); a->Load(article_id); CreateTreeBranch(a->data()->group, a->data()->name, m_SrcListWnd, m_ArticlesDB.size()-1, m_pTreeRootFont, m_uTreeRootColor, m_pTreeItemFont, m_uTreeItemColor, bReaded); } 2) UIDiaryWnd.h: void UnloadNewsTab (); void LoadNewsTab (); void Reload (EDiaryFilter new_filter); // Исправление отображения зеленым цветом прочитанных записей в дневнике КПК void AddDiaryArticle (shared_str, bool bReaded); Спойлер Я использую ревизию с XP DEV, там уже проведена работа над слотами. Если кто-то использует другую версию исходников, могут быть различия. Создадим слот для второго детектора:В UIInventoryWnd.cpp после: m_pUISlotQuickAccessList_3 = xr_new<CUIDragDropListEx>(); AttachChild(m_pUISlotQuickAccessList_3); m_pUISlotQuickAccessList_3->SetAutoDelete(true); xml_init.InitDragDropListEx (uiXml, "dragdrop_slot_quick_access_3", 0, m_pUISlotQuickAccessList_3); BindDragDropListEnents (m_pUISlotQuickAccessList_3); добавим: m_pUIDetAdvList = xr_new<CUIDragDropListEx>(); AttachChild(m_pUIDetAdvList); m_pUIDetAdvList->SetAutoDelete(true); xml_init.InitDragDropListEx (uiXml, "dragdrop_slot_det_adv", 0, m_pUIDetAdvList); BindDragDropListEnents (m_pUIDetAdvList); после: m_slots_array[SLOT_QUICK_ACCESS_3] = m_pUISlotQuickAccessList_3; добавить: m_slots_array[DET_ADV_SLOT] = m_pUIDetAdvList; В UIInventoryWnd.h после: CUIDragDropListEx* m_pUISlotQuickAccessList_3; добавить: CUIDragDropListEx* m_pUIDetAdvList; В файле: uiinventorywnd2.cpp сразу после: _itm = m_pInv->m_slots[SLOT_QUICK_ACCESS_3].m_pIItem; if(_itm) { CUICellItem* itm = create_cell_item(_itm); m_pUISlotQuickAccessList_3->SetItem (itm); } добавим: _itm = m_pInv->m_slots[DET_ADV_SLOT].m_pIItem; if(_itm) { CUICellItem* itm = create_cell_item(_itm); m_pUIDetAdvList->SetItem (itm); } после: m_pUISlotQuickAccessList_3->ClearAll (true); добавим: m_pUIDetAdvList->ClearAll (true); В файле UIInventoryWnd3.cpp после: case INVENTORY_TO_SLOT15_ACTION: CurrentIItem()->SetSlot(SLOT_QUICK_ACCESS_3); break; добавим: case INVENTORY_TO_SLOT16_ACTION: CurrentIItem()->SetSlot(DET_ADV_SLOT); break; В файле inventory_space.h после: #define SLOT_QUICK_ACCESS_3 15 добавить: #define DET_ADV_SLOT 16 Также вносим изменения в slots_total. Число должно быть на один больше последнего номера слотов. В нашем случае будет вот так: #define SLOTS_TOTAL 17 В файле UIMessages.h после: INVENTORY_TO_SLOT15_ACTION, пишем: INVENTORY_TO_SLOT16_ACTION, Осталось только зарегистрировать наш новый слот в конфигах игры по аналогии с остальными: В inventory_new.xml и в inventory_new_16: <dragdrop_slot_det_adv x="581" y="673" width="100" height="50" cell_width = "48" cell_height="50" rows_num="1" cols_num="2" custom_placement="0" show_grid = "0"/> И в system.ltx: slot_persistent_1 = false ;нож 0 slot_persistent_2 = false ;пистолет 1 slot_persistent_3 = false ;автомвт 2 slot_persistent_4 = true ;гранаты 3 slot_persistent_5 = false ;бинокль 4 slot_persistent_6 = true ;болт 5 slot_persistent_7 = false ;костюм 6 slot_persistent_8 = false ;пда 7 slot_persistent_9 = false ;детектор 8 slot_persistent_10 = false ;фонарь 9 slot_persistent_11 = true ;артефакт 10 slot_persistent_12 = false ;шлем 11 slot_persistent_13 = false ;яч1 12 slot_persistent_14 = false ;яч2 13 slot_persistent_15 = false ;яч3 14 slot_persistent_16 = false ;яч4 15 slot_persistent_17 = false ;детектор 2 16 Спойлер В CoP некоторые модификации броников увеличивают скорость восстановления здоровья, энергии и т.д. В оригинале ТЧ есть пара уникальных костюмов, в которых даже прописан параметр health_restore_speed, но конечно же, он не работает. Добавить эти параметры очень просто:В CustomOutfit.cpp после: m_HitTypeProtection[ALife::eHitTypePhysicStrike]= READ_IF_EXISTS(pSettings, r_float, section, "physic_strike_protection", 0.0f); Добавим: m_fHealthRestoreSpeed = READ_IF_EXISTS(pSettings, r_float, section, "health_restore_speed", 0.0f ); m_fRadiationRestoreSpeed = READ_IF_EXISTS(pSettings, r_float, section, "radiation_restore_speed", 0.0f ); m_fSatietyRestoreSpeed = READ_IF_EXISTS(pSettings, r_float, section, "satiety_restore_speed", 0.0f ); m_fPowerRestoreSpeed = READ_IF_EXISTS(pSettings, r_float, section, "power_restore_speed", 0.0f ); m_fBleedingRestoreSpeed = READ_IF_EXISTS(pSettings, r_float, section, "bleeding_restore_speed", 0.0f ); Сразу хочу заметить, что если в конфиге будет отсутствовать один из новых параметров, его значение будет равным 0.0. Идем дальше. В файле CustomOutfit.h после: public: float m_additional_weight; float m_additional_weight2; добавим: float m_fHealthRestoreSpeed; float m_fRadiationRestoreSpeed; float m_fSatietyRestoreSpeed; float m_fPowerRestoreSpeed; float m_fBleedingRestoreSpeed; Теперь эти параметры читаются, но пока ещё никак не используются. Для их использования в Actor.cpp после, например: float CActor::HitArtefactsOnBelt (float hit_power, ALife::EHitType hit_type) { float res_hit_power_k = 1.0f; float _af_count = 0.0f; ................................................................................ res_hit_power_k -= _af_count; return res_hit_power_k * hit_power; } Добавим: #define OUTFIT_UPDATE_TIME 0.100f #include "CustomOutfit.h" void CActor::UpdtateOutfitInSlot() { static float update_time = 0; float f_update_time = 0; if(update_time<OUTFIT_UPDATE_TIME) { update_time += conditions().fdelta_time(); return; } else { f_update_time = update_time; update_time = 0.0f; } CCustomOutfit* outfit = GetOutfit(); if(outfit) { conditions().ChangeBleeding(outfit->m_fBleedingRestoreSpeed*f_update_time); conditions().ChangeHealth(outfit->m_fHealthRestoreSpeed*f_update_time); conditions().ChangePower(outfit->m_fPowerRestoreSpeed*f_update_time); conditions().ChangeSatiety(outfit->m_fSatietyRestoreSpeed*f_update_time); #ifndef OBJECTS_RADIOACTIVE // alpet: отключается для избежания двойного хита conditions().ChangeRadiation (outfit->m_fRadiationRestoreSpeed*f_update_time); #endif } } Теперь после: //для свойств артефактов, находящихся на поясе UpdateArtefactsOnBelt (); добавим: UpdtateOutfitInSlot (); Теперь в Actor.h после: //свойства артефактов virtual void UpdateArtefactsOnBelt (); virtual void MoveArtefactBelt (const CArtefact* artefact, bool on_belt); virtual float HitArtefactsOnBelt (float hit_power, ALife::EHitType hit_type); const xr_vector<const CArtefact*>& ArtefactsOnBelt() {return m_ArtefactsOnBelt;} добавим: //свойства брони virtual void UpdtateOutfitInSlot (); Спойлер Думаю из названия всё понятно. Создадим кнопку, которую можно будет легко изменять в опциях, а при нажатии будет вызываться функция из скрипта. В файле: ActorInput.cpp после: #include "../../build_config_defines.h" добавим: #include "pch_script.h" #include "InventoryOwner.h" #include "script_game_object.h" #include "script_game_object_impl.h" На самом деле я точно не уверен, что нужны все четыре инклуда, возможно в этом файле я прописывал инклуд для чего-то ещё. Но на всякий случай добавьте все четыре. Также, например после: case kCROUCH_TOGGLE: { g_bAutoClearCrouch = !g_bAutoClearCrouch; if (!g_bAutoClearCrouch) mstate_wishful |= mcCrouch; }break; Добавим: case kCLOCK: { luabind::functor<void> clock_key; if (ai().script_engine().functor("gz_items_hud.clock_key",clock_key)) clock_key(); }break; Как видите у меня здесь кнопка показа часов. "gz_items_hud.clock_key" это как раз скрипт и функция, которые будут вызваны при нажатии кнопки. Теперь в файле key_binding_registrator_script.cpp в: class_<enum_exporter<EGameActions> >("key_bindings") .enum_("commands") [ по аналогии с остальным добавим: value("kCLOCK", int(kCLOCK)), Если будете добавлять в самый конец, не забудьте убрать запятую после двойной скобки. Потом в файле: xr_level_controller.cpp добавим по аналогии с остальными: { "clock", kCLOCK ,_sp}, Как я понял, _sp - работает в одиночной игре, _both в одиночной и мультиплеере, _mp - только в мультиплеере. Но это нужно проверять. Я мультиплеер не использую, стоит _sp и пускай себе стоит. Теперь в xr_level_controller.h добавим: kCLOCK, к другим кнопкам. Кстати таким образом, если это необходимо, можно заменить какое-то движковое действие на скриптовое. Просто ищем case kНУЖНАЯ КНОПКА: и меняем "начинку" на свою. Всё, в движке кнопка имеется, переходим к конфигам:Файл u\ui_keybinding.xml добавим в нужную группу кнопок: <command id="kb_clock" exe="clock"/> Теперь в test\rus\ui_st_keybinding.xml: <string id="kb_clock"> <text>Часы</text> </string> Если вы хотите чтобы по умолчанию кнопка была уже установлена, ищем файл default_controls.ltx в папке config оттуда берутся данные о том, какую кнопку на какое действие назначить при создании игрой файла user.ltx Просто пишем: bind clock kC Функция в скрипте самая обычная: --//*** ЧАСЫ НА РУКЕ function clock_key() -- вызывается из движка при нажатии кнопки часов --действия при нажатии кнопки end На этом всё. Правда я не проверял, что будет, если скрипта или функции не существует. Спойлер Source - https://yadi.sk/d/LYCNOX-buFd7a Добавлены параметры для аномалий: ; это настройки онлайн спавна spawn_blowout_artefacts = on ; главный переключатель возможности рождения artefact_spawn_probability = 0.05 ;вероятность, что во время срабатывания аномалии будет рожден артефакт ; добавленные мной birth_on_death_probability = 0.2 ; вероятность рождения артефакта после смерти существа в аномалии birth_on_torn_probability = 0.5 ; вероятность рождения артефакта при разрыве тела в мясорубке birth_on_nonalive = true ; возможность рождения при срабатывании на предмет birth_on_alive = true ; возможность рождения при срабатывании на живое существо birth_on_dead = true ; возможность рождения при срабатывании на труп 1 1 Как оформить тему Правила форума Вопросы по сайту Личное пространство на Trello Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты
Gowther 46 Опубликовано 15 декабря, 2020 (изменено) Есть у вас исходники движка? Поделитесь, кто нибудь, пожалуйста upd: вроде как нашёл Изменено 15 декабря, 2020 пользователем Gowther Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты
Alex Kireev 18 Опубликовано 19 июня, 2021 А можно статью или ссылку на то где будет рассказываться работа с движком от начала и до конца, то есть раскажеться что где скачать, как редактировать, как сохранить, распоковать/запоковать и прочие ньюансы, не понятные новичкам по редактированию движка Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты
Stern-13 2 707 Опубликовано 20 июня, 2021 В 19.06.2021 в 13:06, Alex Kireev сказал: А можно статью или ссылку на то где будет рассказываться работа с движком от начала и до конца, то есть раскажеться что где скачать, как редактировать, как сохранить, распоковать/запоковать и прочие ньюансы, не понятные новичкам по редактированию движка Без знаний C++ или похожих на него движков в дословном гайде смысла нет, иначе автору придется делать все за этих новичков. Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты