diff --git a/gamedata/configs/text/eng/ui_mm_modded_exes.xml b/gamedata/configs/text/eng/ui_mm_modded_exes.xml index f9ad751d09..960a6db3d5 100644 --- a/gamedata/configs/text/eng/ui_mm_modded_exes.xml +++ b/gamedata/configs/text/eng/ui_mm_modded_exes.xml @@ -840,8 +840,8 @@ Horizontal recoil is independent of vertical (g_decouple_horz_recoil) - - Scale Hud Motion Marks By Anim Speed (scale_hud_motion_marks_by_speed) + + Disable Scale Hud Motion Marks By Anim Speed (disable_scale_hud_motion_marks_by_speed) diff --git a/gamedata/configs/text/rus/ui_mm_modded_exes.xml b/gamedata/configs/text/rus/ui_mm_modded_exes.xml index 1bcb83603b..93875111ab 100644 --- a/gamedata/configs/text/rus/ui_mm_modded_exes.xml +++ b/gamedata/configs/text/rus/ui_mm_modded_exes.xml @@ -839,8 +839,8 @@ Горизонтальная отдача не зависит от вертикальной (g_decouple_horz_recoil) - - Регулировать Motion Marks в зависимости от скорости анимации (scale_hud_motion_marks_by_speed) + + Запрещать Регулировать Motion Marks в зависимости от скорости анимации (disable_scale_hud_motion_marks_by_speed) diff --git a/gamedata/scripts/_g_patches.script b/gamedata/scripts/_g_patches.script index 27ed7707e0..b629561261 100644 --- a/gamedata/scripts/_g_patches.script +++ b/gamedata/scripts/_g_patches.script @@ -429,6 +429,12 @@ _G.CHudItem__OnMotionMark = function(state, mark, obj, owner) SendScriptCallback("actor_on_hud_animation_mark", state, mark, obj, owner) end +-- Hud Item motion mark callback +AddScriptCallback("actor_on_hud_item_animation_mark", state, mark, obj, owner) +_G.CHudItem__OnItemMotionMark = function(state, mark, obj, owner) + SendScriptCallback("actor_on_hud_animation_mark", state, mark, obj, owner) +end + _G.CHudItem__PlayHUDMotion = function(anm_table, obj, owner) SendScriptCallback("actor_on_hud_animation_play", anm_table, obj, owner) return anm_table diff --git a/gamedata/scripts/lua_help_ex.script b/gamedata/scripts/lua_help_ex.script index eba40586e0..3f1467e9c7 100644 --- a/gamedata/scripts/lua_help_ex.script +++ b/gamedata/scripts/lua_help_ex.script @@ -19,7 +19,7 @@ allow_accel_during_lookout [0; 1] // flag to allow 'running' speed during left or right lookouts - scale_hud_motion_marks_by_speed [1; 0] // flag to scale motion marks by speed, default is on + disable_scale_hud_motion_marks_by_speed [0; 1] // flag to disable scaling motion marks by speed telekinetic_objects_include_corpses [0; 1] // Enable the ability for poltergeists and burers to throw corpses @@ -1075,6 +1075,41 @@ function ForceSetZoomType(float) callbacks (see callbacks_gameobject.script): npc_on_weapon_reload_start, npc_on_weapon_reload_stop -- (npc, wpn), fired on a stalker's weapon entering/leaving the reload state; actor reloads fire actor_on_weapon_reload instead + + // Additive animations by verdatim + + + function play_hud_motion_add(LPCSTR M, bool bMixIn, u32 state, float speed, float end, u16 mode) + // same as play_hud_motion but acts as an additive animation, returns a table with various information about blend IDs that can be passed to + // clear_specific_blends below to clear the blend created from here (useful for idle anims) + // mode defines which anim gets added, 1 is both, 2 is item only, and 3 is hands only + // table contains this information + { + table["anim_time"] = returns.anim_time; + // right hand blend IDs + table["m_model_p0_ID"] = returns.m_model_p0_ID; + table["m_model_p2_ID"] = returns.m_model_p2_ID; + // left hand blend IDs + table["m_model_2_p0_ID"] = returns.m_model_2_p0_ID; + table["m_model_2_p1_ID"] = returns.m_model_2_p1_ID; + table["m_model_2_p2_ID"] = returns.m_model_2_p2_ID; + // mode + table["mode"] = mode; + + (item blend IDs from int 0 to int N, variable amount) + table[0-N] = returns.Item_BlendID[i] + } + + function clear_blends() + // clears all additive animations + + function load_motion(const shared_str& sect_name, const shared_str& alias, const shared_str& hand_anim, const shared_str& item_anim) + // arguments are the hud section name of the weapon, an alias, like "anm_reload_extra", hand anim name and item anim name (gotten from omf) + + function clear_specific_blends(::luabind::object table) + // takes a table as an argument. give the table received from play_hud_motion_add to clear that specific blend + + } class CWeaponKnife : CWeapon { diff --git a/src/Include/xrRender/KinematicsAnimated.h b/src/Include/xrRender/KinematicsAnimated.h index f9ecb333f1..9e98f6560e 100644 --- a/src/Include/xrRender/KinematicsAnimated.h +++ b/src/Include/xrRender/KinematicsAnimated.h @@ -100,6 +100,7 @@ class IKinematicsAnimated u8 channel = 0) = 0; virtual CBlend* PlayCycle(u16 partition, MotionID M, BOOL bMixIn = TRUE, PlayCallback Callback = 0, LPVOID CallbackParam = 0, u8 channel = 0, float speed = 0) = 0; + virtual void CloseAddCycles(u16 partition = 0, u16 BlendID = 0) = 0; // fx'es virtual MotionID ID_FX(LPCSTR N) = 0; virtual MotionID ID_FX_Safe(LPCSTR N) = 0; diff --git a/src/Include/xrRender/animation_blend.h b/src/Include/xrRender/animation_blend.h index 31ed5ffb5b..c9a2451799 100644 --- a/src/Include/xrRender/animation_blend.h +++ b/src/Include/xrRender/animation_blend.h @@ -33,6 +33,10 @@ class CBlend MotionID motionID; u16 bone_or_part; // startup parameters u8 channel; + + // Verdatim, ID of blend for additive animations + u16 Add_ID; + BOOL SkipFirstFrame; private: ECurvature blend; public: diff --git a/src/Layers/xrRender/AnimationKeyCalculate.h b/src/Layers/xrRender/AnimationKeyCalculate.h index c89adfc780..4a8ba84ed2 100644 --- a/src/Layers/xrRender/AnimationKeyCalculate.h +++ b/src/Layers/xrRender/AnimationKeyCalculate.h @@ -88,6 +88,15 @@ IC void Dequantize(CKey& K, const CBlend& BD, const CMotion& M) u32 frame = iFloor(time); float delta = time - float(frame); u32 count = M.get_count(); + + // skip first frame if SkipFirstFrame is used + // count is total frames of animaion (constant per motion), frame is global frame + if (BD.SkipFirstFrame) { + if ((((frame + 0) % count) == 0) && count != 0) { + //Msg("skipping first frame"); + frame++; + } + } // rotation if (M.test_flag(flRKeyAbsent)) { @@ -181,92 +190,6 @@ IC void Dequantize(CKey& K, const CBlend& BD, const CMotion& M) } } - -IC void MixInterlerp(CKey& Result, const CKey* R, const CBlend* const BA[MAX_BLENDED], int b_count) -{ - VERIFY(MAX_BLENDED >= b_count); - switch (b_count) - { - case 0: - Result.Q.set(0, 0, 0, 0); - Result.T.set(0, 0, 0); - break; - case 1: - Result = R[0]; - /* - if(Result.T.y>10000){ - Log("1"); - Log("BLEND_INST",BLEND_INST.Blend.size()); - Log("Bone",LL_BoneName_dbg(SelfID)); - Msg("Result.Q %f,%f,%f,%f",Result.Q.x,Result.Q.y,Result.Q.z,Result.Q.w); - Log("Result.T",Result.T); - VERIFY(0); - } - */ - break; - case 2: - { - float w0 = BA[0]->blendAmount; - float w1 = BA[1]->blendAmount; - float ws = w0 + w1; - float w; - if (fis_zero(ws)) w = 0; - else w = w1 / ws; -#ifdef DEBUG - //. if (fis_zero(w0+w1) || (!_valid(w))){ - //. Debug.fatal (DEBUG_INFO,"TO ALEXMX VERY IMPORTANT: (TOTAL: %f) w: %f, w0: %f, w1: %f, ws:%f, BIS: %d",w0+w1,w,w0,w1,ws,BLEND_INST.Blend.size()); - //. } -#endif - KEY_Interp(Result, R[0], R[1], clampr(w, 0.f, 1.f)); - /* - if(Result.T.y>10000){ - Log("2"); - Log("BLEND_INST",BLEND_INST.Blend.size()); - Log("Bone",LL_BoneName_dbg(SelfID)); - Msg("Result.Q %f,%f,%f,%f",Result.Q.x,Result.Q.y,Result.Q.z,Result.Q.w); - Log("Result.T",Result.T); - Log("parent",*parent); - VERIFY(0); - } - */ - } - break; - default: - { - //int count = Blend.size(); - float total = 0; - ConsistantKey S[MAX_BLENDED]; - for (int i = 0; i < b_count; i++) - S[i].set(R + i, BA[i]->blendAmount); - - std::sort(S, S + b_count); - CKey tmp; - total = S[0].w; - tmp = *S[0].K; - for (int cnt = 1; cnt < b_count; cnt++) - { - total += S[cnt].w; - float d; - if (fis_zero(total)) d = 0.0f; - else d = S[cnt].w / total; - - clampr(d, 0.f, 1.f); - -#ifdef DEBUG - //. if ((total==0) || (!_valid(S[cnt].w/total))){ - //. Debug.fatal (DEBUG_INFO,"TO ALEXMX VERY IMPORTANT: (TOTAL: %f) w: %f, total: %f, count: %d, real count: %d",total,S[cnt].w,total,count,BLEND_INST.Blend.size()); - //. } -#endif - - KEY_Interp(Result, tmp, *S[cnt].K, d); - tmp = Result; - } - } - break; - } -} - - IC void key_sub(CKey& rk, const CKey& k0, const CKey& k1) //sub right { Fquaternion q; @@ -312,15 +235,118 @@ IC void key_mad(CKey& res, const CKey& k0, const CKey& k1, float v) key_add(res, k, k0); } +// shift this function down so i have access to the key functiono +IC void MixInterlerp(CKey& Result, const CKey* R, const CBlend* const BA[MAX_BLENDED], int b_count, const animation::channel_def& ch) +{ + VERIFY(MAX_BLENDED >= b_count); + + // verdatim, additive animations: + // if the channel is 2 (additive), then add the final blends together instead of + // mixing them based off of blend amount + // this is already done in MixChannels but not for here + if (ch.rule.extern_ == animation::add) { + CKey tmp = *R; + for (int cnt = 1; cnt < b_count; cnt++) + { + key_mad(Result, tmp, *(R + cnt), 1); + tmp = Result; + } + Result = tmp; + return; + } + + switch (b_count) + { + case 0: + Result.Q.set(0, 0, 0, 0); + Result.T.set(0, 0, 0); + break; + case 1: + Result = R[0]; + /* + if(Result.T.y>10000){ + Log("1"); + Log("BLEND_INST",BLEND_INST.Blend.size()); + Log("Bone",LL_BoneName_dbg(SelfID)); + Msg("Result.Q %f,%f,%f,%f",Result.Q.x,Result.Q.y,Result.Q.z,Result.Q.w); + Log("Result.T",Result.T); + VERIFY(0); + } + */ + break; + case 2: + { + float w0 = BA[0]->blendAmount; + float w1 = BA[1]->blendAmount; + float ws = w0 + w1; + float w; + if (fis_zero(ws)) w = 0; + else w = w1 / ws; +#ifdef DEBUG + //. if (fis_zero(w0+w1) || (!_valid(w))){ + //. Debug.fatal (DEBUG_INFO,"TO ALEXMX VERY IMPORTANT: (TOTAL: %f) w: %f, w0: %f, w1: %f, ws:%f, BIS: %d",w0+w1,w,w0,w1,ws,BLEND_INST.Blend.size()); + //. } +#endif + KEY_Interp(Result, R[0], R[1], clampr(w, 0.f, 1.f)); + /* + if(Result.T.y>10000){ + Log("2"); + Log("BLEND_INST",BLEND_INST.Blend.size()); + Log("Bone",LL_BoneName_dbg(SelfID)); + Msg("Result.Q %f,%f,%f,%f",Result.Q.x,Result.Q.y,Result.Q.z,Result.Q.w); + Log("Result.T",Result.T); + Log("parent",*parent); + VERIFY(0); + } + */ + } + break; + default: + { + + //int count = Blend.size(); + float total = 0; + ConsistantKey S[MAX_BLENDED]; + for (int i = 0; i < b_count; i++) + S[i].set(R + i, BA[i]->blendAmount); + + std::sort(S, S + b_count); + CKey tmp; + total = S[0].w; + tmp = *S[0].K; + for (int cnt = 1; cnt < b_count; cnt++) + { + total += S[cnt].w; + float d; + if (fis_zero(total)) d = 0.0f; + else d = S[cnt].w / total; + + clampr(d, 0.f, 1.f); +#ifdef DEBUG + //. if ((total==0) || (!_valid(S[cnt].w/total))){ + //. Debug.fatal (DEBUG_INFO,"TO ALEXMX VERY IMPORTANT: (TOTAL: %f) w: %f, total: %f, count: %d, real count: %d",total,S[cnt].w,total,count,BLEND_INST.Blend.size()); + //. } +#endif + + KEY_Interp(Result, tmp, *S[cnt].K, d); + tmp = Result; + + } + } + break; + } +} + +// verdatim, add two extra parameters for keys to access blend flags for additive animations, adds complexity, but this function is found nowhere else IC void keys_substruct(CKey* R, const CKey* BR, int b_count) { - for (int i = 0; i < b_count; i++) - { - CKey r; - key_sub(r, R[i], BR[i]); - R[i] = r; - } + for (int i = 0; i < b_count; i++) + { + CKey r; + key_sub(r, R[i], BR[i]); + R[i] = r; + } } @@ -405,7 +431,7 @@ IC void MixAdd(CKey& Result, const CKey* R, const float* BA, int b_count) IC void process_single_channel(CKey& Result, const animation::channel_def& ch, const CKey* R, const CBlend* const BA[MAX_BLENDED], int b_count) { - MixInterlerp(Result, R, BA, b_count); + MixInterlerp(Result, R, BA, b_count, ch); VERIFY(_valid( Result.T )); VERIFY(_valid( Result.Q )); } diff --git a/src/Layers/xrRender/SkeletonAnimated.cpp b/src/Layers/xrRender/SkeletonAnimated.cpp index 7066940e06..957dde232b 100644 --- a/src/Layers/xrRender/SkeletonAnimated.cpp +++ b/src/Layers/xrRender/SkeletonAnimated.cpp @@ -286,6 +286,66 @@ void CKinematicsAnimated::LL_CloseCycle(u16 part, u8 mask_channel /*= (1<<0)*/) //blend_cycles[part].clear (); // ? } +void CKinematicsAnimated::CloseAddCycles(u16 partition, u16 BlendID) +{ + //for (MotionsSlotVecIt m_it = m_Motions.begin(); m_it != m_Motions.end(); m_it++) + //{ + // SMotionsSlot& MS = *m_it; + // MotionDefVec* def = MS.motions.motion_defs(); + // for (MotionDefVecIt it = def->begin(); it != def->end(); ++it) + // { + // //Msg("bone part is %d ", it->bone_or_part); + // //LL_CloseAddCycles(it->bone_or_part, u8(2)); + // } + //} + + LL_CloseAddCycles(partition, 1 << u8(2), BlendID); +} + +void CKinematicsAnimated::LL_CloseAddCycles(u16 part, u8 mask_channel /*= (1<<0)*/, u16 BlendID) +{ + if (BI_NONE == part) return Msg("part %d is BI_NONE", part); + if (part >= MAX_PARTS) return Msg("part %d is >= MAX_PARTS %d ", part, MAX_PARTS); + + // destroy cycle(s) + BlendSVecIt I = blend_cycles[part].begin(), E = blend_cycles[part].end(); + for (; I != E; I++) + { + CBlend& B = *(*I); + if (!(mask_channel & (1 << B.channel))) + { + //Msg("channel %d is masked", 1<bones.size(); i++) + Bone_Motion_Stop_IM((*bones)[P->bones[i]], *I); + + blend_cycles[part].erase(I); // ? + E = blend_cycles[part].end(); + I--; + + // verdatim additive animations + B.Add_ID = u16(65535); + } + else + { + CBlend& B = *(*I);; + //Msg("BlendID [%d] does not match current Add_ID [%d]", BlendID, B.Add_ID); + } + } + //blend_cycles[part].clear (); // ? +} + float CKinematicsAnimated::get_animation_length(MotionID motion_ID) { VERIFY(motion_ID.slot 1); + + // verdatim, additive animation blend defs, use separate vector for additive blends. if empty space exists, use it. Otherwise push back. + if (channel == 2){ + B.SkipFirstFrame = SkipFirstFrame; + + BlendSVecIt I = blend_additives.begin(), E = blend_additives.end(); + for (int cnt = 0; I != E; I++) + { + CBlend& b = *(*I); + // 65535 is the dummy value + if (&b == nullptr) continue; + if (*(&b.Add_ID) == u16(65535)) { + blend_additives[cnt] = &B; + B.Add_ID = cnt; + return; + } + cnt++; + } + blend_additives.push_back(&B); + } + } void CKinematicsAnimated::IFXBlendSetup(CBlend& B, MotionID motion_ID, float blendAccrue, float blendFalloff, @@ -391,6 +472,7 @@ CBlend* CKinematicsAnimated::LL_PlayCycle(u16 part, MotionID motion_ID, BOOL bMi if (channel == 0) { _DBG_SINGLE_USE_MARKER; + //Msg("stopping previous cycle"); if (bMixing) LL_FadeCycle(part, blendFalloff, 1 << channel); else LL_CloseCycle(part, 1 << channel); } @@ -398,9 +480,15 @@ CBlend* CKinematicsAnimated::LL_PlayCycle(u16 part, MotionID motion_ID, BOOL bMi CBlend* B = IBlend_Create(); if (!B) return 0; + BOOL SkipFirstFrame = FALSE; + if (channel == 2) { + CMotionDef* m_def = m_Motions[motion_ID.slot].motions.motion_def(motion_ID.idx); + SkipFirstFrame = m_def->SkipFirstFrame(); + } _DBG_SINGLE_USE_MARKER; IBlendSetup(*B, part, channel, motion_ID, bMixing, blendAccrue, blendFalloff, Speed, noloop, Callback, - CallbackParam); + CallbackParam, SkipFirstFrame); + for (u32 i = 0; i < P->bones.size(); i++) { if (!(*bones)[P->bones[i]]) @@ -558,6 +646,11 @@ void CKinematicsAnimated::LL_UpdateTracks(float dt, bool b_force, bool leave_ble blend_cycles[part].erase(I); E = blend_cycles[part].end(); I--; + if (B.channel == 2) { + // verdatim additive animations + // after blend is destroyed, remove that blend by setting its id to 65535 + B.Add_ID = u16(65535); + } } //else{ // CMotionDef* m_def = m_Motions[B.motionID.slot].motions.motion_def(B.motionID.idx); @@ -778,6 +871,9 @@ void CKinematicsAnimated::Load(const char* N, IReader* data, u32 dwFlags) m_Partition = NULL; Update_LastTime = 0; + // clear blend_additives list + blend_additives.clear(); + const auto loadOMF = [&](LPCSTR _path) { string_path fn; diff --git a/src/Layers/xrRender/SkeletonAnimated.h b/src/Layers/xrRender/SkeletonAnimated.h index 77e5dfbfcb..4b300fa796 100644 --- a/src/Layers/xrRender/SkeletonAnimated.h +++ b/src/Layers/xrRender/SkeletonAnimated.h @@ -92,6 +92,8 @@ class ECORE_API CKinematicsAnimated : public CKinematics, public IKinematicsAnim svector blend_pool; BlendSVec blend_cycles[MAX_PARTS]; BlendSVec blend_fx; + //additive blends + BlendSVec blend_additives; animation::channels channels; protected: // internal functions @@ -103,7 +105,7 @@ class ECORE_API CKinematicsAnimated : public CKinematics, public IKinematicsAnim CBlend* IBlend_Create(); private: void IBlendSetup(CBlend& B, u16 part, u8 channel, MotionID motion_ID, BOOL bMixing, float blendAccrue, - float blendFalloff, float Speed, BOOL noloop, PlayCallback Callback, LPVOID CallbackParam); + float blendFalloff, float Speed, BOOL noloop, PlayCallback Callback, LPVOID CallbackParam, BOOL SkipFirstFrame = FALSE); void IFXBlendSetup(CBlend& B, MotionID motion_ID, float blendAccrue, float blendFalloff, float Power, float Speed, u16 bone); //. bool LoadMotions (LPCSTR N, IReader *data); @@ -146,6 +148,8 @@ class ECORE_API CKinematicsAnimated : public CKinematics, public IKinematicsAnim u8 channel = 0); void LL_FadeCycle(u16 partition, float falloff, u8 mask_channel = (1 << 0)); void LL_CloseCycle(u16 partition, u8 mask_channel = (1 << 0)); + void LL_CloseAddCycles(u16 partition, u8 mask_channel = (1 << 2), u16 BlendID = 0); + void CloseAddCycles(u16 partition, u16 BlendID = 0); void LL_SetChannelFactor(u16 channel, float factor); CBlendInstance& LL_GetBlendInstance(u16 bone_id) diff --git a/src/xrEngine/SkeletonMotions.cpp b/src/xrEngine/SkeletonMotions.cpp index c9f1ddc312..24f456cd22 100644 --- a/src/xrEngine/SkeletonMotions.cpp +++ b/src/xrEngine/SkeletonMotions.cpp @@ -381,6 +381,11 @@ bool CMotionDef::StopAtEnd() return !!(flags & esmStopAtEnd); } +bool CMotionDef::SkipFirstFrame() +{ + return !!(flags & esmSkipFirstFrame); +} + bool shared_motions::create(shared_str key, IReader* data, vecBones* bones) { motions_value* v = g_pMotionsContainer->dock(key, data, bones); diff --git a/src/xrEngine/SkeletonMotions.h b/src/xrEngine/SkeletonMotions.h index 8759281bb7..99fba51bf9 100644 --- a/src/xrEngine/SkeletonMotions.h +++ b/src/xrEngine/SkeletonMotions.h @@ -156,6 +156,8 @@ class ENGINE_API CMotionDef ICF float Speed() { return Dequantize(speed); } ICF float Power() { return Dequantize(power); } bool StopAtEnd(); + // verdatim, for additive animations + bool SkipFirstFrame(); }; struct accel_str_pred diff --git a/src/xrEngine/motion.h b/src/xrEngine/motion.h index 4424f7b486..69791ee07a 100644 --- a/src/xrEngine/motion.h +++ b/src/xrEngine/motion.h @@ -155,6 +155,9 @@ enum ESMFlags esmRootMover = 1 << 5, esmIdle = 1 << 6, esmUseWeaponBone = 1 << 7, + + // verdatim additive animations + esmSkipFirstFrame = 1 << 8, }; #if defined(_EDITOR) || defined(_MAX_EXPORT) || defined(_MAYA_EXPORT) diff --git a/src/xrGame/HudItem.cpp b/src/xrGame/HudItem.cpp index a11a4eaf87..0d3781ed4e 100644 --- a/src/xrGame/HudItem.cpp +++ b/src/xrGame/HudItem.cpp @@ -27,7 +27,7 @@ int g_nearwall = NW_FOV; int g_nearwall_trace = NT_CAM; // verdatim -BOOL scale_hud_motion_marks_by_speed = FALSE; +BOOL disable_scale_hud_motion_marks_by_speed = FALSE; CHudItem::CHudItem() { @@ -560,7 +560,7 @@ void CHudItem::UpdateCL() float motion_curr_time = ((float)Device.dwTimeGlobal - (float)m_dwMotionStartTm) / 1000.0f; // verdatim, edits so motion marks shift their timings based on speed - if (scale_hud_motion_marks_by_speed) { + if (!disable_scale_hud_motion_marks_by_speed) { CMotionDef def; u16 s = m_current_motion_def->speed; float speed = def.Dequantize(s); @@ -568,8 +568,9 @@ void CHudItem::UpdateCL() // get the final_anim_speed after the ltx speed changes / script changes from actor_on_hud_animation_play and scale the marks accordingly to the two timings float final_anim_speed = HudItemData()->final_anim_speed; - motion_prev_time = (((float)m_dwMotionCurrTm - (float)m_dwMotionStartTm) / 1000.0f) * speed * final_anim_speed; - motion_curr_time = (((float)Device.dwTimeGlobal - (float)m_dwMotionStartTm) / 1000.0f) * speed * final_anim_speed; + // edit to not re-calculate already calculated values + motion_prev_time *= speed * final_anim_speed; + motion_curr_time *= speed * final_anim_speed; } @@ -590,6 +591,44 @@ void CHudItem::UpdateCL() } } + // same as above but for item marks + const xr_vector& marks_i = m_item_current_motion_def->marks; + if (!marks_i.empty()) + { + float motion_prev_time = ((float)m_dwMotionCurrTm - (float)m_dwMotionStartTm) / 1000.0f; + float motion_curr_time = ((float)Device.dwTimeGlobal - (float)m_dwMotionStartTm) / 1000.0f; + + // verdatim, edits so motion marks shift their timings based on speed + if (disable_scale_hud_motion_marks_by_speed) { + CMotionDef def; + u16 s = m_current_motion_def->speed; + float speed = def.Dequantize(s); + + // get the final_anim_speed after the ltx speed changes / script changes from actor_on_hud_animation_play and scale the marks accordingly to the two timings + float final_anim_speed = HudItemData()->final_anim_speed; + + motion_prev_time *= speed * final_anim_speed; + motion_curr_time *= speed * final_anim_speed; + + } + + xr_vector::const_iterator it = marks_i.begin(); + xr_vector::const_iterator it_e = marks_i.end(); + for (; it != it_e; ++it) + { + const motion_marks& M = (*it); + if (M.is_empty()) + continue; + + const motion_marks::interval* Iprev = M.pick_mark(motion_prev_time); + const motion_marks::interval* Icurr = M.pick_mark(motion_curr_time); + if (Iprev == NULL && Icurr != NULL /* || M.is_mark_between(motion_prev_time, motion_curr_time)*/) + { + OnItemMotionMark(m_startedMotionState, M); + } + } + } + m_dwMotionCurrTm = Device.dwTimeGlobal; if (m_dwMotionCurrTm > m_dwMotionEndTm) { @@ -614,6 +653,13 @@ void CHudItem::OnMotionMark(u32 state, const motion_marks& M) funct(state, *M.name, object().lua_game_object(), object().lua_game_object() ? object().lua_game_object()->Parent() : nullptr); } +void CHudItem::OnItemMotionMark(u32 state, const motion_marks& M) +{ + ::luabind::functor funct; + if (ai().script_engine().functor("_G.CHudItem__OnItemMotionMark", funct)) + funct(state, *M.name, object().lua_game_object(), object().lua_game_object() ? object().lua_game_object()->Parent() : nullptr); +} + void CHudItem::OnH_A_Chield() { } @@ -786,9 +832,10 @@ u32 CHudItem::PlayHUDMotion(shared_str M, BOOL bMixIn, CHudItem* W, u32 state, f return anim_time; } -u32 CHudItem::PlayHUDMotion_noCB(const shared_str& motion_name, BOOL bMixIn, float speed, bool bMixIn2) +u32 CHudItem::PlayHUDMotion_noCB(const shared_str& motion_name, BOOL bMixIn, float speed, bool bMixIn2, u8 channel, anim_play_returns* returns) { - m_current_motion = motion_name; + if (channel == 0) + m_current_motion = motion_name; if (bDebug && item().m_pInventory) { @@ -801,7 +848,7 @@ u32 CHudItem::PlayHUDMotion_noCB(const shared_str& motion_name, BOOL bMixIn, flo } if (IsAttachedToHUD()) { - return HudItemData()->anim_play(motion_name, bMixIn, m_current_motion_def, m_started_rnd_anim_idx, speed, bMixIn2); + return HudItemData()->anim_play(motion_name, bMixIn, m_current_motion_def, m_started_rnd_anim_idx, speed, bMixIn2, channel, returns, m_item_current_motion_def); } else { @@ -810,6 +857,51 @@ u32 CHudItem::PlayHUDMotion_noCB(const shared_str& motion_name, BOOL bMixIn, flo } } +::luabind::object CHudItem::PlayHUDMotion_Additive(shared_str M, BOOL bMixIn, CHudItem* W, u32 state, float speed, float end, bool bMixIn2, u16 mode) +{ + anim_play_returns returns; + // 1 is both, 2 is item only, 3 is hands only + returns.mode = mode; + PlayHUDMotion_noCB(M, bMixIn, speed, bMixIn2, u8(2), &returns); + + // from script_game_object.cpp line 1395, thanks lucy + ::luabind::object table = ::luabind::newtable(ai().script_engine().lua()); + + table["anim_time"] = returns.anim_time; + table["m_model_p0_ID"] = returns.m_model_p0_ID; + table["m_model_p2_ID"] = returns.m_model_p2_ID; + table["m_model_2_p0_ID"] = returns.m_model_2_p0_ID; + table["m_model_2_p1_ID"] = returns.m_model_2_p1_ID; + table["m_model_2_p2_ID"] = returns.m_model_2_p2_ID; + table["mode"] = mode; + + for (int i = 0; i < returns.Item_BlendID.size(); i++) + { + table[1+i] = returns.Item_BlendID[i]; + } + + return table; +} + +void CHudItem::ClearBlends() +{ + HudItemData()->ClearBlends(); + + return; +} + +BOOL CHudItem::load_one_motion(const shared_str& sect_name, const shared_str& alias, const shared_str& hand_anim, const shared_str& item_anim) +{ + if (HudItemData()->load_motion(sect_name, alias, hand_anim, item_anim)) + return TRUE; + return FALSE; +} + +void CHudItem::StopHUDMotion_Additive(anim_play_returns* returns) +{ + HudItemData()->ClearBlends(returns); +} + void CHudItem::StopCurrentAnimWithoutCallback() { m_dwMotionStartTm = 0; diff --git a/src/xrGame/HudItem.h b/src/xrGame/HudItem.h index a1d97315be..211dcb6e2e 100644 --- a/src/xrGame/HudItem.h +++ b/src/xrGame/HudItem.h @@ -1,4 +1,4 @@ -п»ї#pragma once +#pragma once class CSE_Abstract; class CPhysicItem; @@ -81,6 +81,19 @@ class CHUDState virtual void OnStateSwitch(u32 S, u32 oldState) = 0; }; +// verdatim, additive animations +struct anim_play_returns { + u32 anim_time; + // maybe i should turns the partitions for the hand models into set arrays / Vectors, will think about it + u16 m_model_p0_ID; + u16 m_model_p2_ID; + u16 m_model_2_p0_ID; + u16 m_model_2_p1_ID; + u16 m_model_2_p2_ID; + IntVec Item_BlendID; + u16 mode = 0; +}; + class CHudItem : public CHUDState { protected: @@ -101,6 +114,10 @@ class CHudItem : public CHUDState struct { const CMotionDef* m_current_motion_def; + + // item motion_def + const CMotionDef* m_item_current_motion_def; + shared_str m_current_motion; u32 m_dwMotionCurrTm; u32 m_dwMotionStartTm; @@ -176,6 +193,9 @@ class CHudItem : public CHUDState virtual void OnMotionMark(u32 state, const motion_marks& M); + //item motion mark + virtual void OnItemMotionMark(u32 state, const motion_marks& M); + virtual void PlayAnimIdle(); virtual bool TryPlayAnimBore(); virtual bool TryPlayAnimIdle(); @@ -196,7 +216,14 @@ class CHudItem : public CHUDState virtual void UpdateXForm() = 0; u32 PlayHUDMotion(shared_str M, BOOL bMixIn, CHudItem* W, u32 state, float speed = 1.f, float end = 0.f, bool bMixIn2 = true); - u32 PlayHUDMotion_noCB(const shared_str& M, BOOL bMixIn, float speed = 1.f, bool bMixIn2 = true); + u32 PlayHUDMotion_noCB( const shared_str& M, BOOL bMixIn, float speed = 1.f, bool bMixIn2 = true, u8 channel = u8(0), anim_play_returns* returns = nullptr); + + // verdatim + ::luabind::object PlayHUDMotion_Additive(shared_str M, BOOL bMixIn, CHudItem* W, u32 state, float speed = 1.f, float end = 0.f, bool bMixIn2 = true, u16 mode = 1); + void ClearBlends(); + BOOL load_one_motion(const shared_str& sect_name, const shared_str& alias, const shared_str& hand_anim, const shared_str& item_anim); + void StopHUDMotion_Additive(anim_play_returns* returns = nullptr); + void StopCurrentAnimWithoutCallback(); IC void RenderHud(BOOL B) { m_huditem_flags.set(fl_renderhud, B); } @@ -336,4 +363,4 @@ class CAnonHudItem : public CHudItem virtual bool TryPlayAnimIdle() { return false; } virtual void UpdateHudAdditional(Fmatrix& trans) { } DECLARE_SCRIPT_REGISTER_FUNCTION -}; \ No newline at end of file +}; diff --git a/src/xrGame/console_commands.cpp b/src/xrGame/console_commands.cpp index 0eac01e435..c596ac773f 100644 --- a/src/xrGame/console_commands.cpp +++ b/src/xrGame/console_commands.cpp @@ -138,7 +138,7 @@ extern BOOL disableActorBodyRotationDelay; //leer extern BOOL pseudogiantDodgeWhileFalling; // Verdatim extern BOOL AllowAccelDuringLookOut; // Verdatim -extern BOOL scale_hud_motion_marks_by_speed; // Verdatim +extern BOOL disable_scale_hud_motion_marks_by_speed; // Verdatim //demonized: new console vars extern BOOL firstPersonDeath; @@ -3077,7 +3077,7 @@ void CCC_RegisterCommands() CMD4(CCC_Integer, "allow_accel_during_lookout", &AllowAccelDuringLookOut, 0, 1); // Verdatim - CMD4(CCC_Integer, "scale_hud_motion_marks_by_speed", &scale_hud_motion_marks_by_speed, 0, 1); // Verdatim + CMD4(CCC_Integer, "disable_scale_hud_motion_marks_by_speed", &disable_scale_hud_motion_marks_by_speed, 0, 1); // Verdatim CMD4(CCC_Integer, "telekinetic_objects_include_corpses", &g_telekinetic_objects_include_corpses, 0, 1); // Tosox diff --git a/src/xrGame/player_hud.cpp b/src/xrGame/player_hud.cpp index 58aa5a49f7..04b1691698 100644 --- a/src/xrGame/player_hud.cpp +++ b/src/xrGame/player_hud.cpp @@ -107,6 +107,55 @@ void player_hud_motion_container::load(IKinematicsAnimated* model, const shared_ } } +BOOL player_hud_motion_container::load_single_motion(IKinematicsAnimated* model, const shared_str& alias, const shared_str& hand_anim, const shared_str& item_anim) +{ + player_hud_motion* pm = NULL; + + string512 buff; + MotionID motion_ID; + + xr_vector::iterator it = m_anims.begin(); + xr_vector::iterator it_e = m_anims.end(); + for (; it != it_e; ++it) + { + const shared_str& s = (true) ? (*it).m_alias_name : (*it).m_base_name; // ?? + if (s == alias) + // return false if alias is already being used + return FALSE; + } + + m_anims.resize(m_anims.size() + 1); + pm = &m_anims.back(); + + //base and alias name + pm->m_alias_name = alias; + pm->m_base_name = hand_anim; + pm->m_additional_name = item_anim; + + + //and load all motions for it + + xr_strcpy(buff, pm->m_base_name.c_str()); + + motion_ID = model->ID_Cycle_Safe(buff); + + if (!motion_ID.valid()) + { + motion_ID = model->ID_Cycle_Safe("hand_idle_doun"); + } + if (motion_ID.valid()) + { + pm->m_animations.resize(pm->m_animations.size() + 1); + pm->m_animations.back().mid = motion_ID; + pm->m_animations.back().name = buff; +#ifdef DEBUG + // Msg(" alias=[%s] base=[%s] name=[%s]",pm->m_alias_name.c_str(), pm->m_base_name.c_str(), buff); +#endif // #ifdef DEBUG + } + VERIFY2(pm->m_animations.size(), make_string("motion not found [%s]", pm->m_base_name.c_str()).c_str()); + return TRUE; +} + Fvector& attachable_hud_item::hands_attach_pos() { if (g_player_hud->m_adjust_mode) @@ -612,7 +661,7 @@ player_hud_motion* attachable_hud_item::find_motion(const shared_str& anm_name) string256 anim_name_r; bool is_16x9 = UI().is_widescreen(); xr_sprintf(anim_name_r, "%s%s", anm_name.c_str(), ((m_attach_place_idx == 1) && is_16x9) ? "_16x9" : ""); - + player_hud_motion* anm = m_hand_motions->find_motion(anim_name_r); if (!anm) @@ -627,20 +676,118 @@ player_hud_motion* attachable_hud_item::find_motion(const shared_str& anm_name) return anm; } +BOOL attachable_hud_item::load_motion(const shared_str& sect_name, const shared_str& alias, const shared_str& hand_anim, const shared_str& item_anim) +{ + if (m_parent->create_hand_motion(*sect_name, *alias, *hand_anim, *item_anim)) + return TRUE; + return FALSE; +} + +void attachable_hud_item::ClearBlends(anim_play_returns* returns) +{ + IKinematicsAnimated* ka = m_model->dcast_PKinematicsAnimated(); + // clear blends for each partition + + if (returns == nullptr) { + anim_play_returns temp = {0, 0, 0, 0, 0, 0}; + returns = &temp; + } + u16 pcI = ka->partitions().count(); + for (u16 pid = 0; pid < pcI; ++pid) + { + u16 blend_id = 0; + if (returns->Item_BlendID.size() == 0) { + blend_id = 0; + } + else + blend_id = returns->Item_BlendID[pid]; + + if (!(blend_id)) { + blend_id = 0; + } + if ((returns->mode == 1) || (returns->mode == 2)) + ka->CloseAddCycles(pid, blend_id); // visual model + } + + u16 pcR = g_player_hud->m_model->partitions().count(); + for (u16 pid = 0; pid < pcR; ++pid) + { + // not too sure if this is the best idea for this but oh well + u16 blend_id = 0; + switch (pid) { + case 0: + blend_id = returns->m_model_p0_ID; + break; + case 1: + blend_id = 0; + break; + case 2: + blend_id = returns->m_model_p2_ID; + break; + default: + blend_id = 0; + + } + + if (!(blend_id)) { + blend_id = 0; + } + if ((returns->mode == 1) || (returns->mode == 3)) + g_player_hud->m_model->CloseAddCycles(pid, blend_id); // right arm + } + + u16 pcL = g_player_hud->m_model_2->partitions().count(); + for (u16 pid = 0; pid < pcL; ++pid) + { + // not too sure if this is the best idea for this but oh well + u16 blend_id = 0; + switch (pid) { + case 0: + blend_id = returns->m_model_2_p0_ID; + break; + case 1: + blend_id = returns->m_model_2_p1_ID; + break; + case 2: + blend_id = returns->m_model_2_p2_ID; + break; + default: + blend_id = 0; + + } + + if (!(blend_id)) { + blend_id = 0; + } + if ((returns->mode == 1) || (returns->mode == 3)) + g_player_hud->m_model_2->CloseAddCycles(pid, blend_id); // left arm + } + +} + u32 attachable_hud_item::anim_play(const shared_str& anm_name_b, BOOL bMixIn, const CMotionDef*& md, u8& rnd_idx, - float speed, bool bMixIn2) + float speed, bool bMixIn2, u8 channel, anim_play_returns* returns, const CMotionDef*& mdi) { player_hud_motion* anm = find_motion(anm_name_b); rnd_idx = (u8)Random.randI(anm->m_animations.size()); const motion_descr& M = anm->m_animations[rnd_idx]; if (speed == 1.f) speed = anm->m_anim_speed != 0 ? anm->m_anim_speed : 1.f; - // Verdatim: store the final anim speed for use in motion mark timing scaling - final_anim_speed = speed; + // Verdatim: store the final anim speed for use in motion mark timing scaling + final_anim_speed = speed; + + anim_play_returns foo; + anim_play_returns* temp = &foo; + + u16 mode = 0; + if (returns != nullptr) { + mode = returns->mode; + } u32 ret = 0; if (m_attach_place_idx != SCOPE_ATTACH_IDX) { - ret = g_player_hud->anim_play(m_attach_place_idx, M.mid, bMixIn, md, speed); + if (!(mode == 2)) + ret = g_player_hud->anim_play(m_attach_place_idx, M.mid, bMixIn, md, speed, u16(-1), channel, temp); } if (m_model->dcast_PKinematicsAnimated()) @@ -652,7 +799,7 @@ u32 attachable_hud_item::anim_play(const shared_str& anm_name_b, BOOL bMixIn, co item_anm_name = anm->m_additional_name; else item_anm_name = M.name; - + MotionID M2 = ka->ID_Cycle_Safe(item_anm_name); if (!M2.valid()) M2 = ka->ID_Cycle_Safe("idle"); @@ -671,12 +818,25 @@ u32 attachable_hud_item::anim_play(const shared_str& anm_name_b, BOOL bMixIn, co } u16 pc = ka->partitions().count(); - for (u16 pid = 0; pid < pc; ++pid) - CBlend* B = ka->PlayCycle(pid, M2, (!!bMixIn && bMixIn2), 0, 0, 0, speed); + if (!(mode == 3)) + { + for (u16 pid = 0; pid < pc; ++pid) + { + CBlend* B = ka->PlayCycle(pid, M2, (!!bMixIn && bMixIn2), 0, 0, channel, speed); + temp->Item_BlendID.push_back(B->Add_ID); + //Msg("adding blend id [%d], new size of vec is [%d]", B->Add_ID, temp->Item_BlendID.size()); + } + } + // set the motion def of the item + mdi = ka->LL_GetMotionDef(M2); m_model->CalculateBones_Invalidate(); } + if (returns != nullptr) { + *returns = *temp; + } + if (m_attach_place_idx == SCOPE_ATTACH_IDX) { return ret; } @@ -1479,31 +1639,39 @@ float player_hud::SetBlendAnmTime(LPCSTR name, float time) } //0 = both, 1 = left, 2 = right -void play_blend(player_hud* hud, u8 pid, const MotionID& M, BOOL bMixIn, float speed, bool script_anim = false) +void play_blend(player_hud* hud, u8 pid, const MotionID& M, BOOL bMixIn, float speed, bool script_anim = false, u8 channel = u8(0), anim_play_returns* ret = nullptr) { - switch (pid) - { - case 0: - { - if (!script_anim && hud->script_anim_part == 2) return; - play_blend(hud, 1, M, bMixIn, speed); - play_blend(hud, 2, M, bMixIn, speed); - break; - } - case 1: - if (!script_anim && hud->script_anim_part == 1) return; - hud->m_model_2->PlayCycle(0, M, bMixIn, 0, 0, 0, speed); - hud->m_model_2->PlayCycle(1, M, bMixIn, 0, 0, 0, speed); - hud->m_model_2->PlayCycle(2, M, bMixIn, 0, 0, 0, speed); - hud->m_model_2->dcast_PKinematics()->CalculateBones_Invalidate(); - break; - case 2: - if (!script_anim && hud->script_anim_part == 0) return; - hud->m_model->PlayCycle(0, M, bMixIn, 0, 0, 0, speed); - hud->m_model->PlayCycle(2, M, bMixIn, 0, 0, 0, speed); - hud->m_model->dcast_PKinematics()->CalculateBones_Invalidate(); - break; - } + if (ret == nullptr) { + anim_play_returns temp; + ret = &temp; + } + switch (pid) + { + case 0: + { + if (!script_anim && hud->script_anim_part == 2) return; + play_blend(hud, 1, M, bMixIn, speed, false, channel, ret); + play_blend(hud, 2, M, bMixIn, speed, false, channel, ret); + break; + } + case 1: + if (!script_anim && hud->script_anim_part == 1) return; + // left arm + ret->m_model_2_p0_ID = hud->m_model_2->PlayCycle(0, M, bMixIn, 0, 0, channel, speed)->Add_ID; + ret->m_model_2_p1_ID = hud->m_model_2->PlayCycle(1, M, bMixIn, 0, 0, channel, speed)->Add_ID; + + // this line below is ??, not sure why it exists. it plays the right arm anim for m_model_2 but the right arm is hidden in m_model_2 + ret->m_model_2_p2_ID = hud->m_model_2->PlayCycle(2, M, bMixIn, 0, 0, channel, speed)->Add_ID; + hud->m_model_2->dcast_PKinematics()->CalculateBones_Invalidate(); + break; + case 2: + if (!script_anim && hud->script_anim_part == 0) return; + // right arm + ret->m_model_p0_ID = hud->m_model->PlayCycle(0, M, bMixIn, 0, 0, channel, speed)->Add_ID; + ret->m_model_p2_ID = hud->m_model->PlayCycle(2, M, bMixIn, 0, 0, channel, speed)->Add_ID; + hud->m_model->dcast_PKinematics()->CalculateBones_Invalidate(); + break; + } } extern BOOL print_bone_warnings; @@ -1532,7 +1700,7 @@ void player_hud::StopScriptAnim() } //part: 0 = right arm; 1 = left arm -u32 player_hud::anim_play(u16 part, const MotionID& M, BOOL bMixIn, const CMotionDef*& md, float speed, u16 override_part) +u32 player_hud::anim_play(u16 part, const MotionID& M, BOOL bMixIn, const CMotionDef*& md, float speed, u16 override_part, u8 channel, anim_play_returns* returns) { u16 part_id = u16(-1); if (attached_item(0) && attached_item(1)) @@ -1543,7 +1711,7 @@ u32 player_hud::anim_play(u16 part, const MotionID& M, BOOL bMixIn, const CMotio if (override_part != u16(-1)) part_id = override_part; - play_blend(this, part_id, M, bMixIn, speed); + play_blend(this, part_id, M, bMixIn, speed, false, channel, returns); return motion_length(M, md, speed); } @@ -1564,6 +1732,19 @@ player_hud_motion_container* player_hud::get_hand_motions(LPCSTR section) return &res->pm; } +BOOL player_hud::create_hand_motion(LPCSTR section, LPCSTR alias, LPCSTR hand_anim, LPCSTR item_anim) +{ + // load a new motion for an already initiated item section + for (hand_motions* phm : m_hand_motions) + { + if (phm->section == section) + if (phm->pm.load_single_motion(m_model, alias, hand_anim, item_anim)); + return TRUE; + } + + return FALSE; +} + void player_hud::update_script_item() { Fvector ypr = item_pos[1]; diff --git a/src/xrGame/player_hud.h b/src/xrGame/player_hud.h index 35a37c077d..030d2a49aa 100644 --- a/src/xrGame/player_hud.h +++ b/src/xrGame/player_hud.h @@ -32,6 +32,7 @@ struct player_hud_motion_container xr_vector m_anims; player_hud_motion* find_motion(const shared_str& name); void load(IKinematicsAnimated* model, const shared_str& sect); + BOOL load_single_motion(IKinematicsAnimated* model, const shared_str& alias, const shared_str& hand_anim, const shared_str& item_anim); }; struct hand_motions @@ -296,6 +297,8 @@ struct hud_item_measures float m_attach_scale; }; +extern struct anim_play_returns; + struct attachable_hud_item { player_hud* m_parent; @@ -331,6 +334,10 @@ struct attachable_hud_item void set_bone_visible(const shared_str& bone_name, BOOL bVisibility, BOOL bSilent = FALSE); void debug_draw_firedeps(); player_hud_motion* find_motion(const shared_str& anm_name); + + // verdatim + BOOL load_motion(const shared_str& sect_name, const shared_str& alias, const shared_str& hand_anim, const shared_str& item_anim); + //hands bind position Fvector& hands_attach_pos(); Fvector& hands_attach_rot(); @@ -354,7 +361,9 @@ struct attachable_hud_item //props u32 m_upd_firedeps_frame; void tune(Ivector values); - u32 anim_play(const shared_str& anim_name, BOOL bMixIn, const CMotionDef*& md, u8& rnd, float speed = 0, bool bMixIn2 = true); + u32 anim_play(const shared_str& anim_name, BOOL bMixIn, const CMotionDef*& md, u8& rnd, float speed, bool bMixIn2, u8 channel, anim_play_returns* returns, const CMotionDef*& mdi); + void ClearBlends(anim_play_returns* returns = nullptr); + u32 anim_add_stop(const shared_str& anim_name, BOOL bMixIn, const CMotionDef*& md, u8& rnd, float speed = 0, bool bMixIn2 = true, u8 channel = u8(2)); }; class player_hud @@ -376,7 +385,7 @@ class player_hud void render_hud(); void render_item_ui(); bool render_item_ui_query(); - u32 anim_play(u16 part, const MotionID& M, BOOL bMixIn, const CMotionDef*& md, float speed, u16 override_part = u16(-1)); + u32 anim_play(u16 part, const MotionID& M, BOOL bMixIn, const CMotionDef*& md, float speed, u16 override_part = u16(-1), u8 channel = u8(0), anim_play_returns* returns = nullptr); u32 script_anim_play(u8 hand, LPCSTR itm_name, LPCSTR anm_name, bool bMixIn = true, float speed = 1.f); const shared_str& section_name() const { return m_sect_name; } void OnFrame(); @@ -401,6 +410,7 @@ class player_hud xr_vector m_hand_motions; player_hud_motion_container* get_hand_motions(LPCSTR section); + BOOL create_hand_motion(LPCSTR section, LPCSTR alias, LPCSTR hand_anim, LPCSTR item_anim); void update_script_item(); diff --git a/src/xrGame/script_attachment_manager.cpp b/src/xrGame/script_attachment_manager.cpp index ff3664391c..95ca4d101b 100644 --- a/src/xrGame/script_attachment_manager.cpp +++ b/src/xrGame/script_attachment_manager.cpp @@ -602,6 +602,66 @@ u32 script_attachment::PlayMotion(LPCSTR name, bool mixin, float speed) return length; } +::luabind::object script_attachment::PlayMotion_Add(LPCSTR name, bool bMixIn, float speed) +{ + IKinematicsAnimated* k = renderable.visual->dcast_PKinematicsAnimated(); + + if (!k) + return ::luabind::newtable(ai().script_engine().lua()); + + MotionID M2 = k->ID_Cycle_Safe(name); + if (!M2.valid()) + M2 = k->ID_Cycle_Safe("idle"); + + if (!M2.valid()) + return ::luabind::newtable(ai().script_engine().lua()); + + ::luabind::object table = ::luabind::newtable(ai().script_engine().lua()); + + u16 pc = k->partitions().count(); + for (u16 pid = 0; pid < pc; ++pid) + { + CBlend* B = k->PlayCycle(pid, M2, bMixIn, 0, 0, 0, speed); + table[pid+1] = B->Add_ID; + } + + k->UpdateTracks(); + m_kinematics->CalculateBones_Invalidate(); + m_kinematics->CalculateBones(true); + + return table; +} + +void script_attachment::ClearSpecificBlends(::luabind::object table) +{ + if (table && table.type() == LUA_TTABLE) { + IKinematicsAnimated* k = renderable.visual->dcast_PKinematicsAnimated(); + + if (!k) + return; + u16 pc = k->partitions().count(); + for (u16 pid = 0; pid < pc; ++pid) + { + u16 Add_ID = ::luabind::object_cast(table[pid+1]); + if (Add_ID) + k->CloseAddCycles(pid, Add_ID); + } + } +} + +void script_attachment::ClearBlends() +{ + IKinematicsAnimated* k = renderable.visual->dcast_PKinematicsAnimated(); + + if (!k) + return; + u16 pc = k->partitions().count(); + for (u16 pid = 0; pid < pc; ++pid) + { + k->CloseAddCycles(pid, 0); + } +} + u32 script_attachment::motion_length(const MotionID& M, const CMotionDef*& md, float speed) { IKinematicsAnimated* k = renderable.visual->dcast_PKinematicsAnimated(); diff --git a/src/xrGame/script_attachment_manager.h b/src/xrGame/script_attachment_manager.h index a619ab7782..5fc6bdad1c 100644 --- a/src/xrGame/script_attachment_manager.h +++ b/src/xrGame/script_attachment_manager.h @@ -190,6 +190,10 @@ class script_attachment : u32 PlayMotion(LPCSTR name, bool mixin = true, float speed = 1.f); u32 motion_length(const MotionID& M, const CMotionDef*& md, float speed); + // additive animations + ::luabind::object PlayMotion_Add(LPCSTR name, bool bMixIn, float speed); + void ClearSpecificBlends(::luabind::object table = ::luabind::newtable(ai().script_engine().lua())); + void ClearBlends(); u16 bone_id(LPCSTR bone_name); LPCSTR bone_name(u16 bone_id); diff --git a/src/xrGame/script_attachment_script.cpp b/src/xrGame/script_attachment_script.cpp index 710994737c..cb9186acd0 100644 --- a/src/xrGame/script_attachment_script.cpp +++ b/src/xrGame/script_attachment_script.cpp @@ -88,6 +88,10 @@ void script_attachment::script_register(lua_State* L) .def("set_name", &script_attachment::SetName) .def("get_name", &script_attachment::GetName) .def("play_motion", &script_attachment::PlayMotion) + // additive animations + .def("play_motion_hud", &script_attachment::PlayMotion_Add) + .def("clear_specific_blends", &script_attachment::ClearSpecificBlends) + .def("clear_blends", &script_attachment::ClearBlends) //Script 3D UI .def("set_ui", &script_attachment::SetScriptUI) @@ -125,4 +129,4 @@ void script_attachment::script_register(lua_State* L) //Userdata .property("userdata", &script_attachment::GetUserdata, &script_attachment::SetUserdata) ]; -} \ No newline at end of file +} diff --git a/src/xrGame/script_game_object.h b/src/xrGame/script_game_object.h index 71cc24df42..b2804d475a 100644 --- a/src/xrGame/script_game_object.h +++ b/src/xrGame/script_game_object.h @@ -1058,6 +1058,12 @@ class CScriptGameObject //Any class that is derived from CHudItem u32 PlayHudMotion(LPCSTR M, bool bMixIn, u32 state, float speed = 0.f, float end = 0.f); + + ::luabind::object PlayHUDMotion_Add(LPCSTR M, bool bMixIn, u32 state, float speed = 0.f, float end = 0.f, u16 mode = 1); + void ClearBlends(); + BOOL load_motion(const shared_str& sect_name, const shared_str& alias, const shared_str& hand_anim, const shared_str& item_anim); + void ClearSpecificBlends(::luabind::object table = ::luabind::newtable(ai().script_engine().lua())); + void SwitchState(u32 state); u32 GetState(); Fvector hud_fire_point(); diff --git a/src/xrGame/script_game_object3.cpp b/src/xrGame/script_game_object3.cpp index 1a6011629f..2be8dc5dd6 100644 --- a/src/xrGame/script_game_object3.cpp +++ b/src/xrGame/script_game_object3.cpp @@ -1842,6 +1842,91 @@ u32 CScriptGameObject::PlayHudMotion(LPCSTR M, bool bMixIn, u32 state, float spe return itm->PlayHUDMotion(M, bMixIn, itm, state, speed, end); } +::luabind::object CScriptGameObject::PlayHUDMotion_Add(LPCSTR M, bool bMixIn, u32 state, float speed, float end, u16 mode) +{ + CWeapon* Weapon = object().cast_weapon(); + if (Weapon) + { + if (!Weapon->HudAnimationExist(M)) + return ::luabind::newtable(ai().script_engine().lua()); + + return Weapon->PlayHUDMotion_Additive(M, bMixIn, Weapon, state, speed, end, true, mode); + } + + CHudItem* itm = object().cast_inventory_item()->cast_hud_item(); + if (!itm) + return ::luabind::newtable(ai().script_engine().lua()); + + if (!itm->HudAnimationExist(M)) + return ::luabind::newtable(ai().script_engine().lua()); + + return itm->PlayHUDMotion_Additive(M, bMixIn, itm, state, speed, end, true, mode); +} + +void CScriptGameObject::ClearBlends() +{ + CWeapon* Weapon = object().cast_weapon(); + if (Weapon) + { + Weapon->ClearBlends(); + } + + CHudItem* itm = object().cast_inventory_item()->cast_hud_item(); + if (!itm) + return; + + itm->ClearBlends(); +} + +BOOL CScriptGameObject::load_motion(const shared_str& sect_name, const shared_str& alias, const shared_str& hand_anim, const shared_str& item_anim) +{ + CWeapon* Weapon = object().cast_weapon(); + if (Weapon) + { + return Weapon->load_one_motion(sect_name, alias, hand_anim, item_anim); + } + + CHudItem* itm = object().cast_inventory_item()->cast_hud_item(); + if (!itm) + return FALSE; + + return itm->load_one_motion(sect_name, alias, hand_anim, item_anim); +} + +void CScriptGameObject::ClearSpecificBlends(::luabind::object table) +{ + anim_play_returns returns; + if (table && table.type() == LUA_TTABLE) + { + returns.anim_time = ::luabind::object_cast(table["anim_time"]); + returns.m_model_p0_ID = ::luabind::object_cast(table["m_model_p0_ID"]); + returns.m_model_p2_ID = ::luabind::object_cast(table["m_model_p2_ID"]); + returns.m_model_2_p0_ID = ::luabind::object_cast(table["m_model_2_p0_ID"]); + returns.m_model_2_p1_ID = ::luabind::object_cast(table["m_model_2_p1_ID"]); + returns.m_model_2_p2_ID = ::luabind::object_cast(table["m_model_2_p2_ID"]); + returns.mode = ::luabind::object_cast(table["mode"]); + + for (int i = 0; i < MAX_PARTS; i++) { + u16 item_ID = ::luabind::object_cast(table[i+1]); + if (!(item_ID)) { + break; + } + returns.Item_BlendID.push_back(item_ID); + } + CWeapon* Weapon = object().cast_weapon(); + if (Weapon) + { + Weapon->StopHUDMotion_Additive(&returns); + } + + CHudItem* itm = object().cast_inventory_item()->cast_hud_item(); + if (!itm) + return; + + itm->StopHUDMotion_Additive(&returns); + } +} + void CScriptGameObject::SwitchState(u32 state) { CWeapon* Weapon = object().cast_weapon(); diff --git a/src/xrGame/script_game_object_script3.cpp b/src/xrGame/script_game_object_script3.cpp index 3e462a03b6..96e4b40f60 100644 --- a/src/xrGame/script_game_object_script3.cpp +++ b/src/xrGame/script_game_object_script3.cpp @@ -518,6 +518,13 @@ class_ script_register_game_object2(class_ .def("weapon_in_grenade_mode", &CScriptGameObject::WeaponInGrenadeMode) // For CHudItem .def("play_hud_motion", SAFE_WRAP(&CScriptGameObject::PlayHudMotion)) + + // additive animations + .def("play_hud_motion_add", SAFE_WRAP(&CScriptGameObject::PlayHUDMotion_Add)) + .def("clear_blends", SAFE_WRAP(&CScriptGameObject::ClearBlends)) + .def("load_one_motion", SAFE_WRAP(&CScriptGameObject::load_motion)) + .def("clear_specific_blends", SAFE_WRAP(&CScriptGameObject::ClearSpecificBlends)) + .def("switch_state", SAFE_WRAP(&CScriptGameObject::SwitchState)) .def("get_state", SAFE_WRAP(&CScriptGameObject::GetState)) .def("hud_fire_point", SAFE_WRAP(&CScriptGameObject::hud_fire_point))