Skip to content
Open
4 changes: 2 additions & 2 deletions gamedata/configs/text/eng/ui_mm_modded_exes.xml
Original file line number Diff line number Diff line change
Expand Up @@ -840,8 +840,8 @@
<string id="ui_mm_modded_exes_gameplay_weapons_g_decouple_horz_recoil">
<text>Horizontal recoil is independent of vertical (g_decouple_horz_recoil)</text>
</string>
<string id="ui_mm_modded_exes_gameplay_weapons_scale_hud_motion_marks_by_speed">
<text>Scale Hud Motion Marks By Anim Speed (scale_hud_motion_marks_by_speed)</text>
<string id="ui_mm_modded_exes_gameplay_weapons_disable_scale_hud_motion_marks_by_speed">
<text>Disable Scale Hud Motion Marks By Anim Speed (disable_scale_hud_motion_marks_by_speed)</text>
</string>

<string id="ui_mm_modded_exes_gameplay_weapons_g_fire_reloads_ubgl">
Expand Down
4 changes: 2 additions & 2 deletions gamedata/configs/text/rus/ui_mm_modded_exes.xml
Original file line number Diff line number Diff line change
Expand Up @@ -839,8 +839,8 @@
<string id="ui_mm_modded_exes_gameplay_weapons_g_decouple_horz_recoil">
<text>Ãîðèçîíòàëüíàÿ îòäà÷à íå çàâèñèò îò âåðòèêàëüíîé (g_decouple_horz_recoil)</text>
</string>
<string id="ui_mm_modded_exes_gameplay_weapons_scale_hud_motion_marks_by_speed">
<text>Ðåãóëèðîâàòü Motion Marks â çàâèñèìîñòè îò ñêîðîñòè àíèìàöèè (scale_hud_motion_marks_by_speed)</text>
<string id="ui_mm_modded_exes_gameplay_weapons_disable_scale_hud_motion_marks_by_speed">
<text>Çàïðåùàòü Ðåãóëèðîâàòü Motion Marks â çàâèñèìîñòè îò ñêîðîñòè àíèìàöèè (disable_scale_hud_motion_marks_by_speed)</text>
</string>

<string id="ui_mm_modded_exes_gameplay_weapons_g_fire_reloads_ubgl">
Expand Down
6 changes: 6 additions & 0 deletions gamedata/scripts/_g_patches.script
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
37 changes: 36 additions & 1 deletion gamedata/scripts/lua_help_ex.script
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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 {
Expand Down
1 change: 1 addition & 0 deletions src/Include/xrRender/KinematicsAnimated.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
4 changes: 4 additions & 0 deletions src/Include/xrRender/animation_blend.h
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
212 changes: 119 additions & 93 deletions src/Layers/xrRender/AnimationKeyCalculate.h
Original file line number Diff line number Diff line change
Expand Up @@ -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))
{
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}
}


Expand Down Expand Up @@ -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 ));
}
Expand Down
Loading
Loading