quakec/source/server/weapons/frames_core.qc
2024-09-01 18:12:38 -07:00

271 lines
7.2 KiB
C++

/*
server/weapons/frames_core.qc
advanced viewmodel frame iteration
Copyright (C) 2021-2024 NZ:P Team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to:
Free Software Foundation, Inc.
59 Temple Place - Suite 330
Boston, MA 02111-1307, USA
*/
void(entity person) W_ShowCrosshair;
void() ContinueRun =
{
float startframe;
float endframe;
string modelname;
startframe = GetFrame(self.weapon,SPRINT_START);
endframe = GetFrame(self.weapon,SPRINT_END);
if(!startframe && !endframe)
{
startframe = GetFrame(self.weapon,SPRINT_IN_END);
endframe = GetFrame(self.weapon,SPRINT_IN_END);
}
if (!self.downed) {
modelname = GetWeaponModel(self.weapon, 0);
} else
modelname = "";
Set_W_Frame (startframe, endframe, 0, 0, SPRINT, ContinueRun, modelname, false, S_BOTH, false);
}
void () W2_Frame_Update =
{
local void temp(optional float t);
// note: call whenever weapon frames are called!
if (self.anim_weapon2_time > time)
return; //don't call every frame, if it is the animations will play too fast
#ifndef FTE
if (self.weapon == W_KAR_SCOPE || self.weapon == W_HEADCRACKER) {
self.weapon2frame = self.weaponframe;
return;
}
#endif // FTE
self.anim_weapon2_time = time + self.weapon2_animduration;
if (self.weapon2frame != self.weapon2frame_end && !self.anim2_reversed)
{ // continue an animation
if (self.anim2_reversed) {
self.weapon2frame = self.weapon2frame - 1;
} else {
self.weapon2frame = self.weapon2frame + 1;
}
if (self.callfuncat2)
{
if (self.weapon2frame == self.callfuncat2)
{
if (self.animend2)
{
temp = self.animend2;
self.animend2 = SUB_Null2;
if (temp)
temp(S_LEFT);
}
}
}
if (PlayWeaponSound(self.weapon, self.weapon2_anim_type, FALSE, self.weapon2frame)) {
// Slight rumble because we triggered a weapon sound
nzp_rumble(self, 1000, 1200, 75);
}
return;
}
else
{
if (self.callfuncat2 != self.weapon2frame && self.reload_delay <= time)
W_ShowCrosshair(self);
self.weapon2frame = self.weapon2frame_end = self.weapon2frame = GetFrame(self.weapon,BASE_FRAME);
self.new_anim2_stop = FALSE;
self.weapon2_anim_type = 0;
self.weapon2_animduration = 0;
self.callfuncat2 = 0;
temp = self.animend2;
self.animend2 = SUB_Null;
if (temp)
temp(S_LEFT);
}
};
void () W_Frame_Update =
{
local void temp(optional float t);
// note: call whenever weapon frames are called!
if (self.anim_weapon_time > time)
return; //don't call every frame, if it is the animations will play too fast
//if (IsDualWeapon(self.weapon))
// W2_Frame_Update();
self.anim_weapon_time = time + self.weapon_animduration;
if (self.weaponframe != self.weaponframe_end && !self.anim_reversed)
{ // continue an animation
if (self.anim_reversed) {
self.weaponframe = self.weaponframe - 1;
} else {
self.weaponframe = self.weaponframe + 1;
}
if (self.weaponmodel == "models/weapons/kar/v_kar.mdl" && (self.weapon == W_KAR_SCOPE || self.weapon == W_HEADCRACKER))
{
self.weapon2model = "models/weapons/kar/v_karscope.mdl";
self.weapon2frame = self.weaponframe;
//self.weapon2skin = self.weaponskin;
}
else if (self.weaponmodel == "progs/VModels/v_knife.mdl" || self.weaponmodel == "models/machines/v_perk.mdl") {
self.weapon2model = "";
}
if (self.callfuncat)
{
if (self.weaponframe == self.callfuncat)
{
if (self.animend)
{
temp = self.animend;
self.animend = SUB_Null;
if (temp)
temp(S_RIGHT);
}
}
}
if (PlayWeaponSound(self.weapon, self.weapon_anim_type, FALSE, self.weaponframe)) {
// Slight rumble because we triggered a weapon sound
nzp_rumble(self, 1000, 1200, 75);
}
// FIXME: We need a way to play sounds at specific frames for any viewmodel, not just weapons
if (self.weaponmodel == "models/weapons/grenade/v_betty.mdl" && self.weaponframe == 9) {
Sound_PlaySound(self, "sounds/weapons/grenade/prime.wav", SOUND_TYPE_WEAPON_OTHER, SOUND_PRIORITY_PLAYALWAYS);
nzp_rumble(self, 1000, 1200, 75);
}
return;
}
else
{
if (self.callfuncat != self.weaponframe && self.reload_delay2 <= time)
W_ShowCrosshair(self);
self.weaponframe_end = self.weaponframe = GetFrame(self.weapon,BASE_FRAME);
self.new_anim_stop = FALSE;
self.weapon_anim_type = 0;
self.weapon_animduration = 0;
self.callfuncat = 0;
temp = self.animend;
self.animend = SUB_Null;
if (temp)
temp(S_RIGHT);
}
//if (!IsDualWeapon(self.weapon))
// W2_Frame_Update();
};
float(string path) model_should_hide_weapon2 =
{
switch(path) {
case "models/weapons/grenade/v_grenade.mdl":
case "models/weapons/grenade/v_betty.mdl":
case "models/weapons/bk/v_bk.mdl":
case "models/weapons/knife/v_bowie.mdl":
case "models/weapons/knife/v_knife.mdl":
case "models/weapons/morphine/v_morphine.mdl":
return true;
}
return false;
}
void Set_W_Frame (float startframe, float endframe, float duration, float funccalledin, float animtype, void(optional float t) endanimfunc, string set_model, float dontstartnew, float side, float lock_viewmodel) =
{
float math, reversed;
if (startframe >= endframe) {
reversed = true;
} else {
reversed = false;
}
math = 0;
if (duration) {
math = duration / (fabs(endframe - startframe) + 1);
} else {
math = 0.1;
}
if (side == S_RIGHT || side == S_BOTH) {
self.weaponframe = startframe;
self.weaponframe_end = endframe;
self.animend = endanimfunc;
self.callfuncat = funccalledin;
self.weapon_anim_type = animtype;
self.new_anim_stop = dontstartnew;
self.weapon_animduration = math;
self.anim_reversed = reversed;
}
if (side == S_LEFT || side == S_BOTH) {
self.weapon2frame = startframe;
self.weapon2frame_end = endframe;
self.weapon2_anim_type = animtype;
self.new_anim2_stop = dontstartnew;
self.weapon2_animduration = math;
self.anim2_reversed = reversed;
if (side != S_BOTH) {
self.animend2 = endanimfunc;
self.callfuncat2 = funccalledin;
}
}
if ((startframe != endframe) && !(self.zoom == 2)) { // naievil -- latter used for checkhold
if (side == S_LEFT) {
self.weapon2model = set_model;
} else {
self.weaponmodel = set_model;
if (model_should_hide_weapon2(set_model) == true) {
self.weapon2model = "";
} else if (self.weapon == W_KAR_SCOPE) {
self.weapon2model = "models/weapons/kar/v_karscope.mdl";
} else if (IsDualWeapon(self.weapon)) {
self.weapon2model = GetLeftWeaponModel(self.weapon);
}
}
}
#ifndef FTE
// For source ports where the viewmodel is able to be manipulated based on the camera
// position, we explicitly communicate to those clients to prohibit that with
// lock_viewmodel whenever we are drinking a Perk-A-Cola, meleeing, etc.
nzp_lockviewmodel(self, lock_viewmodel);
#endif // FTE
}