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))