#include "pch.h" #include "animation.h" #include "ui.h" #include "util.h" #ifndef GTASA #include #include #include "../depend/kiero/minhook/MinHook.h" #include "eAnimations.h" #include #endif #ifdef GTA3 #include #endif #ifdef GTASA void Animation::PlayCutscene(std::string& rootKey, std::string& cutsceneId, std::string& interior) { if (Util::IsOnCutscene()) { SetHelpMessage("Another cutscene is running", false, false, false); return; } CPlayerPed* pPlayer = FindPlayerPed(); if (!pPlayer) { return; } m_Cutscene::m_SceneName = cutsceneId; Command(cutsceneId.c_str()); m_Cutscene::m_nInterior = pPlayer->m_nAreaCode; pPlayer->m_nAreaCode = std::stoi(interior); Command(pPlayer->m_nAreaCode); } #elif GTAVC // Thanks to codenulls(https://github.com/codenulls/) static auto OLD_CStreaming_RemoveModel = (bool(__cdecl*)(int))0x40D6E0; static bool NEW_CStreaming_RemoveModel(int modelID) { // Check if it's IFP animation block if (modelID >= 7916 && modelID <= 7950) { // Do not unload the animation block return true; } return OLD_CStreaming_RemoveModel(modelID); } void Animation::_PlayAnimation(RpClump* pClump, int animGroup, int animID, float blend) { if (animGroup < CAnimManager::ms_numAnimAssocDefinitions) { CAnimationStyleDescriptor* pAnimDef = &CAnimManager::ms_aAnimAssocDefinitions[animGroup]; if (pAnimDef) { if (!_LoadAnimationBlock(pAnimDef->blockName)) { return; } } } CAnimBlendAssociation* pAnimAssoc = RpAnimBlendClumpGetFirstAssociation(pClump); while (pAnimAssoc) { if (pAnimAssoc->m_nAnimId == animID && pAnimAssoc->m_nAnimGroup == animGroup) { // Destroy the animation pAnimAssoc->~CAnimBlendAssociation(); break; } pAnimAssoc = RpAnimBlendGetNextAssociation(pAnimAssoc); } pAnimAssoc = CAnimManager::BlendAnimation(pClump, animGroup, animID, blend); pAnimAssoc->m_nFlags = ANIMATION_STARTED | ANIMATION_MOVEMENT; if (m_Loop) { pAnimAssoc->m_nFlags |= ANIMATION_LOOPED; } if (m_bSecondary) { pAnimAssoc->m_nFlags |= ANIMATION_PARTIAL; } } bool Animation::_LoadAnimationBlock(const char* szBlockName) { CAnimBlock* pAnimBlock = CAnimManager::GetAnimationBlock(szBlockName); if (pAnimBlock) { if (!pAnimBlock->bLoaded) { int animIndex = ((unsigned char*)pAnimBlock - (unsigned char*)CAnimManager::ms_aAnimBlocks) / 32; CStreaming::RequestModel(7916 + animIndex, 0x20 | MISSION_REQUIRED | PRIORITY_REQUEST); CStreaming::LoadAllRequestedModels(true); if (pAnimBlock->bLoaded) { return true; } } else { return true; } } return false; } #else void Animation::_PlayAnimation(RpClump* pClump, int animGroup, int animID, float blend) { CAnimBlendAssociation* pAnimStaticAssoc = CAnimManager::GetAnimAssociation((AssocGroupId)animGroup, (AnimationId)animID); CAnimBlendAssociation* pAnimAssoc = RpAnimBlendClumpGetFirstAssociation(pClump); while (pAnimAssoc) { if (pAnimAssoc->m_nAnimID == pAnimStaticAssoc->m_nAnimID && pAnimAssoc->m_pAnimBlendHierarchy == pAnimStaticAssoc->m_pAnimBlendHierarchy) { // Destroy the animation pAnimAssoc->FreeAnimBlendNodeArray(); break; } pAnimAssoc = RpAnimBlendGetNextAssociation(pAnimAssoc); } pAnimAssoc = CAnimManager::BlendAnimation(pClump, (AssocGroupId)animGroup, (AnimationId)animID, blend); pAnimAssoc->m_nFlags = 0x1 | 0x20; if (m_Loop) { pAnimAssoc->m_nFlags |= 0x2; } if (m_bSecondary) { pAnimAssoc->m_nFlags |= 0x10; } } #endif void Animation::PlayAnimation(std::string& ifp, std::string& anim, std::string& value) { CPlayerPed *pPlayer = FindPlayerPed(); if (!pPlayer) { return; } #ifdef GTASA int hplayer = CPools::GetPedRef(pPlayer); if (ifp != "PED") { Command(ifp.c_str()); Command(); } Command(hplayer); if (m_bSecondary) { Command(hplayer, anim.c_str(), ifp.c_str(), 4.0, m_Loop, 0, 0, 0, -1); } else { Command(hplayer, anim.c_str(), ifp.c_str(), 4.0, m_Loop, 0, 0, 0, -1); } if (ifp != "PED") { Command(ifp.c_str()); } #else if (pPlayer) { int groupID, animID; sscanf(value.c_str(), "%d$%d,", &groupID, &animID); _PlayAnimation(pPlayer->m_pRwClump, groupID, animID, 4.0f); } #endif } Animation::Animation() { #ifdef GTASA Events::processScriptsEvent += [this] { if (m_Cutscene::m_bRunning) { if (Command()) { CPlayerPed* pPlayer = FindPlayerPed(); if (!pPlayer) { return; } pPlayer->m_nAreaCode = m_Cutscene::m_nInterior; Command(pPlayer->m_nAreaCode); m_Cutscene::m_nInterior = 0; TheCamera.Fade(0, 1); } } else { if (m_Cutscene::m_SceneName != "" && Command()) { Command(); m_Cutscene::m_bRunning = true; } } }; #elif GTAVC // mov al, 01 // ret // nop (2x) patch::SetRaw(0x40C9C0, (void*)"\xB0\x01\xC3\x90\x90", 5); // // ret // // nop (3x) patch::SetRaw(0x404950, (void*)"\xC3\x90\x90\x90", 4); MH_CreateHook((void*)0x40D6E0, NEW_CStreaming_RemoveModel, (void**)&OLD_CStreaming_RemoveModel); MH_EnableHook((void*)0x40D6E0); #endif } void Animation::Draw() { if (ImGui::BeginTabBar("Animation", ImGuiTabBarFlags_NoTooltip + ImGuiTabBarFlags_FittingPolicyScroll)) { ImGui::Spacing(); CPlayerPed* pPlayer = FindPlayerPed(); int hPlayer = CPools::GetPedRef(pPlayer); ImGui::Spacing(); if (ImGui::BeginTabItem("Anims")) { ImGui::Spacing(); if (ImGui::Button("Stop animation", Ui::GetSize())) { if (hPlayer) { #ifdef GTASA Command(hPlayer); #else _PlayAnimation(pPlayer->m_pRwClump, ANIM_GROUP_MAN, ANIM_MAN_IDLE_STANCE, 4.0f); #endif } } ImGui::Spacing(); ImGui::Columns(2, nullptr, false); ImGui::Checkbox("Loop", &m_Loop); Ui::ShowTooltip("Keep playing the animation on repeat"); ImGui::NextColumn(); ImGui::Checkbox("Secondary", &m_bSecondary); Ui::ShowTooltip("Player can move while playing the animation"); ImGui::Columns(1); ImGui::Spacing(); if (ImGui::BeginChild("Anims Child")) { ImGui::Spacing(); Ui::DrawJSON(m_AnimData, PlayAnimation, RemoveAnimation); ImGui::EndChild(); } ImGui::EndTabItem(); } if (ImGui::BeginTabItem("Custom")) { ImGui::InputTextWithHint("IFP name", "ped", m_nIfpBuffer, INPUT_BUFFER_SIZE); ImGui::InputTextWithHint("Anim name", "cower", m_nAnimBuffer, INPUT_BUFFER_SIZE); ImGui::Spacing(); if (ImGui::Button("Add animation", Ui::GetSize())) { m_AnimData.m_pJson->m_Data["Custom"][m_nAnimBuffer] = ("0, " + std::string(m_nIfpBuffer)); m_AnimData.m_pJson->WriteToDisk(); } ImGui::EndTabItem(); } #ifdef GTASA if (ImGui::BeginTabItem("Misc")) { ImGui::Spacing(); if (Ui::ListBox("Fighting style", m_FightingStyleList, m_nFightingStyle)) { Command(hPlayer, m_nFightingStyle + 4, 6); SetHelpMessage("Fighting anim set", false, false, false); } if (Ui::ListBoxStr("Walking style", m_WalkingStyleList, m_nWalkingStyle)) { if (m_nWalkingStyle == "default") { patch::Set(0x609A4E, 0x4D48689); patch::Set(0x609A52, 0); } else { patch::Nop(0x609A4E, 6); Command(m_nWalkingStyle.c_str()); Command(); Command(hPlayer, m_nWalkingStyle.c_str()); Command(m_nWalkingStyle.c_str()); } SetHelpMessage("Walking anim set", false, false, false); } ImGui::EndTabItem(); } if (ImGui::BeginTabItem("Cutscene")) { ImGui::Spacing(); if (ImGui::Button("Stop cutscene", Ui::GetSize())) { if (m_Cutscene::m_bRunning) { Command(); m_Cutscene::m_bRunning = false; m_Cutscene::m_SceneName = ""; CPlayerPed* player = FindPlayerPed(); player->m_nAreaCode = m_Cutscene::m_nInterior; Command(player->m_nAreaCode); m_Cutscene::m_nInterior = 0; TheCamera.Fade(0, 1); } } ImGui::Spacing(); if (ImGui::BeginChild("Cutscene Child")) { ImGui::Spacing(); Ui::DrawJSON(m_Cutscene::m_Data, PlayCutscene, nullptr); ImGui::EndChild(); } ImGui::EndTabItem(); } #endif ImGui::EndTabBar(); } } void Animation::RemoveAnimation(std::string& ifp, std::string& anim, std::string& ifpRepeat) { if (ifp == "Custom") { m_AnimData.m_pJson->m_Data["Custom"].erase(anim); m_AnimData.m_pJson->WriteToDisk(); SetHelpMessage("Animation removed", false, false, false); } else { SetHelpMessage("You can only remove custom anims", false, false, false); } }