Это популярное сообщение. Kondr48 314 Опубликовано 15 Августа 2016 Это популярное сообщение. Поделиться Опубликовано 15 Августа 2016 (изменено) Ковыряемся в исходниках SoC. На данный момент тема ориентирована в большей степени на новичков. Здесь будут собираться готовые решения по мелкому ковырянию исходников движка SoC. Собственно приглашаю всех желающих присоединиться. Сборка исходников, необходимые программы. Расширения для диалогов: Скрытый текст Один из вариантов реализации случайных фраз у диалогов. Автор: Winsor. Часть 2. + немного переделанная функция дампа xml Автор: Winsor. Исправление ошибок: Скрытый текст Исправление отображения зеленым цветом прочитанных записей в разделе КПК "Дневник". Автор: lvg_brest Маленькое исправление колбека before save. Нашел: Карлан. Исправление сохранения клиентских объектов. Автор: Shoker Фикс вертикальной синхронизации (r2) Автор: SkyLoader Фикс не отключения ПНВ при удалении броника ф-циями release\transfer_item или продаже\выкладывании в другой инвентарь, автор: UnLoaded Исправление вылета по отсутствию звука. Путь до звука выводится в лог (как с текстурами в ЗП). Исправление пулестойкости костюма. Расширение скриптового функционала: Скрытый текст Функции, возвращающие текущий год и месяц. Функция перемотки времени из CoP. Создание колбеков для Актора на примере колбека на удар ножом. Назначение скриптам горячих клавиш, изменяемых в главном меню. Создание функции, перебирающей предметы на поясе. Работа с интерфейсом (худ, инвентарь и т.п.): визуальная часть: Скрытый текст Редактирование загрузочного экрана. Создание нового индикатора на худе. Расширение геймплея: Скрытый текст Создание нового слота. Новые параметры для бронежилетов. Восстановление функции рождения артефактов при срабатывании аномалии. Автор: Bak Добавление изменения переносимого веса в свойства артефактов. Массовое перемещение предметов между окнами, Автор: UnLoaded Зум в один клик. Автор: Shkiper2012. Дополнение: Kondr48 Порция мелких правок от Shkiper2012. Работа с рендером: Скрытый текст Скриншоты в формате png. Изменено 2 Ноября 2017 пользователем Kondr48 4 13 Ссылка на комментарий
Это популярное сообщение. Kondr48 314 Опубликовано 15 Августа 2016 Автор Это популярное сообщение. Поделиться Опубликовано 15 Августа 2016 (изменено) Создание колбеков для Актора на примере колбека на удар ножом Колбек - это функция, которая вызывается при определенном событии, например нажатие клавиши, выстрел из оружия, смерть актора и т.д. Создать такой колбек не сложно. Рассмотрим на примере создания колбеков на удары ножом на ЛКМ и ПКМ. Никаких аргументов здесь передаваться не будет, просто вызов функции при ударе. Итак. 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)(); должно получиться: Скрытый текст void CWeaponKnife::switch2_Attacking (u32 state) { if(m_bPending) return; if(state==eFire) { m_pHUD->animPlay(random_anim(mhud_attack), FALSE, this, state); g_actor->callback(GameObject::eKnifeAttackOne)(); } else { m_pHUD->animPlay(random_anim(mhud_attack2), FALSE, this, state); g_actor->callback(GameObject::eKnifeAttackTwo)(); } m_attackStart = true; m_bPending = true; } 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 Скрытый текст В функцию: function actor_binder:net_destroy() добавляем: self.object:set_callback(callback.knife_attack_one, nil) self.object:set_callback(callback.knife_attack_two, nil) В функцию 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 db.actor:iterate_belt(clear_belt, db.actor) --вызываем в нужном месте. clear_belt - функция, которая вызовется для каждого предмета на поясе. function clear_belt(npc, item) db.actor:move_to_ruck(item) --действие с предметом. Например перемещение в рюкзак. end Исправление отображения зеленым цветом прочитанных записей в разделе КПК "Дневник" by lvg_brest: Скрытый текст 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, Регистрация слота в конфигах игры: 1. В 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"/> 2. В 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 Изменено 22 Июня 2017 пользователем Kondr48 3 2 3 Ссылка на комментарий
Kober(BRUC) 99 Опубликовано 15 Августа 2016 Поделиться Опубликовано 15 Августа 2016 (изменено) Хотел бы узнать план. Какие еще "уроки" будут в ближайшее время? Изменено 15 Августа 2016 пользователем Kondr48 Добавлено Kondr48, 15 Августа 2016 Как такового плана нет. Просто в процессе своих мелких правок решил описывать, как и что делаю. Так по мере работы буду выкладывать. Ссылка на комментарий
Это популярное сообщение. Kondr48 314 Опубликовано 15 Августа 2016 Автор Это популярное сообщение. Поделиться Опубликовано 15 Августа 2016 (изменено) Новые параметры для бронежилетов. Скрытый текст В 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 На этом всё. Правда я не проверял, что будет, если скрипта или функции не существует. Изменено 22 Июня 2017 пользователем Kondr48 3 1 5 Ссылка на комментарий
CRAZY_STALKER666 36 Опубликовано 15 Августа 2016 Поделиться Опубликовано 15 Августа 2016 Может не по теме, помещу под спойлер, но все же: В рамках 1.0004 - как убрать красную надпись в режиме demo_record. Убрать нормально, способ "потыкать на кнопочки" приводит к записи демо, что не нужно, и убрает весь худ пока не удалишь user.ltx. Интересно именно удаление вызова отрисовки текста в движке.Искал такие вещи в интернетах, есть для 1.0006 - и то ссылка не пашет.А тема идеально вроде подходит) Не соответствует правилам. Ссылка на комментарий
Kondr48 314 Опубликовано 15 Августа 2016 Автор Поделиться Опубликовано 15 Августа 2016 (изменено) CRAZY_STALKER666, в исходниках вот здесь стоит посмотреть: FDemoRecord.cpp if (psHUD_Flags.test(HUD_DRAW)){ if ((Device.dwTimeGlobal/750)%3!=0) { // pApp->pFontSystem->SetSizeI (0.02f); pApp->pFontSystem->SetColor (color_rgba(255,0,0,255)); pApp->pFontSystem->SetAligment(CGameFont::alCenter); pApp->pFontSystem->OutSetI (0,-.05f); pApp->pFontSystem->OutNext ("%s","RECORDING"); pApp->pFontSystem->OutNext ("Key frames count: %d",iCount); pApp->pFontSystem->SetAligment(CGameFont::alLeft); pApp->pFontSystem->OutSetI (-0.2f,+.05f); pApp->pFontSystem->OutNext ("SPACE"); pApp->pFontSystem->OutNext ("BACK"); pApp->pFontSystem->OutNext ("ESC"); pApp->pFontSystem->OutNext ("F11"); pApp->pFontSystem->OutNext ("F12"); pApp->pFontSystem->SetAligment(CGameFont::alLeft); pApp->pFontSystem->OutSetI (0,+.05f); pApp->pFontSystem->OutNext ("= Append Key"); pApp->pFontSystem->OutNext ("= Cube Map"); pApp->pFontSystem->OutNext ("= Quit"); pApp->pFontSystem->OutNext ("= Level Map ScreenShot"); pApp->pFontSystem->OutNext ("= ScreenShot"); } } А в рамках 4 патча даже не знаю: хексом мб это искать и закомментировать. По сути это и смысл использования исходников: нашел то, что нужно и подправил/дописал. А так по сути тема больше для правок исходников. Изменено 15 Августа 2016 пользователем Kondr48 1 Ссылка на комментарий
НаноБот 728 Опубликовано 15 Августа 2016 Поделиться Опубликовано 15 Августа 2016 (изменено) Я, кстати, категорически против что колбеки вешали исключительно на актора, т.е. колбек на удар ножом вешаем на объект (биндер) ножа, передаём точку, вектор и силу удара, так же на выстрел из оружия, любого, ручного, станкового, БТР'а, вертолёта вешаем на сам объект, а не на несчастного актора. А то получается полная солянка, а не скриптинг. Поверьте так гораздо удобней и соответствует ООП. А так же, колбек на нажатие клавиш должен быть не только на акторе, но и на активный управляемый объект, это: актив итем(оружие которое держим в руках), текущий холдер(техника в которой сидим), активный детектор(который держим в руках). Я эти идеи частично реализовал в своём проекте XRay-Extensions NanoBot. Изменено 15 Августа 2016 пользователем НаноБот 1 ...в конце концов, важен лишь, машинный код. СТАЛКЕР только для ПК! Ссылка на комментарий
Kondr48 314 Опубликовано 15 Августа 2016 Автор Поделиться Опубликовано 15 Августа 2016 (изменено) НаноБот, если колбек нужен будет не только актору, то да. Согласен. Однако в случае с ножом, есть ли в этом смысл, если этот колбек будет использоваться только для актора? P.S. Нет желания подкинуть сюда пару статеек по работе на исходниках? К примеру адаптацию Вашего проекта новая баллистика? Или те же колбеки? Изменено 22 Января 2017 пользователем Kondr48 1 Ссылка на комментарий
Это популярное сообщение. Bak 753 Опубликовано 16 Августа 2016 Это популярное сообщение. Поделиться Опубликовано 16 Августа 2016 (изменено) Восстановление функции рождения артефактов при срабатывании аномалии. сурс CustomZone.cpp CustomZone.h Mincer.cpp Mincer.h Добавлены варианты спавна: - При смерти существа внутри аномалии - При разрыве тела в мясорубке ; это настройки онлайн спавна 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 ; возможность рождения при срабатывании на труп Изменено 16 Августа 2016 пользователем Bak 2 7 6 Ссылка на комментарий
Dennis_Chikin 3 658 Опубликовано 12 Октября 2016 Поделиться Опубликовано 12 Октября 2016 (изменено) По поводу коллбэков возникает вопрос: а точно ли все, что есть именно в виде коллбэков и все, что планируется добавить, надо делать именно "коллбэками" ? Там разного обрамления ненужного не слишком многовато получается ? То есть, смотрите, вот есть, например, оружие. Или арты. Или там какие-нибудь бочки-огнетушители. Сейчас там по умолчанию стоят "затычки", которые есть-пить не просят. Возникает мысль добавить этот самый "коллбэк". Добавляем. Начинаем прописывать в конфигах, script_binding =, все вот эти вот load/save/init/reinit/update и прочую ересь совсем не нужную, разгребать те скрипты, которые сто лет ни кто не трогал, потому что ни за каким надом нужны не были... То есть, куча работы и накладных расходов. И, да, само вот это вот "а на актора или еще куда" Может, подумать уже какой другой механизм ? P.S. Нет желания подкинуть сюда пару статеек по работе на исходниках? Поддерживаю. Кто уже довольно неплохо разгреб, в каких файлах функциях что лежит - может поделитесь ? Изменено 12 Октября 2016 пользователем Dennis_Chikin 2 Солянка обезжиренная, диетическая, полезные советы по "солянке", текущий тестовый патч Ссылка на комментарий
Winsor 177 Опубликовано 1 Ноября 2016 Поделиться Опубликовано 1 Ноября 2016 (изменено) добавление, например, на выстрел в Вашем примере - это всего лишь вызов в нужном месте что нибудь типа псевдокод вызова калбека на выстрел из класса оружия auto source=this; if (m_Owner==Actor()) { source=Actor(); } source->callback(типкалбекахит)(кто_стрелял, из_чего, чем); теперь в классе актора, или сталкера (да, нужен скриптовый класс биндера "script_binding= ", иначе у чего будет движок вызывать эти методы при их наличии?) регистрируем этот калбек через set_callback в одном вызове (ну и в одном очищаем) - чаще всего init/net_destroy. все, дальше обрабатываем так как надо. никаких load/save/update не требуется. еще один пример - реализация калбека на хит по объекту. движком генерируем вызов этого калбека из CGameObject (прародителя усех объектов в луа). в самих скриптах только в объектах (биндере), например, бочки делаем обработку этого калбека - и все, обрабатываются только бочки. И, да, само вот это вот "а на актора или еще куда Само собой, иногда приходиться идти на хитрость - есть окно инвентаря - вот куда ему добавить перехват калбека , если по умолчанию, ни сам класс этого окна не экспортируется в игру (это полбеды), ни в игре нету дочернего класса от CUIInventoryWnd, чтобы на нем добавить обработчики (как это например сделано для главного меню). Но со вторым вариантом возиться долго и не интересно. проще всегда делать Actor()->callback(калбек_из_окна)(окно_каллбека, другие параметры) и в биндере актора перехватить это калбек. все, чесно и прозрачно. Придумывать единый механизм, отличный от Actor() для таких целей - ну не знаю, не уверен что это окупиться. Кто уже довольно неплохо разгреб, в каких файлах функциях что лежит - может поделитесь Поделиться чем? в движке примерно 4к файлов *.cpp. Сформулируйте вопрос... Изменено 4 Января 2017 пользователем Kondr48 Немного подправил цитаты. 1 Ссылка на комментарий
UnLoaded 313 Опубликовано 26 Декабря 2016 Поделиться Опубликовано 26 Декабря 2016 (изменено) Создание нового слота ... после: m_slots_array[sLOT_QUICK_ACCESS_3] = m_pUISlotQuickAccessList_3; ... У меня нет нигде m_slots_array. Результат поиска в 4611 файлах - 0. Версия исходников 1.0007(rc1). Если пропустить все, касаемо m_slots_array - работать новый слот будет ? Изменено 26 Декабря 2016 пользователем UnLoaded Ссылка на комментарий
Kondr48 314 Опубликовано 29 Декабря 2016 Автор Поделиться Опубликовано 29 Декабря 2016 (изменено) UnLoaded, Версия исходников 1.0007(rc1) Ну это еще не аргумент. Я например форкнулся с r180 с репозитория на xp-dev, собственно туторы по этой версии я и писал. Если у Вас именно "чистые" исходники, то для начала вам нужно добавить туда все недостоющие части кода по слотам из этой (или более высокой, если хотите) ревизии. А если ревизия итак оттуда, то, по данному "тутору" слоты легко создаются и m_slots_array там присутствует. Изменено 29 Декабря 2016 пользователем Kondr48 Ссылка на комментарий
Rygiy 3 Опубликовано 4 Января 2017 Поделиться Опубликовано 4 Января 2017 (изменено) Восстановление функции рождения артефактов при срабатывании аномалииКаким образом и куда вставлять данные файлы? Увы, у меня нет исходников, а если бы и были, то что потом делать с исходниками? (при слиянии потерялась вторая заметка) Вот то и делать: ставить visual studio, и разбираться, как оно работает. (Если честно, то я это поделие так и не осилил - слишком много окошечек и кнопочек.) dc Изменено 27 Января 2017 пользователем Dennis_Chikin Добавлено Kondr48, 4 Января 2017 В исходники, куда же еще.ваша_папка_исходников\trunk\xray\xr_3da\ Ссылка на комментарий
Kondr48 314 Опубликовано 22 Января 2017 Автор Поделиться Опубликовано 22 Января 2017 (изменено) Все мы с Вами знаем, что в ЗП добавлен ряд интересных и полезных индикаторов на худе. На самом деле добавить их легко. Разберем на примере индикатора поломки брони. Для начала, в движке CoP есть такой удобный инструмент как UIHelper, для дальнейшей работы он нам понадобится, поэтому добавляем в xrGame\ui: 1. UIHelper.h //////////////////////////////////////////////////////////////////////////// // Module : UIHelper.h // Created : 17.01.2008 // Author : Evgeniy Sokolov // Description : UI Helper class //////////////////////////////////////////////////////////////////////////// #ifndef UI_HELPER_H_INCLUDED #define UI_HELPER_H_INCLUDED class CUIXml; class CUIWindow; class CUIStatic; class UIHelper { public: UIHelper () {}; ~UIHelper () {}; static CUIStatic* CreateStatic ( CUIXml& xml, LPCSTR ui_path, CUIWindow* parent ); }; #endif // UI_HELPER_H_INCLUDED 2. UIHelper.cpp: //////////////////////////////////////////////////////////////////////////// // Module : UIHelper.cpp // Created : 17.01.2008 // Author : Evgeniy Sokolov // Description : UI Helper class implementation //////////////////////////////////////////////////////////////////////////// #include "StdAfx.h" #include "UIHelper.h" #include "UIXmlInit.h" CUIStatic* UIHelper::CreateStatic( CUIXml& xml, LPCSTR ui_path, CUIWindow* parent ) { CUIStatic* ui = new CUIStatic(); if(parent) { parent->AttachChild ( ui ); ui->SetAutoDelete ( true ); } CUIXmlInit::InitStatic ( xml, ui_path, 0, ui ); return ui; } Здесь я оставил только добавление статика, на самом деле в ЗП с помощью этого инструмента можно все что угодно добавлять. Переносите себе по мере необходимости , идем дальше. Нам нужен файл UIMainIngameWnd.h в группе protected: находим: CUIZoneMap* UIZoneMap; И после добавляем: CUIStatic* m_ind_outfit_broken; Теперь файл UIMainIngameWnd.cpp. Сначала не забудьте прописать #include "UIHelper.h" в начале файла там где все остальные. Находим: void CUIMainIngameWnd::Init() К примеру, после: m_UIIcons = xr_new<CUIScrollView>(); m_UIIcons->SetAutoDelete(true); xml_init.InitScrollView (uiXml, "icons_scroll_view", 0, m_UIIcons); AttachChild (m_UIIcons); Добавим: m_ind_outfit_broken = UIHelper::CreateStatic(uiXml, "indicator_outfit_broken", this); Затем находим: void CUIMainIngameWnd::Update() И, например, перед: // health&power UIHealthBar.SetProgressPos (m_pActor->GetfHealth()*100.0f); UIMotionIcon.SetPower (m_pActor->conditions().GetPower()*100.0f); Добавим: PIItem pItem = m_pActor->inventory().ItemFromSlot(OUTFIT_SLOT); m_ind_outfit_broken->Show(false); if (pItem) { float condition = pItem->GetCondition(); if (condition<0.75f) { m_ind_outfit_broken->Show(true); if(condition>0.5f) m_ind_outfit_broken->InitTexture("ui_inGame2_circle_Armorbroken_green"); else if(condition>0.25f) m_ind_outfit_broken->InitTexture("ui_inGame2_circle_Armorbroken_yellow"); else m_ind_outfit_broken->InitTexture("ui_inGame2_circle_Armorbroken_red"); } } Теперь разберем что нужно будет сделать в конфигах. indicator_outfit_broken это имя статика. Добавить надо его в maingame.xml вот так: <indicator_outfit_broken x="980" y="410" width="26" height="35" stretch="1"/> ну и, соответственно, "зарегистрировать" в игре вот эти текстуры: "ui_inGame2_circle_Armorbroken_green" "ui_inGame2_circle_Armorbroken_yellow" "ui_inGame2_circle_Armorbroken_red" На этом всё . Собственно у меня по такой схеме сделаны все подобные иконки, потому что система ТЧ показалась мне неоправданно сложной и громоздкой. Ну, быть может, это на мой дилетантский взгляд. P.S. Конечно, лучше совместить прогресс бар, который показывает состояние брони и этот индикатор. Чтобы два раза не дергать состояние костюма на апдейте. Но я не стал усложнять урок) Изменено 22 Января 2017 пользователем Kondr48 1 Ссылка на комментарий
Winsor 177 Опубликовано 27 Января 2017 Поделиться Опубликовано 27 Января 2017 Поговорим немного о диалогах в ТЧ 1.0007. Наверное, большинство знают что диалоги (как, например, и артикли в энциклопедии) являются объектами, которые загружаются один раз за всю сессию игры (на основании паттерна Singleton) в структуру SPhraseDialogData : CSharedResource. т.е. если мы разрабатываем диалог, то для проверки того что именно мы написали необходимо выйти и зайти в игру полностью. Само собой это сводит на нет полностью работу с диалогами, создаваемыми скриптами (через експорт функций класса CPhraseDialog). Но часто хочется оживить Зону и разнообразить диалоги. 1) расширяем чуть чуть экспорт CPhraseDialog Добавляем в экспорт CPhraseDialog функцию SetPriority для изменения приоритета нашего диалога. Теперь он выглядит вот так: class_<CPhraseDialog>("CPhraseDialog") .def("AddPhrase", &CPhraseDialog::AddPhrase_script ) .def("SetPriority", &CPhraseDialog::SetPriority), Этим мы можем при создании диалогов помещать начало нашего графа , например, в самый верх или них списка начальных фраз. 2) В связи с тем что 80-90% диалогов все таки статические (им хватает для жизни preconditions) - добавляем параметр, который позволит управлять, обновлять ли диалог каждый раз, или только при первой загрузке в структуру struct SPhraseDialogData : CSharedResource добавляем поле-признак, например, bool b_bForceReload. в класс CPhraseDialog два метода public: void SetDialogForceReload(bool value=false) {data()->b_bForceReload=value;} bool GetDialogForceReload() {return data()->b_bForceReload;} CPhraseDialog::load_shared после SetCaption, например, добавляем SetDialogForceReload(pXML->ReadAttribInt(dialog_node, "force_reload", 0)==1? true:false); т.е. при наличии в конфиге диалога параметра force_reload="1" он помечается как перезагружаемый <dialog id="test_dynamic" force_reload="1"> <init_func>subtest.gen_dialog1</init_func> </dialog> 3) Добавляем в класс окна диалогов признак, который указывает, что окно в данный момент инициализируется. Это нужно в связи с тем что CPhraseDialogManager::AddAvailableDialog может вызываться из других мест, не только из инициализатора окна диалога. позволяет избежать, например, перестроения диалога, когда он уже начат с кем то из НПС. в класс CUITalkWnd добавляем protected: bool m_bInitState; public: bool GetInitState() const {return m_bInitState;} и инициализацию m_bInitState=false в конструктор класса. в методе void CUITalkWnd::InitTalkDialog() в начале пишемm_bInitState=true;и аналогично в концеm_bInitState=false;Теперь мы имеем признак того что CUITalkWnd инизиализирует графы диалогов. 4) Изменяем метод загрузки данных для конкретного диалога с использованием методов CSharedResource void CPhraseDialog::Load(shared_str dialog_id) { m_DialogId = dialog_id; bool need_load=inherited_shared::start_load_shared(m_DialogId); //делаем инициализацию SPhraseDialogData* при первом вызове. если синглтон не был создан ранее - он создается, иначе возвращается созданный //результат функции - это флаг, указывающий, требуется ли загрузка данных при первичной инициализации. if (need_load) //структура создается первый раз, ее надо просто загрузить, также таким образом можно избежать двойного вызова метода загрузки inherited_shared::load_shared(m_DialogId, nullptr); else if (GetDialogForceReload()) //структура уже создавалась и загружалась ранее { //но установлен флаг для принудительной перезагрузки CUIGameSP* ui_sp = smart_cast<CUIGameSP*>(HUD().GetUI()->UIGame()); if (ui_sp && ui_sp->TalkMenu->GetInitState()) //перезагружаем данные только тогда, когда идет инициализация окна диалога { data()->SetLoad(false);//для структуры SPhraseDialogData устанавливаем флаг принудительной загрузки inherited_shared::load_shared(m_DialogId, nullptr); //обновляем данные //inherited_shared::finish_load_shared вызывать не обязательно, так как load_shared уже выполняет его функционал. } } } Все. теперь при каждом открытии окна диалога у Вас будет перезагружаться скрипт subtest.gen_dialog1, который Вам позволит генерировать случайные фразы, например, через math.random Также, параметр force_reload можно использовать и для перезагрузки на моменте отладки и построения диалогов из конфига xml, но надо учитывать, что данный метод не перезагружает скрипты, которые используются в precondition, строковые константы в других xml файлах и подобные внешние ресурсы. Добавлено Kondr48, 31 Января 2017 Хотелось бы добавить, что для успешной сборки в PhraseDialog.cpp нужно добавить инклуды: #include "UIGameSp.h" #include "HUDManager.h" #include "level.h" #include "ui\UITalkWnd.h" Заметка изменена 4 Апреля 2018 3 Ссылка на комментарий
Карлан 1 049 Опубликовано 27 Января 2017 Поделиться Опубликовано 27 Января 2017 @Winsor, слишком муторный подход, мы просто убрали прокладки. Вот же я показывал: Диалог загружается каждый раз при обращении к нему со всеми своими потрохами. Всея динамика как есть, графы, фразы и все что угодно можно переделывать по ходу игры безо всяких пометок. Диалоги перегружаются и во время самого разговора, поэтому у меня даже сделан флаг для локального запоминания фразы (чтобы она не менялась): function create_bye_phrase() if not bye_phr_idx then bye_phr_idx = math.random(4) bye_phr_idx = bye_phr_idx-1 end return game.translate_string("actor_break_dialog_"..bye_phr_idx) end У меня вот как-то так пока, но это все, конечно, мишура: C++ class CPhrase { function GetGoodwillLevel(); --// позволит задавать благосклонность фразе, последний параметр AddPhrase, но при ПЕРЕстроении графа ими будет пользоваться сподручнее function SetGoodwillLevel(number); --// Karlan->ALL: финалайзер доделывать или нет? помоему он не нужен, мишура все это }; C++ class CPhraseDialog { CPhraseDialog() --// конструктор класса --// Karlan->ALL: полной динамики я пока не добился --// FIXME почему-то не строится граф, вроде бы все вершины и ребра явно прописываю, но граф в итоге получается абсолютно полностью избитый, возможно для полной динамики придется сделать еще один подкласс, где будут методы полного построения графа в скриптах, так что пока динамический граф можно строить только из шаблонов function GetDialog(string); --// для теста function SetCaption(string); --// позволяет на лету указать(изменить) заголовок (показывается вместо нулевой фразы) (рекомендуется вызывать ДО создания графа(!)) function SetPriority(number); --// позволяет на лету указать(изменить) приоритет (рекомендуется вызывать ДО создания графа(!)) function IsFinished(); --// проверяет есть ли еще какие-то доступные фразы в графе, если true, то выкинет в список выбора темы }; C++ class CPhraseScript { function SetScriptText(string); --// позволяет задать текст скриптом, на входе айди диалога и айди сказанной фразы в строковых представлениях }; Что, возможно, действительно тут надо - написать класс для создания графов, у меня так руки и не дошли. Попробуй на досуге, я пытался грубыми врезками вклинится без сторонних классов (прямо в CPhraseDialog, как можно видеть), у меня не вышло, хотя совсем глубоко не окапывался. Я уже не помню, но по моему у меня были мысли экспортировать класс, который как раз эти графы все делает. Ссылка на комментарий
Winsor 177 Опубликовано 27 Января 2017 Поделиться Опубликовано 27 Января 2017 (изменено) Почему муторный? у меня граф перестраивается только для тех диалогов, которым нужно. Все диалоги перестраивать каждый раз - лишняя нагрузка. И он перестраивается полностью. Мы с Вами пошли просто разными путями. Вы, насколько я понял - пытались скриптом генерировать сам граф, я же генерацию графа оставил на движок, только сделал механизм перезагрузки. Как по мне - оба варианта имеют право на жизнь. Мой пост можно воспринимать как иллюстрацию - как победить shared_data.Она используется не только для диалогов. Изменено 27 Января 2017 пользователем Winsor 1 Ссылка на комментарий
Карлан 1 049 Опубликовано 27 Января 2017 Поделиться Опубликовано 27 Января 2017 Все диалоги перестраивать каждый раз - лишняя нагрузка Не все диалоги, а только те, к которым идет обращение. Нагрузки там никакой нет совершенно. Самый сложные диалоги у Сидоровича, и в скорости их чтения абсолютно ничего не изменилось, стоит-ли говорить о других? Вы, насколько я понял - пытались скриптом генерировать сам граф, я же генерацию графа оставил на движок, только сделал механизм перезагрузки. Нет, я пытался сделать скриптовые механизмы управлением графа. Выстраивает его в любом случае движковый класс, но строит он его по шаблону, и вот для того, чтобы эти шаблоны можно было задавать в скриптах я и делал функции. Мой пост можно воспринимать как иллюстрацию - как победить shared_data.Она используется не только для диалогов. О том я и говорю, у нас ее вообще нет. Право на жизнь конечно имеет, но мне он кажется весьма переусложненным . Ссылка на комментарий
Winsor 177 Опубликовано 27 Января 2017 Поделиться Опубликовано 27 Января 2017 @Карлан, было бы неплохо, если бы Вы поделились частью исходников для изучения, как подобный механизм реализован у Вас, а именно CPhraseDialog::Load, CPhraseDialog::load_shared. xr_3da\xrGame\xml_str_id_loader.cpp тоже очень хотелось бы изучить Спасибо. 1 1 Ссылка на комментарий
Рекомендуемые сообщения
Создайте аккаунт или авторизуйтесь, чтобы оставить комментарий
Комментарии могут оставлять только зарегистрированные пользователи
Создать аккаунт
Зарегистрировать новый аккаунт в нашем сообществе. Это несложно!
Зарегистрировать новый аккаунтВойти
Есть аккаунт? Войти.
Войти