nuclide/src/client/NSView.qc

471 lines
10 KiB
Plaintext

/*
* Copyright (c) 2022 Vera Visions LLC.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
var bool autocvar_r_skipWorld = false;
void
NSView::NSView(void)
{
m_viewTarget = __NULL__;
m_vecPosition = [0,0];
m_vecSize = [0,0];
m_iSeat = 0;
m_flFieldOfView = 90.0f;
m_client = __NULL__;
m_flSensitivity = 1.0f;
m_bDrawEntities = true;
}
void
NSView::SetupView(void)
{
setproperty(VF_DRAWENGINESBAR, (float)0);
setproperty(VF_DRAWCROSSHAIR, (float)0);
if (g_cheats == true)
setproperty(VF_DRAWWORLD, autocvar_r_skipWorld ? false : true);
else
setproperty(VF_DRAWWORLD, (float)1);
setproperty(VF_ACTIVESEAT, (float)m_iSeat);
setproperty(VF_MIN, m_vecPosition);
setproperty(VF_SIZE, m_vecSize);
setproperty(VF_AFOV, m_flFieldOfView);
setsensitivityscaler(m_flSensitivity);
/* if yes, draw everything. */
if (m_bDrawLocalPlayer)
setproperty(VF_VIEWENTITY, 0);
else
setproperty(VF_VIEWENTITY, m_viewTarget.entnum);
/* handle camera override */
if (pSeat->m_flCameraTime > time || pSeat->m_flCameraTime == -1) {
setproperty(VF_ORIGIN, pSeat->m_vecCameraOrigin);
setproperty(VF_CL_VIEWANGLES, pSeat->m_vecCameraAngle);
setproperty(VF_ANGLES, pSeat->m_vecCameraAngle);
} else {
setproperty(VF_ORIGIN, origin);
//setproperty(VF_CL_VIEWANGLES, angles);
setproperty(VF_ANGLES, angles);
pSeat->m_flCameraTime = 0.0f;
}
/* the view may not have gotten the chance to set the client angle early on */
/* honestly this could be handled a lot better, but I don't know of a more reliable solution right now */
if (m_bSetClientAngle == true || cltime <= 0.5) {
setproperty(VF_ANGLES, m_vecClientAngle);
setproperty(VF_CL_VIEWANGLES, m_vecClientAngle);
m_bSetClientAngle = false;
}
m_vecLastOrigin = origin;
}
void
NSView::RenderView(void)
{
renderscene();
}
void
NSView::SetDrawLocalPlayer(bool choice)
{
m_bDrawLocalPlayer = choice;
}
void
NSView::StairSmooth(void)
{
/* don't run this on anything going up or down... */
if (fabs(m_viewTarget.groundentity.velocity[2]))
return;
/* handle stair stepping */
if (GetViewMode() == VIEWMODE_FPS) {
vector endpos = origin;
/* Have we gone up since last frame? */
if ((m_viewTarget.flags & FL_ONGROUND) && (endpos[2] - m_vecLastOrigin[2] > 0)) {
endpos[2] = m_vecLastOrigin[2] += (frametime * 150);
if (endpos[2] > origin[2]) {
endpos[2] = origin[2];
}
if (origin[2] - endpos[2] > 18) {
endpos[2] = origin[2] - 18;
}
}
// Teleport hack
if (fabs(origin[2] - m_vecLastOrigin[2]) > 64) {
endpos[2] = origin[2];
}
origin = endpos;
}
}
void
NSView::SetViewPosition(vector new_pos)
{
m_vecPosition = new_pos;
}
void
NSView::SetViewSize(vector new_size)
{
m_vecSize = new_size;
}
void
NSView::SetViewTarget(NSEntity new_target)
{
m_viewTarget = new_target;
}
void
NSView::SetCameraOrigin(vector new_origin)
{
origin = new_origin;
}
void
NSView::SetCameraAngle(vector new_angle)
{
angles = new_angle;
}
vector
NSView::GetCameraOrigin(void)
{
return origin;
}
vector
NSView::GetCameraAngle(void)
{
return angles;
}
void
NSView::SetClientAngle(vector new_angle)
{
m_vecClientAngle = new_angle;
m_bSetClientAngle = true;
}
void
NSView::SetViewMode(viewmode_t new_mode)
{
m_viewmode = new_mode;
}
viewmode_t
NSView::GetViewMode(void)
{
return m_viewmode;
}
void
NSView::SetSeatID(int new_id)
{
m_iSeat = new_id;
}
void
NSView::SetClientOwner(NSClient new_owner)
{
m_client = new_owner;
}
void
NSView::SetAFOV(float new_fov)
{
m_flFieldOfView = new_fov;
}
float
NSView::GetAFOV(void)
{
return m_flFieldOfView;
}
void
NSView::SetSensitivity(float new_fov)
{
m_flSensitivity = new_fov;
}
float
NSView::GetSensitivity(void)
{
return m_flSensitivity;
}
vector
NSView::GetHUDCanvasPos(void)
{
if (autocvar_cg_hudAspect <= 0) {
return m_vecPosition;
} else {
return [m_vecPosition[0] + ((m_vecSize[0] / 2) - ((m_vecSize[1] * autocvar_cg_hudAspect) / 2)), m_vecPosition[1]];
}
}
vector
NSView::GetHUDCanvasSize(void)
{
if (autocvar_cg_hudAspect <= 0) {
return m_vecSize;
} else {
return [m_vecSize[1] * autocvar_cg_hudAspect, m_vecSize[1]];
}
}
float
NSView::GetViewWidth(void)
{
return m_vecSize[0];
}
float
NSView::GetViewHeight(void)
{
return m_vecSize[1];
}
void
NSView::AddPunchAngle(vector vecAdd)
{
angles += vecAdd;
}
void View_PreDraw();
void View_PostDraw();
void View_DrawViewModel();
void
NSView::UpdateView(void)
{
NSClientPlayer pl = (NSClientPlayer)m_viewTarget;
NSClient cl = (NSClient)m_viewTarget;
NSClientSpectator spec = (NSClientSpectator)m_viewTarget;
entity c;
clearscene();
/* is a client attached to this view? */
if (cl) {
/* run preframe code on our viewtarget */
cl.PreFrame();
/* update our player seat info with predicted info */
pSeat->m_vecPredictedOrigin = cl.origin;
pSeat->m_flPredictedFlags = cl.flags;
pSeat->m_vecPredictedVelocity = cl.velocity;
/* this player will respawn, so null visual damage cues */
if (Client_IsDead(cl)) {
if (_m_bWasAlive == true) {
pSeat->m_flDamageAlpha = 0.0f;
pSeat->m_vecDamagePos = g_vec_null;
pSeat->m_iDamageFlags = 0i;
pSeat->m_flShakeFreq = 0.0f;
pSeat->m_flShakeDuration = 0.0f;
pSeat->m_flShakeTime = 0.0f;
pSeat->m_flShakeAmp = 0.0f;
}
_m_bWasAlive = false;
} else {
_m_bWasAlive = true;
}
}
/* put entities into the scene (and call their predraws */
if (m_bDrawEntities) {
addentities(MASK_ENGINE);
}
/* after predraws we can act upon their new positions */
if (cl) {
switch (GetViewMode()) {
case VIEWMODE_FPS:
if (Client_InIntermission()) {
cl.UpdateIntermissionCam();
} else {
if (Client_IsDead(pl)) {
SetAFOV(cvar("fov"));
SetSensitivity(1.0f);
pl.UpdateDeathcam();
} else {
SetAFOV(cvar("fov") * pl.viewzoom);
SetSensitivity(pl.viewzoom);
cl.UpdateAliveCam();
StairSmooth();
View_DrawViewModel();
_m_bWasAlive = true;
}
}
break;
case VIEWMODE_THIRDPERSON:
break;
case VIEWMODE_SPECTATING:
spec = (NSClientSpectator)m_viewTarget;
switch (spec.spec_mode) {
case SPECMODE_DEATHCAM:
vector deathAngle;
vector vecCamEnd;
c = findfloat(world, ::entnum, spec.spec_ent);
vector vecCamStart = c.origin;
float progression = time - spec.m_flLastSpecTargetChange;
vecCamStart[2] += 16;
vecCamStart += (v_right * 4);
deathAngle[0] = bound(0, progression * 15.0f, 90.0f);
deathAngle[1] = c.angles[1] + (progression * 22.5f);
deathAngle[2] = 0.0f;
makevectors(deathAngle);
vecCamEnd = vecCamStart + (v_forward * -48) + [0,0,16] + (v_right * 4);
traceline(vecCamStart, vecCamEnd, FALSE, m_viewTarget);
SetCameraOrigin(trace_endpos + (v_forward * 5));
SetCameraAngle(deathAngle);
SetClientAngle(deathAngle);
break;
case SPECMODE_LOCKEDCHASE:
view_angles = [0, spec.v_angle[1], 0];
case SPECMODE_THIRDPERSON:
makevectors(view_angles);
vector vecStart = spec.GetEyePos();
vecStart[2] += 16;
vecStart += (v_right * 4);
vector vecEnd = vecStart + (v_forward * -48) + [0,0,16] + (v_right * 4);
traceline(vecStart, vecEnd, FALSE, m_viewTarget);
SetCameraOrigin(trace_endpos + (v_forward * 5));
SetCameraAngle(view_angles);
break;
case SPECMODE_FIRSTPERSON:
c = findfloat(world, ::entnum, spec.spec_ent);
if (c.classname == "player") {
NSClientPlayer bp = (NSClientPlayer)c;
removeentity(c);
SetCameraOrigin(bp.GetEyePos());
SetCameraAngle(bp.v_angle);
SetAFOV(cvar("fov") * bp.viewzoom);
/* 0 means world */
if (spec.spec_ent) {
c = findfloat(world, ::entnum, spec.spec_ent);
/* we found them */
if (c && c != spec) {
NSClientPlayer ps = (NSClientPlayer)c;
if (ps.health <= 0)
pl.UpdateDeathcam();
else
View_DrawViewModel();
}
}
}
break;
case SPECMODE_CHASEOVERVIEW:
c = findfloat(world, ::entnum, spec.spec_ent);
if (c.classname == "player") {
SetCameraOrigin(c.origin);
}
drawfill(m_vecPosition, m_vecSize, [0,0,0], 1.0f, DRAWFLAG_NORMAL);
g_overview.SetViewPosition(m_vecPosition);
g_overview.SetViewSize(m_vecSize);
g_overview.SetRadarPitch(view_angles[0]);
g_overview.UpdateView();
return;
case SPECMODE_FREEOVERVIEW:
SetCameraOrigin(pSeat->m_vecPredictedOrigin);
drawfill(m_vecPosition, m_vecSize, [0,0,0], 1.0f, DRAWFLAG_NORMAL);
g_overview.SetViewPosition(m_vecPosition);
g_overview.SetViewSize(m_vecSize);
g_overview.SetRadarPitch(view_angles[0]);
g_overview.UpdateView();
return;
break;
default:
SetCameraOrigin(cl.GetEyePos());
SetCameraAngle(view_angles);
}
break;
default:
break;
}
View_PreDraw();
}
/* prepare our scene properties */
SetupView();
/* properties are locked in place, run logic that depends on final values */
if (m_bDrawEntities)
addentities(MASK_GLOWS);
SkyCamera_Setup(origin);
if (cl)
XR_UpdateView(m_viewTarget);
/* render our frame */
RenderView();
RenderTarget_Monitor_Update();
/* all 2D operations happen after this point */
for (entity b = world; (b = findfloat(b, ::isCSQC, 1));) {
NSEntity pf = (NSEntity) b;
if (pf.postdraw)
pf.postdraw();
}
/* the blinding stuff */
if (cl) {
Fade_Update(m_vecPosition[0], m_vecPosition[1], m_vecSize[0], m_vecSize[1]);
View_PostDraw();
/* move this into NSClient methods */
cl.PostFrame();
}
if (autocvar(r_showView, 0) == false)
return;
Font_DrawText(m_vecPosition + [8,8], "NSView Debug Information", FONT_CON);
Font_DrawText(m_vecPosition + [8,20], sprintf("Seat: %i", m_iSeat), FONT_CON);
Font_DrawText(m_vecPosition + [8,32], sprintf("FOV: %d", m_flFieldOfView), FONT_CON);
Font_DrawText(m_vecPosition + [8,44], sprintf("Origin: %v", origin), FONT_CON);
Font_DrawText(m_vecPosition + [8,56], sprintf("Angles: %v", angles), FONT_CON);
Font_DrawText(m_vecPosition + [8,68], sprintf("View-Target: %d", num_for_edict(m_viewTarget)), FONT_CON);
Font_DrawText(m_vecPosition + [8,80], sprintf("View-Mode: %d", m_viewmode), FONT_CON);
}