Fix light_dynamic (static) from not spawning in CSQC. Add r_skipDiffuse to rtlight.glsl,

add SURF_PENETRATE, which will make bullets pass right through them when
BULLETPENETRATION is set. Go over and refactor a lot of base_client, player
and spectator code to facilitate both permanent and temporary spectators
better. Add experimental env_glow lens flare code. Fix material ID detection
bug for Q3 based BSPs. A couple helper functions were added to src/client/utils.cpp
but they are not yet final.
This commit is contained in:
Marco Cawthorne 2022-03-17 21:05:47 -07:00
parent 96f3a1224a
commit 143a00e94e
Signed by: eukara
GPG Key ID: C196CD8BA993248A
28 changed files with 484 additions and 185 deletions

View File

@ -160,7 +160,7 @@ Scores_Draw(void)
pos = video_mins + [(video_res[0] / 2) - 145, 30];
}
if (serverkeyfloat("teams") > 0) {
if (Util_IsTeamPlay()) {
Scores_DrawTeam(pl, pos);
} else {
Scores_DrawNormal(pl, pos);

View File

@ -22,6 +22,8 @@
!!samps =PCF shadowmap
!!samps =CUBE projectionmap
!!cvardf r_skipDiffuse
#include "sys/defs.h"
//if there's no vertex normals known, disable some stuff.
@ -125,7 +127,11 @@ varying vec3 lightvector;
#if defined(FLAT)
vec4 bases = vec4(FLAT, FLAT, FLAT, 1.0);
#else
#if r_skipDiffuse == 0
vec4 bases = texture2D(s_diffuse, tex_c);
#else
vec4 bases = vec4(1.0, 1.0, 1.0, 1.0);
#endif
#endif
#ifdef BUMP

View File

@ -12,7 +12,7 @@
fl_r4 0x01000000
fl_r5 0x02000000
fl_r6 0x04000000
fl_r7 0x08000000
penetrate 0x08000000
alien 0x10000000
flesh 0x20000000

View File

@ -5,6 +5,7 @@
surfaceParm nodraw
surfaceParm trans
surfaceParm metal
surfaceParm penetrate
surfaceParm nolightmap
nomipmaps
}

View File

@ -19,6 +19,7 @@
#include "font.h"
#include "fade.h"
#include "cmd.h"
#include "util.h"
/* flags for 2d drawing */
#define DRAWFLAG_NORMAL 0

View File

@ -143,6 +143,7 @@ void
CSQC_UpdateView(float w, float h, float focus)
{
player pl = __NULL__;
base_client cl = __NULL__;
spectator spec;
int s;
@ -202,6 +203,7 @@ CSQC_UpdateView(float w, float h, float focus)
pSeat->m_ePlayer = self = findfloat(world, entnum, player_localentnum);
pl = (player)self;
cl = (base_client)self;
/* player slot not present */
if (!self) {
@ -210,8 +212,9 @@ CSQC_UpdateView(float w, float h, float focus)
/* this needs to be moved into a base_client method */
#if 1
if (self.classname == "player") {
Predict_PlayerPreFrame(pl);
cl.PreFrame();
if (!Client_IsSpectator(pl)) {
pSeat->m_vecPredictedOrigin = pl.origin;
pSeat->m_vecPredictedVelocity = pl.velocity;
@ -252,9 +255,8 @@ CSQC_UpdateView(float w, float h, float focus)
pl.viewzoom = oldzoom;
View_PreDraw();
} else if (self.classname == "spectator") {
} else if (Client_IsSpectator(pl)) {
spec = (spectator)self;
Predict_SpectatorPreFrame(spec);
if (spec.spec_mode == SPECMODE_FIRSTPERSON || spec.spec_mode == SPECMODE_THIRDPERSON) {
entity c = findfloat(world, ::entnum, spec.spec_ent);
@ -279,7 +281,8 @@ CSQC_UpdateView(float w, float h, float focus)
setproperty(VF_CL_VIEWANGLES, view_angles);
setproperty(VF_ANGLES, view_angles);
} else {
if (getplayerkeyvalue(pl.entnum-1, "*spec") == "0") {
/* we're not spectating at all */
if (!Client_IsSpectator(pl)) {
setproperty(VF_ORIGIN, pSeat->m_vecPredictedOrigin + pl.view_ofs);
if (pl.flags & FL_INVEHICLE) {
@ -299,7 +302,7 @@ CSQC_UpdateView(float w, float h, float focus)
Shake_Update(pl);
setproperty(VF_ANGLES, view_angles + pl.punchangle);
} else if (getplayerkeyvalue(pl.entnum-1, "*spec") == "1") {
} else if (Client_IsSpectator(pl)) {
spec = (spectator)self;
switch (spec.spec_mode) {
case SPECMODE_THIRDPERSON:
@ -328,13 +331,9 @@ CSQC_UpdateView(float w, float h, float focus)
default:
setproperty(VF_ORIGIN, pSeat->m_vecPredictedOrigin);
}
} else if (getplayerkeyvalue(pl.entnum-1, "*spec") == "2") {
setproperty(VF_ORIGIN, pSeat->m_vecPredictedOrigin);
Shake_Update(pl);
setproperty(VF_ANGLES, view_angles + pl.punchangle);
}
if (g_iIntermission) {
if (Client_InIntermission()) {
view_angles = pSeat->m_vecCameraAngle;
view_angles += [sin(time), sin(time * 2)];
setproperty(VF_ORIGIN, pSeat->m_vecCameraOrigin);
@ -357,10 +356,27 @@ CSQC_UpdateView(float w, float h, float focus)
setproperty(VF_AFOV, autocvar_r_viewmodelfov);
setproperty(VF_ORIGIN, pSeat->m_vecPredictedOrigin + pl.view_ofs);
View_DrawViewModel();
} else if (pl.health > 0) {
View_DrawViewModel();
} else if (getplayerkeyvalue(pl.entnum-1, "*dead") == "1") {
} else {
if (Client_IsSpectator(pl)) {
/* 0 means world */
if (spec.spec_ent) {
spec = (spectator)self;
entity c = findfloat(world, ::entnum, spec.spec_ent);
/* we found them */
if (c && c != spec) {
player ps = (player)c;
if (ps.health <= 0)
pl.UpdateDeathcam();
else
View_DrawViewModel();
}
}
} else if (Client_IsDead(pl)) {
pl.UpdateDeathcam();
} else {
View_DrawViewModel();
}
}
/* this is running whenever we're doing 'buildcubemaps' */
@ -368,7 +384,6 @@ CSQC_UpdateView(float w, float h, float focus)
setproperty(VF_ORIGIN, g_vecCubePos);
setproperty(VF_SIZE_X, g_dCubeSize);
setproperty(VF_SIZE_Y, g_dCubeSize);
print(sprintf("cubesize: %d\n", g_dCubeSize));
setproperty(VF_AFOV, 90);
}
@ -385,15 +400,15 @@ CSQC_UpdateView(float w, float h, float focus)
Fade_Update((int)video_mins[0],(int)video_mins[1], (int)w, (int)h);
View_PostDraw();
if (g_iIntermission) {
if (Client_InIntermission()) {
Scores_Draw();
} else if (focus == TRUE) {
GameText_Draw();
PointMessage_Draw();
if (getplayerkeyvalue(pl.entnum-1, "*spec") == "0") {
if (!Client_IsSpectator(pl)) {
HUD_Draw();
} else if (self.classname == "player") {
} else {
HUD_DrawSpectator();
}
@ -412,10 +427,7 @@ CSQC_UpdateView(float w, float h, float focus)
/* move this into base_client methods */
#if 1
if (self.classname == "player")
Predict_PlayerPostFrame((player)self);
else if (self.classname == "spectator")
Predict_SpectatorPostFrame((spectator)self);
cl.PostFrame();
#endif
}

View File

@ -26,4 +26,5 @@ shake.qc
cmd.qc
event.qc
entry.qc
util.cpp
#endlist

View File

@ -46,8 +46,10 @@ player::predraw(void)
/* make sure we're enabling shadow rendering on us */
effects &= ~EF_NOSHADOW;
base_client cl = (base_client)pSeat->m_ePlayer;
if (getplayerkeyvalue(pSeat->m_ePlayer.entnum-1, "*spec") == "1") {
/* it's either us or us spectating */
if (Client_IsSpectator(cl)) {
spectator spec = (spectator)pSeat->m_ePlayer;
if (entnum == spec.spec_ent && spec.spec_mode == SPECMODE_FIRSTPERSON) {
this_us = 1;

View File

@ -74,39 +74,7 @@ Propagate our pmove state to whatever the current frame before its stomped on
void
Predict_PlayerPreFrame(player pl)
{
/* this is where a game/mod would decide to add more prediction rollback
* information. */
pl.PredictPreFrame();
if (pl.flags & FL_INVEHICLE)
if (pl.vehicle) {
NSVehicle veh = (NSVehicle)pl.vehicle;
veh.PredictPreFrame();
}
/* run physics code for all the input frames which we've not heard back
* from yet. This continues on in Player_ReceiveEntity! */
for (int i = pl.sequence + 1; i <= clientcommandframe; i++) {
float flSuccess = getinputstate(i);
if (flSuccess == FALSE) {
continue;
}
/* don't do partial frames, aka incomplete input packets */
if (input_timelength == 0) {
break;
}
if (i==clientcommandframe){
CSQC_Input_Frame();
}
/* this global is for our shared random number seed */
input_sequence = i;
/* run our custom physics */
pl.Physics_Run();
}
}
/*
@ -121,17 +89,7 @@ Rewind our pmove state back to before we started predicting.
void
Predict_PlayerPostFrame(player pl)
{
/* give the game/mod a chance to roll back its values too */
pl.PredictPostFrame();
if (pl.flags & FL_INVEHICLE)
if (pl.vehicle) {
NSVehicle veh = (NSVehicle)pl.vehicle;
veh.PredictPostFrame();
}
/* update bounds */
setorigin(pl, pl.origin);
}
/*
@ -146,7 +104,6 @@ Propagate our pmove state to whatever the current frame before its stomped on
void
Predict_SpectatorPreFrame(spectator pl)
{
pl.PreFrame();
}
/*
@ -161,5 +118,4 @@ Rewind our pmove state back to before we started predicting.
void
Predict_SpectatorPostFrame(spectator pl)
{
pl.PostFrame();
}

40
src/client/util.cpp Normal file
View File

@ -0,0 +1,40 @@
float
Client_IsSpectator(base_client cl)
{
return (getplayerkeyfloat(cl.entnum - 1, "*spec") > 0) ? TRUE : FALSE;
}
float
Client_IsRealSpectator(base_client cl)
{
return (cl.classname == "spectator") ? TRUE : FALSE;
}
float
Client_IsFakeSpectator(base_client cl)
{
return (getplayerkeyvalue(cl.entnum - 1, "*spec") == "2") ? TRUE : FALSE;
}
float
Client_IsDead(base_client cl)
{
if (Client_IsSpectator(cl) == TRUE)
return FALSE;
else
return (getplayerkeyvalue(cl.entnum - 1, "*dead") == "1") ? TRUE : FALSE;
}
float
Client_IsPlayer(base_client cl)
{
return (cl.classname == "player") ? TRUE : FALSE;
}
float
Client_InIntermission(void)
{
return g_iIntermission;
}

17
src/client/util.h Normal file
View File

@ -0,0 +1,17 @@
/* Returns if the specified client is a spectator, doesn't matter if real or fake */
float Client_IsSpectator(base_client);
/* Returns if we're a permanent spectator, USE THIS if you want to access spectator class attributes */
float Client_IsRealSpectator(base_client cl);
/* Returns if we're a fake spectator, in case you need to be certain */
float Client_IsFakeSpectator(base_client cl);
/* Return if the specified client is dead. If they're a spectator they're always alive. */
float Client_IsDead(base_client);
/* Returns if the specified client is a playable client class */
float Client_IsPlayer(base_client cl);
/* Are we in an intermission? (Match ending screen) */
float Client_InIntermission(void);

View File

@ -129,9 +129,10 @@ View_DrawViewModel(void)
entity m_eMuzzleflashL = pSeat->m_eMuzzleflashL;
player pl = __NULL__;
base_client cl = (base_client)pSeat->m_ePlayer;
/* it's either us or us spectating */
if (self.classname == "spectator") {
if (Client_IsSpectator(cl)) {
spectator spec = (spectator)self;
pl = (player)findfloat(world, ::entnum, spec.spec_ent);
@ -139,27 +140,24 @@ View_DrawViewModel(void)
return;
} else {
pl = (player)self;
if (pl.health <= 0) {
return;
}
}
if (!pl)
return;
if (pl.health <= 0) {
return;
}
if (cvar("r_drawviewmodel") == 0 || autocvar_cl_thirdperson == TRUE) {
return;
}
// print(sprintf("%s: %f %d\n", pl.classname, pl.weapontime, pl.activeweapon));
View_UpdateWeapon(pl, m_eViewModel, m_eMuzzleflash);
View_UpdateWeapon(pl, m_eViewModelL, m_eMuzzleflashL);
float fBaseTime2 = m_eViewModel.frame1time;
float fBaseTime = m_eViewModel.frame1time;
m_eViewModel.frame = pl.weaponframe;
m_eViewModelL.frame = m_eViewModel.frame = pl.weaponframe;
m_eViewModelL.frame1time =
m_eViewModelL.frame2time =
m_eViewModel.frame2time =
@ -326,6 +324,16 @@ View_PlayAnimation(int iSequence)
pSeat->m_eViewModel.frame =
pSeat->m_eViewModelL.frame = (float)iSequence;
}
void
View_PlayAnimationLeft(int iSequence)
{
pSeat->m_eViewModelL.frame = (float)iSequence;
}
void
View_PlayAnimationRight(int iSequence)
{
pSeat->m_eViewModel.frame = (float)iSequence;
}
int
View_GetAnimation(void)

View File

@ -28,7 +28,8 @@ Client-side glare/glow orb effect like the flares in 1997's Unreal.
This entity was introduced in Half-Life (1998).
*/
var int autocvar_r_skipFlares = 0;
var int autocvar_r_skipGlows = 0;
var int autocvar_r_skipLensFlares = 0;
class env_glow:NSEntity /* change to renderablentity? */
{
@ -44,10 +45,19 @@ class env_glow:NSEntity /* change to renderablentity? */
void(void) env_glow;
virtual float() predraw;
virtual void() postdraw;
virtual void(string, string) SpawnKey;
virtual void(void) RendererRestarted;
};
void env_sun_lensflare(vector, float, vector);
void
env_glow::postdraw(void)
{
if (!autocvar_r_skipLensFlares)
env_sun_lensflare(origin, m_flAlpha, m_vecColor);
}
void
env_glow::RendererRestarted(void)
{
@ -74,7 +84,7 @@ env_glow::predraw(void)
vector fsize;
vector vecPlayer;
if (autocvar_r_skipFlares)
if (autocvar_r_skipGlows)
return PREDRAW_NEXT;
int s = (float)getproperty(VF_ACTIVESEAT);
@ -108,9 +118,9 @@ env_glow::predraw(void)
makevectors(vectoangles(origin - vecPlayer));
forg = origin + (v_forward * -16);
if (spawnflags & 1)
if (spawnflags & 1) {
makevectors(m_vecOrientation+[0,0,angles[2]]);
else {
} else {
makevectors(view_angles+[0,0,angles[2]]);
}

View File

@ -165,3 +165,52 @@ env_sun::env_sun(void)
setorigin(this, origin);
Init();
}
void
env_sun_lensflare(vector m_vecLensPos, float m_flLensAlpha, vector vecColor)
{
vector lens_pos = project(m_vecLensPos);
vector lens_1 = lens_pos - (FLARE_SIZE / 2);
vector player_pos = getproperty(VF_ORIGIN);
vector player_angle = getproperty(VF_CL_VIEWANGLES);
m_flLensAlpha *= 0.15f;
if (m_flLensAlpha <= 0.0f) {
return;
}
{
vector delta;
float fov;
makevectors(player_angle);
delta = normalize (m_vecLensPos - player_pos);
fov = delta * v_forward;
/* we're in field-of-view */
if (fov > 0.3) {
traceline(player_pos, m_vecLensPos, TRUE, self);
if (trace_fraction != 1.0) {
return;
}
} else {
return;
}
}
player_angle[0] *= -1;
vector test1, test2;
makevectors(vectoangles(m_vecLensPos - player_pos));
test1 = v_forward;
makevectors(player_angle);
test2 = v_forward;
vector c = (test1 - test2) * 512;
drawpic(lens_1, "textures/sfx/flare1", FLARE_SIZE, vecColor * m_flLensAlpha, 1.0f, DRAWFLAG_ADDITIVE);
drawpic(lens_1 - c * 0.1, "textures/sfx/flare2", FLARE_SIZE, vecColor * m_flLensAlpha, 1.0f, DRAWFLAG_ADDITIVE);
drawpic(lens_1 + c * 0.2, "textures/sfx/flare3", FLARE_SIZE, vecColor * m_flLensAlpha, 1.0f, DRAWFLAG_ADDITIVE);
drawpic(lens_1 - c * 0.3, "textures/sfx/flare4", FLARE_SIZE, vecColor * m_flLensAlpha, 1.0f, DRAWFLAG_ADDITIVE);
drawpic(lens_1 + c * 0.4, "textures/sfx/flare2", FLARE_SIZE, vecColor * m_flLensAlpha, 1.0f, DRAWFLAG_ADDITIVE);
drawpic(lens_1 - c * 0.5, "textures/sfx/flare3", FLARE_SIZE, vecColor * m_flLensAlpha, 1.0f, DRAWFLAG_ADDITIVE);
}

View File

@ -480,6 +480,7 @@ NSEntity::Respawn(void)
void
NSEntity::Save(float handle)
{
SaveFloat(handle, "spawnflags", spawnflags);
SaveVector(handle, "origin", origin);
SaveVector(handle, "absmin", absmin);
SaveVector(handle, "absmax", absmax);
@ -498,6 +499,9 @@ void
NSEntity::Restore(string strKey, string strValue)
{
switch (strKey) {
case "spawnflags":
spawnflags = stof(strValue);
break;
case "origin":
origin = stov(strValue);
setorigin(this, origin);
@ -589,6 +593,9 @@ NSEntity::SpawnKey(string strKey, string strValue)
/* we do re-read a lot of the builtin fields in case we want to set
defaults. just in case anybody is wondering. */
switch (strKey) {
case "spawnflags":
spawnflags = stof(strValue);
break;
case "origin":
origin = stov(strValue);
break;

View File

@ -174,7 +174,7 @@ light_dynamic::ReceiveEntity(float flNew, float flFlags)
void
light_dynamic::RendererRestarted(void)
{
#if 0
#if 1
float p = dynamiclight_spawnstatic(origin, m_flDistance, m_vecLight / 255);
dynamiclight_set(p, LFIELD_ANGLES, angles);

View File

@ -372,3 +372,9 @@ CGameRules::CGameRules(void)
/* our currently running mode */
CGameRules g_grMode;
int
Gamerules_IsTeamPlay(void)
{
return (g_grMode.IsTeamPlay()) ? TRUE : FALSE;
}

View File

@ -138,6 +138,7 @@ TraceAttack_FireSingle(vector vecPos, vector vAngle, int iDamage, int iWeapon, f
#ifdef BULLETPENETRATION
if (iTotalPenetrations > 0) {
if (!(trace_surfaceflagsi & SURF_PENETRATE))
iTotalPenetrations -= 1;
TraceAttack_FireSingle(trace_endpos + (v_forward * 2), vAngle, iDamage / 2, iWeapon, dist);
}

View File

@ -3,13 +3,28 @@
class
base_client:NSSurfacePropEntity
{
vector origin_net;
vector velocity_net;
void(void) base_client;
virtual void(void) ClientInputFrame;
/* final input handling of the client */
virtual void(void) ClientInput;
virtual void(void) PreFrame;
virtual void(void) PostFrame;
virtual int(void) IsFakeSpectator;
#ifdef CLIENT
/* gives the chance to override input variables before networking */
virtual void(void) ClientInputFrame;
/* our camera when we're dead */
virtual void(void) UpdateDeathcam;
/* run every frame before renderscene() */
virtual float(void) predraw;
#endif
};

View File

@ -1,10 +1,30 @@
void
base_client::ClientInputFrame(void)
base_client::ClientInput(void)
{
}
void
base_client::PreFrame(void)
{
}
void
base_client::PostFrame(void)
{
}
int
base_client::IsFakeSpectator(void)
{
return (FALSE);
}
#ifdef CLIENT
void
base_client::ClientInputFrame(void)
{
}
void
base_client::UpdateDeathcam(void)
{

View File

@ -39,6 +39,7 @@
#include "../gs-entbase/shared/baseentity.h"
#include "client.h"
#include "spectator.h"
#include "player.h"
#include "damage.h"
#include "flags.h"
@ -50,7 +51,6 @@
#include "math.h"
#include "pmove.h"
#include "memory.h"
#include "spectator.h"
#include "platform.h"
#include "propdata.h"
#include "surfaceproperties.h"
@ -138,6 +138,21 @@ Util_TimeToString(float fTime)
}
}
/* returns whether or not the mode we're playing is a team game */
#ifdef SERVER
int Gamerules_IsTeamPlay(void);
#endif
int
Util_IsTeamPlay(void)
{
#ifdef SERVER
return Gamerules_IsTeamPlay();
#else
return (serverkeyfloat("teams") > 0) ? TRUE : FALSE;
#endif
}
__wrap void
dprint(string m)
{

View File

@ -132,7 +132,7 @@ typedef enum
#define SURF_RESERVED4 0x01000000i
#define SURF_RESERVED5 0x02000000i
#define SURF_RESERVED6 0x04000000i
#define SURF_RESERVED7 0x08000000i
#define SURF_PENETRATE 0x08000000i
/* material surfaceflags (need to be masked) */
#define SURF_MASK 0x0FFFFFFFi

View File

@ -15,7 +15,7 @@
*/
class
base_player:base_client
base_player:spectator
{
PREDICTED_INT(weaponframe);
PREDICTED_FLOAT(health);
@ -53,6 +53,11 @@ base_player:base_client
void(void) base_player;
virtual void(void) ClientInput;
virtual void(void) PreFrame;
virtual void(void) PostFrame;
virtual void(float) Physics_Fall;
virtual void(void) Physics_Crouch;
virtual void(void) Physics_Jump;
@ -65,6 +70,8 @@ base_player:base_client
virtual void(void) Physics_InputPostMove;
virtual void(void) Physics_Run;
virtual int(void) IsFakeSpectator;
#ifdef CLIENT
int sequence;

View File

@ -14,6 +14,93 @@
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
int
base_player::IsFakeSpectator(void)
{
#ifdef SERVER
if (infokey(this, "*spec") == "2")
#else
if (getplayerkeyfloat(entnum - 1, "*spec") == 2)
#endif
return (TRUE);
return (FALSE);
}
void
base_player::PreFrame(void)
{
#ifdef CLIENT
/* this is where a game/mod would decide to add more prediction rollback
* information. */
PredictPreFrame();
if (flags & FL_INVEHICLE)
if (vehicle) {
NSVehicle veh = (NSVehicle)vehicle;
veh.PredictPreFrame();
}
/* run physics code for all the input frames which we've not heard back
* from yet. This continues on in Player_ReceiveEntity! */
for (int i = sequence + 1; i <= clientcommandframe; i++) {
float flSuccess = getinputstate(i);
if (flSuccess == FALSE) {
continue;
}
/* don't do partial frames, aka incomplete input packets */
if (input_timelength == 0) {
break;
}
if (i==clientcommandframe){
CSQC_Input_Frame();
}
/* this global is for our shared random number seed */
input_sequence = i;
/* run our custom physics */
Physics_Run();
}
#endif
}
void
base_player::PostFrame(void)
{
#ifdef CLIENT
/* give the game/mod a chance to roll back its values too */
PredictPostFrame();
if (flags & FL_INVEHICLE)
if (vehicle) {
NSVehicle veh = (NSVehicle)vehicle;
veh.PredictPostFrame();
}
/* update bounds */
setorigin(this, origin);
#endif
}
void
base_player::ClientInput(void)
{
if (IsFakeSpectator()) {
spectator::ClientInput();
SpectatorTrackPlayer();
return;
}
/* allow vehicles to prevent weapon logic from happening */
Vehicle_Input(this);
/* weapon/item logic of what the player controls */
Game_Input((player)this);
}
#ifdef CLIENT
void
base_player::ClientRemove(void)
@ -32,6 +119,11 @@ This is basically CSQC_Input_Frame! So games can override this as they please.
void
base_player::ClientInputFrame(void)
{
if (IsFakeSpectator()) {
spectator::ClientInputFrame();
return;
}
/* If we are inside a VGUI, don't let the client do stuff outside */
if (VGUI_Active()) {
input_impulse = 0;
@ -177,6 +269,11 @@ base_player::ReceiveEntity(float new, float fl)
punchangle[1] = readfloat();
punchangle[2] = readfloat();
vehicle = findfloat(world, ::entnum, readentitynum());
/* FIXME: Make this temp spec only */
spec_ent = readbyte();
spec_mode = readbyte();
spec_flags = readbyte();
}
/*
@ -217,6 +314,10 @@ base_player::PredictPreFrame(void)
SAVE_STATE(w_idle_next);
SAVE_STATE(punchangle);
SAVE_STATE(vehicle);
SAVE_STATE(spec_ent);
SAVE_STATE(spec_mode);
SAVE_STATE(spec_flags);
}
/*
@ -258,6 +359,10 @@ base_player::PredictPostFrame(void)
ROLL_BACK(w_idle_next);
ROLL_BACK(punchangle);
ROLL_BACK(vehicle);
ROLL_BACK(spec_ent);
ROLL_BACK(spec_mode);
ROLL_BACK(spec_flags);
}
#else
void
@ -439,10 +544,9 @@ base_player::Death(void)
/*
=================
base_player::MakeTempSpectator
base_player::MakePlayer
This is what dead players in round matches become, or when we spawn
for the first time before selecting a loadout or something.
True participating player, can walk around and everything.
=================
*/
void
@ -571,6 +675,11 @@ base_player::EvaluateEntity(void)
SAVE_STATE(w_idle_next);
SAVE_STATE(punchangle);
SAVE_STATE(vehicle);
/* FIXME: Make this temp spec only */
SAVE_STATE(spec_ent);
SAVE_STATE(spec_mode);
SAVE_STATE(spec_flags);
}
/*
@ -663,6 +772,11 @@ base_player::SendEntity(entity ePEnt, float fChanged)
else
WriteEntity(MSG_ENTITY, __NULL__);
/* FIXME: Make this fake spectator only. */
WriteByte(MSG_ENTITY, spec_ent);
WriteByte(MSG_ENTITY, spec_mode);
WriteByte(MSG_ENTITY, spec_flags);
return (1);
}
#endif

View File

@ -265,11 +265,7 @@ base_player::Physics_InputPostMove(void)
flags &= ~FL_FROZEN;
/* allow vehicles to prevent weapon logic from happening */
Vehicle_Input(this);
/* weapon/item logic of what the player controls */
Game_Input((player)this);
ClientInput();
}
/* the main physics routine, the head */

View File

@ -15,12 +15,15 @@ typedef enum
SPECMODE_OVERVIEW
} spectatorMode_t;
typedef enumflags
{
SPECFLAG_BUTTON_RELEASED,
};
class spectator:base_client
{
vector origin_net;
vector velocity_net;
float spec_ent; float spec_ent_net;
float spec_flags; float spec_flags_net;
PREDICTED_FLOAT(spec_ent);
PREDICTED_FLOAT(spec_flags);
spectatorMode_t spec_mode; spectatorMode_t spec_mode_net;
vector spec_org;
@ -29,18 +32,20 @@ class spectator:base_client
void(void) spectator;
virtual void(void) ClientInput;
virtual void(void) InputNext;
virtual void(void) InputPrevious;
virtual void(void) InputMode;
virtual void(void) PreFrame;
virtual void(void) PostFrame;
virtual void(void) SpectatorInput;
virtual void(void) WarpToTarget;
virtual void(void) PreFrame;
virtual void(void) PostFrame;
virtual void(void) SpectatorTrackPlayer;
#ifdef SERVER
virtual void(void) EvaluateEntity;
virtual float(entity, float) SendEntity;
virtual void(void) RunClientCommand;
#else

View File

@ -15,15 +15,7 @@
*/
void
spectator::WarpToTarget(void)
{
entity b = edict_num(spec_ent);
setorigin(this, b.origin);
}
void
spectator::SpectatorInput(void)
spectator::ClientInput(void)
{
if (input_buttons & INPUT_BUTTON0) {
InputNext();
@ -32,10 +24,19 @@ spectator::SpectatorInput(void)
} else if (input_buttons & INPUT_BUTTON2) {
InputMode();
} else {
spec_flags &= ~GF_SEMI_TOGGLED;
spec_flags &= ~SPECFLAG_BUTTON_RELEASED;
}
input_buttons = 0;
//crossprint(sprintf("%d %d %d\n", spec_ent, spec_mode, spec_flags));
}
void
spectator::WarpToTarget(void)
{
entity b = edict_num(spec_ent);
setorigin(this, b.origin);
}
#ifdef SERVER
@ -81,7 +82,7 @@ void
spectator::RunClientCommand(void)
{
runstandardplayerphysics(this);
SpectatorInput();
ClientInput();
}
#else
@ -103,7 +104,6 @@ spectator::ClientInputFrame(void)
void
spectator::ReceiveEntity(float new, float fl)
{
if (new == FALSE) {
/* Go through all the physics code between the last received frame
* and the newest frame and keep the changes this time around instead
@ -121,7 +121,7 @@ spectator::ReceiveEntity(float new, float fl)
}
input_sequence = i;
runstandardplayerphysics(this);
SpectatorInput();
ClientInput();
}
/* any differences in things that are read below are now
@ -164,7 +164,7 @@ spectator::predraw(void)
void
spectator::InputNext(void)
{
if (spec_flags & GF_SEMI_TOGGLED)
if (spec_flags & SPECFLAG_BUTTON_RELEASED)
return;
#if 0
@ -190,14 +190,14 @@ spectator::InputNext(void)
if (i <= sep && best == 0) {
f = edict_num(i);
if (f && f.classname == "player") {
if (f && f.classname == "player" && f != this) {
best = i;
}
}
if (i > sep) {
f = edict_num(i);
if (f && f.classname == "player") {
if (f && f.classname == "player" && f != this) {
best = i;
break;
}
@ -209,7 +209,7 @@ spectator::InputNext(void)
spec_ent = best;
#endif
spec_flags |= GF_SEMI_TOGGLED;
spec_flags |= SPECFLAG_BUTTON_RELEASED;
WarpToTarget();
if (spec_mode == SPECMODE_FREE)
@ -219,7 +219,7 @@ spectator::InputNext(void)
void
spectator::InputPrevious(void)
{
if (spec_flags & GF_SEMI_TOGGLED)
if (spec_flags & SPECFLAG_BUTTON_RELEASED)
return;
#if 0
float max_edict;
@ -264,7 +264,7 @@ spectator::InputPrevious(void)
spec_ent = best;
#endif
spec_flags |= GF_SEMI_TOGGLED;
spec_flags |= SPECFLAG_BUTTON_RELEASED;
WarpToTarget();
@ -275,29 +275,28 @@ spectator::InputPrevious(void)
void
spectator::InputMode(void)
{
if (spec_flags & GF_SEMI_TOGGLED)
if (spec_flags & SPECFLAG_BUTTON_RELEASED)
return;
crossprint("MODE\n");
spec_mode++;
if (spec_mode > SPECMODE_FIRSTPERSON)
spec_mode = SPECMODE_FREE;
spec_flags |= GF_SEMI_TOGGLED;
spec_flags |= SPECFLAG_BUTTON_RELEASED;
}
void
spectator::PreFrame(void)
{
#ifdef SERVER
#else
#ifdef CLIENT
/* base player attributes/fields we're going to roll back */
origin_net = origin;
velocity_net = velocity;
spec_ent_net = spec_ent;
spec_mode_net = spec_mode;
spec_flags_net = spec_flags;
SAVE_STATE(origin);
SAVE_STATE(velocity);
SAVE_STATE(spec_ent);
SAVE_STATE(spec_mode);
SAVE_STATE(spec_flags);
/* run physics code for all the input frames which we've not heard back
* from yet. This continues on in Player_ReceiveEntity! */
@ -321,10 +320,16 @@ spectator::PreFrame(void)
/* run our custom physics */
runstandardplayerphysics(this);
SpectatorInput();
ClientInput();
}
#endif
SpectatorTrackPlayer();
}
void
spectator::SpectatorTrackPlayer(void)
{
if (spec_mode == SPECMODE_THIRDPERSON || spec_mode == SPECMODE_FIRSTPERSON ) {
entity b;
@ -345,10 +350,10 @@ spectator::PreFrame(void)
}
}
void
spectator::PostFrame(void)
{
#ifdef SERVER
void
spectator::EvaluateEntity(void)
{
/* check for which values have changed in this frame
and announce to network said changes */
if (origin != origin_net)
@ -366,19 +371,23 @@ spectator::PostFrame(void)
if (spec_flags != spec_flags_net)
SetSendFlags(SPECFL_FLAGS);
origin_net = origin;
velocity_net = velocity;
spec_ent_net = spec_ent;
spec_mode_net = spec_mode;
spec_flags_net = spec_flags;
#else
/* finally roll the values back */
origin = origin_net;
velocity = velocity_net;
spec_ent = spec_ent_net;
spec_mode = spec_mode_net;
spec_flags = spec_flags_net;
setorigin(this, origin);
SAVE_STATE(origin);
SAVE_STATE(velocity);
SAVE_STATE(spec_ent);
SAVE_STATE(spec_mode);
SAVE_STATE(spec_flags);
}
#endif
void
spectator::PostFrame(void)
{
#ifdef CLIENT
ROLL_BACK(origin);
ROLL_BACK(velocity);
ROLL_BACK(spec_ent);
ROLL_BACK(spec_mode);
ROLL_BACK(spec_flags);
#endif
}

View File

@ -475,6 +475,7 @@ SurfData_Impact(entity e, int fl, vector org, vector ang)
case BSPVER_Q3: /* Q3 */
case BSPVER_RTCW: /* RtCW */
case BSPVER_RBSP: /* RFVBSP */
fl &= ~SURF_MASK;
FX_Impact(SurfData_SurfaceFlagtoImpact(fl), org, ang);
break;
default: